diff options
Diffstat (limited to 'protocols/Telegram')
-rw-r--r-- | protocols/Telegram/Telegram.vcxproj | 1 | ||||
-rw-r--r-- | protocols/Telegram/Telegram.vcxproj.filters | 3 | ||||
-rw-r--r-- | protocols/Telegram/res/resource.rc | 49 | ||||
-rw-r--r-- | protocols/Telegram/src/add_phone.cpp | 2 | ||||
-rw-r--r-- | protocols/Telegram/src/auth.cpp | 2 | ||||
-rw-r--r-- | protocols/Telegram/src/avatars.cpp | 136 | ||||
-rw-r--r-- | protocols/Telegram/src/groupchat.cpp | 145 | ||||
-rw-r--r-- | protocols/Telegram/src/menus.cpp | 2 | ||||
-rw-r--r-- | protocols/Telegram/src/options.cpp | 8 | ||||
-rw-r--r-- | protocols/Telegram/src/proto.cpp | 122 | ||||
-rw-r--r-- | protocols/Telegram/src/proto.h | 27 | ||||
-rw-r--r-- | protocols/Telegram/src/resource.h | 13 | ||||
-rw-r--r-- | protocols/Telegram/src/server.cpp | 172 | ||||
-rw-r--r-- | protocols/Telegram/src/stdafx.cxx | 2 | ||||
-rw-r--r-- | protocols/Telegram/src/stdafx.h | 1 | ||||
-rw-r--r-- | protocols/Telegram/src/userinfo.cpp | 151 | ||||
-rw-r--r-- | protocols/Telegram/src/utils.cpp | 131 | ||||
-rw-r--r-- | protocols/Telegram/src/version.h | 2 |
18 files changed, 725 insertions, 244 deletions
diff --git a/protocols/Telegram/Telegram.vcxproj b/protocols/Telegram/Telegram.vcxproj index 243fd85388..3a09c9db55 100644 --- a/protocols/Telegram/Telegram.vcxproj +++ b/protocols/Telegram/Telegram.vcxproj @@ -38,6 +38,7 @@ <ClCompile Include="src\stdafx.cxx">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
+ <ClCompile Include="src\userinfo.cpp" />
<ClCompile Include="src\utils.cpp" />
</ItemGroup>
<ItemDefinitionGroup>
diff --git a/protocols/Telegram/Telegram.vcxproj.filters b/protocols/Telegram/Telegram.vcxproj.filters index 10ea2069d9..1dfbf2f168 100644 --- a/protocols/Telegram/Telegram.vcxproj.filters +++ b/protocols/Telegram/Telegram.vcxproj.filters @@ -32,6 +32,9 @@ <ClCompile Include="src\menus.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="src\userinfo.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\stdafx.cxx">
diff --git a/protocols/Telegram/res/resource.rc b/protocols/Telegram/res/resource.rc index cb6181fb51..65a4b91a35 100644 --- a/protocols/Telegram/res/resource.rc +++ b/protocols/Telegram/res/resource.rc @@ -99,8 +99,10 @@ BEGIN PUSHBUTTON "Log out",IDC_LOGOUT,212,168,86,14
CONTROL "Include URL preview into message text",IDC_USE_PREVIEW,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,4,109,294,10
- CONTROL "Store channel messages in memory only",IDC_RESIDENT_CHANNELS,
+ CONTROL "Do not store channel history in the database",IDC_RESIDENT_CHANNELS,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,4,122,294,10
+ CONTROL "Delete contacts in Miranda when they are deleted from server",IDC_DELETE_CONTACTS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,4,135,294,10
END
IDD_OPTIONS_ADV DIALOGEX 0, 0, 310, 86
@@ -166,6 +168,28 @@ BEGIN PUSHBUTTON "Cancel",IDCANCEL,158,22,50,14
END
+IDD_MYPROFILE DIALOGEX 0, 0, 221, 152
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Birthday",IDC_STATIC,2,3,217,8
+ CONTROL "",IDC_BIRTHDAY,"SysDateTimePick32",DTS_RIGHTALIGN | WS_DISABLED | WS_TABSTOP,0,14,100,15
+ LTEXT "Biography",IDC_STATIC,2,34,217,8
+ EDITTEXT IDC_BIO,0,46,217,101,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY,WS_EX_DLGMODALFRAME
+END
+
+IDD_CHANNEL_INFO DIALOGEX 0, 0, 221, 152
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "User count",IDC_STATIC,2,6,149,8
+ EDITTEXT IDC_USER_COUNT,157,4,59,14,ES_AUTOHSCROLL | ES_NUMBER | WS_DISABLED
+ LTEXT "Channel link",IDC_STATIC,2,27,217,8
+ CONTROL "",IDC_LINK,"Hyperlink",WS_TABSTOP,2,38,217,12
+END
+
/////////////////////////////////////////////////////////////////////////////
//
@@ -219,6 +243,14 @@ BEGIN BEGIN
BOTTOMMARGIN, 262
END
+
+ IDD_MYPROFILE, DIALOG
+ BEGIN
+ END
+
+ IDD_CHANNEL_INFO, DIALOG
+ BEGIN
+ END
END
#endif // APSTUDIO_INVOKED
@@ -258,6 +290,21 @@ BEGIN 0
END
+IDD_USERINFO AFX_DIALOG_LAYOUT
+BEGIN
+ 0
+END
+
+IDD_MYPROFILE AFX_DIALOG_LAYOUT
+BEGIN
+ 0
+END
+
+IDD_CHANNEL_INFO AFX_DIALOG_LAYOUT
+BEGIN
+ 0
+END
+
#endif // English (Neutral) resources
/////////////////////////////////////////////////////////////////////////////
diff --git a/protocols/Telegram/src/add_phone.cpp b/protocols/Telegram/src/add_phone.cpp index fbb61560c9..f799f91d77 100644 --- a/protocols/Telegram/src/add_phone.cpp +++ b/protocols/Telegram/src/add_phone.cpp @@ -1,5 +1,5 @@ /* -Copyright (C) 2012-24 Miranda NG team (https://miranda-ng.org) +Copyright (C) 2012-25 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 diff --git a/protocols/Telegram/src/auth.cpp b/protocols/Telegram/src/auth.cpp index b23e5a4c20..c09d5b20e0 100644 --- a/protocols/Telegram/src/auth.cpp +++ b/protocols/Telegram/src/auth.cpp @@ -1,5 +1,5 @@ /*
-Copyright (C) 2012-24 Miranda NG team (https://miranda-ng.org)
+Copyright (C) 2012-25 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
diff --git a/protocols/Telegram/src/avatars.cpp b/protocols/Telegram/src/avatars.cpp index 96e861419b..6b7e0bbd09 100644 --- a/protocols/Telegram/src/avatars.cpp +++ b/protocols/Telegram/src/avatars.cpp @@ -1,5 +1,5 @@ /*
-Copyright (C) 2012-24 Miranda NG team (https://miranda-ng.org)
+Copyright (C) 2012-25 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
@@ -191,6 +191,29 @@ TG_FILE_REQUEST* CTelegramProto::FindFile(const char *pszUniqueId) return nullptr;
}
+TG_FILE_REQUEST* CTelegramProto::FindFile(int id)
+{
+ mir_cslock lck(m_csFiles);
+
+ for (auto &it : m_arFiles)
+ if (it->m_fileId == id)
+ return it;
+
+ return nullptr;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CTelegramProto::ShowFileProgress(const TD::file *pFile, TG_FILE_REQUEST *ft)
+{
+ PROTOFILETRANSFERSTATUS fts = {};
+ fts.hContact = ft->m_hContact;
+ fts.totalFiles = 1;
+ fts.totalBytes = fts.currentFileSize = pFile->size_;
+ fts.totalProgress = fts.currentFileProgress = pFile->remote_->uploaded_size_;
+ ProtoBroadcastAck((UINT_PTR)ft->m_hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM)&fts);
+}
+
/////////////////////////////////////////////////////////////////////////////////////////
// Extracts a photo/avatar to a file
@@ -227,30 +250,33 @@ void CTelegramProto::ProcessFile(TD::updateFile *pObj) return;
if (!pLocal->is_downloading_completed_) {
- if (auto *F = FindFile(pRemote->unique_id_.c_str())) {
- if (F->m_type != F->AVATAR && F->ofd) {
- DBVARIANT dbv = { DBVT_DWORD };
- dbv.dVal = pLocal->downloaded_size_;
- db_event_setJson(F->ofd->hDbEvent, "ft", &dbv);
- }
+ auto *ft = FindFile(pRemote->unique_id_.c_str());
+ if (ft && ft->m_type != ft->AVATAR && ft->ofd) {
+ DBVARIANT dbv = { DBVT_DWORD };
+ dbv.dVal = pLocal->downloaded_size_;
+ db_event_setJson(ft->ofd->hDbEvent, "ft", &dbv);
}
return;
}
// file upload is not completed, skip it
- if (pRemote->is_uploading_active_)
+ if (pRemote->is_uploading_active_) {
+ auto *ft = FindFile(pFile->id_);
+ if (ft)
+ ShowFileProgress(pFile, ft);
return;
+ }
Utf2T wszExistingFile(pLocal->path_.c_str());
- if (auto *F = FindFile(pRemote->unique_id_.c_str())) {
- if (F->m_type == F->AVATAR) {
- CMStringW wszFullName = F->m_destPath;
+ if (auto *ft = FindFile(pRemote->unique_id_.c_str())) {
+ if (ft->m_type == ft->AVATAR) {
+ CMStringW wszFullName = ft->m_destPath;
if (!wszFullName.IsEmpty())
wszFullName += L"\\";
- wszFullName += F->m_fileName;
+ wszFullName += ft->m_fileName;
- if (F->m_fileName.Right(5).MakeLower() == L".webp") {
+ if (ft->m_fileName.Right(5).MakeLower() == L".webp") {
if (auto *pImage = FreeImage_LoadU(FIF_WEBP, wszExistingFile)) {
wszFullName.Truncate(wszFullName.GetLength() - 5);
wszFullName += L".png";
@@ -258,7 +284,7 @@ void CTelegramProto::ProcessFile(TD::updateFile *pObj) FreeImage_Unload(pImage);
}
}
- else if (F->m_fileName.Right(4).MakeLower() == L".tga") {
+ else if (ft->m_fileName.Right(4).MakeLower() == L".tga") {
if (auto *pImage = FreeImage_LoadU(FIF_TARGA, wszExistingFile)) {
wszFullName.Truncate(wszFullName.GetLength() - 5);
wszFullName += L".png";
@@ -268,54 +294,53 @@ void CTelegramProto::ProcessFile(TD::updateFile *pObj) }
else MoveFileW(wszExistingFile, wszFullName);
- if (F->m_isSmiley)
+ if (ft->m_isSmiley)
SmileyAdd_LoadContactSmileys(SMADD_FILE, m_szModuleName, wszFullName);
else
NS_NotifyFileReady(wszFullName);
}
else { // FILE, PICTURE, VIDEO, VOICE
- if (F->ofd == nullptr)
- return;
-
- DBVARIANT dbv = { DBVT_DWORD };
- dbv.dVal = pLocal->downloaded_size_;
- db_event_setJson(F->ofd->hDbEvent, "ft", &dbv);
-
- CMStringW wszFullName(F->ofd->wszPath);
- int idxSlash = wszFullName.ReverseFind('\\') + 1;
- if (wszFullName.Find('.', idxSlash) == -1) {
- auto *pSlash = strrchr(pLocal->path_.c_str(), '\\');
- if (!pSlash)
- pSlash = pLocal->path_.c_str();
- else
- pSlash++;
-
- if (strchr(pSlash, '.')) {
- dbv.type = DBVT_UTF8;
- dbv.pszVal = (char *)pSlash;
- db_event_setJson(F->ofd->hDbEvent, "f", &dbv);
-
- wszFullName.Truncate(idxSlash);
- wszFullName.Append(Utf2T(pSlash));
- F->ofd->ResetFileName(wszFullName); // resulting ofd->wszPath may differ from wszFullName
- }
- else {
- int iFormat = ProtoGetAvatarFileFormat(wszExistingFile);
- if (iFormat != PA_FORMAT_UNKNOWN) {
- wszFullName.AppendChar('.');
- wszFullName.Append(ProtoGetAvatarExtension(iFormat));
- F->ofd->ResetFileName(wszFullName);
+ if (ft->ofd) {
+ DBVARIANT dbv = { DBVT_DWORD };
+ dbv.dVal = pLocal->downloaded_size_;
+ db_event_setJson(ft->ofd->hDbEvent, "ft", &dbv);
+
+ CMStringW wszFullName(ft->ofd->wszPath);
+ int idxSlash = wszFullName.ReverseFind('\\') + 1;
+ if (wszFullName.Find('.', idxSlash) == -1) {
+ auto *pSlash = strrchr(pLocal->path_.c_str(), '\\');
+ if (!pSlash)
+ pSlash = pLocal->path_.c_str();
+ else
+ pSlash++;
+
+ if (strchr(pSlash, '.')) {
+ dbv.type = DBVT_UTF8;
+ dbv.pszVal = (char *)pSlash;
+ db_event_setJson(ft->ofd->hDbEvent, "f", &dbv);
+
+ wszFullName.Truncate(idxSlash);
+ wszFullName.Append(Utf2T(pSlash));
+ ft->ofd->ResetFileName(wszFullName); // resulting ofd->wszPath may differ from wszFullName
+ }
+ else {
+ int iFormat = ProtoGetAvatarFileFormat(wszExistingFile);
+ if (iFormat != PA_FORMAT_UNKNOWN) {
+ wszFullName.AppendChar('.');
+ wszFullName.Append(ProtoGetAvatarExtension(iFormat));
+ ft->ofd->ResetFileName(wszFullName);
+ }
}
}
- }
- MoveFileW(wszExistingFile, F->ofd->wszPath);
- F->ofd->Finish();
+ MoveFileW(wszExistingFile, ft->ofd->wszPath);
+ ft->ofd->Finish();
+ }
}
mir_cslock lck(m_csFiles);
- m_arFiles.remove(F);
- delete F;
+ m_arFiles.remove(ft);
+ delete ft;
return;
}
@@ -331,6 +356,15 @@ void CTelegramProto::ProcessFile(TD::updateFile *pObj) db_event_delivered(it->hContact, hDbEvent);
}
}
+
+ if (auto *ft = FindFile(pFile->id_)) {
+ // file being uploaded is finished
+ ProtoBroadcastAck(ft->m_hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft);
+
+ mir_cslock lck(m_csFiles);
+ m_arFiles.remove(ft);
+ delete ft;
+ }
return;
}
}
diff --git a/protocols/Telegram/src/groupchat.cpp b/protocols/Telegram/src/groupchat.cpp index e3a646dc03..c4f134f6d9 100644 --- a/protocols/Telegram/src/groupchat.cpp +++ b/protocols/Telegram/src/groupchat.cpp @@ -1,5 +1,5 @@ /* -Copyright (C) 2012-24 Miranda NG team (https://miranda-ng.org) +Copyright (C) 2012-25 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 @@ -46,7 +46,7 @@ void CTelegramProto::InitGroupChat(TG_USER *pUser, const wchar_t *pwszTitle) if (pUser->bLoadMembers) { pUser->m_si = si = Chat_NewSession(GCW_CHATROOM, m_szModuleName, wszId, pwszTitle, pUser); - if (!si->pStatuses) { + if (!si->arStatuses.getCount()) { Chat_AddGroup(si, TranslateT("Creator")); Chat_AddGroup(si, TranslateT("Admin")); Chat_AddGroup(si, TranslateT("Participant")); @@ -61,7 +61,7 @@ void CTelegramProto::InitGroupChat(TG_USER *pUser, const wchar_t *pwszTitle) } else { pUser->m_si = si = Chat_NewSession(GCW_CHANNEL, m_szModuleName, wszId, pwszTitle, pUser); - if (!si->pStatuses) { + if (!si->arStatuses.getCount()) { Chat_AddGroup(si, TranslateT("SuperAdmin")); Chat_AddGroup(si, TranslateT("Visitor")); @@ -391,67 +391,36 @@ void CTelegramProto::ProcessBasicGroup(TD::updateBasicGroup *pObj) pUser->bLoadMembers = true; } -void CTelegramProto::ProcessBasicGroupInfo(TD::updateBasicGroupFullInfo *pObj) +void CTelegramProto::ProcessBasicGroupInfo(TG_USER *pChat, TD::basicGroupFullInfo *pInfo) { - auto *pChat = FindUser(pObj->basic_group_id_); - if (pChat == nullptr || pChat->m_si == nullptr) - return; - - if (auto *pInfo = pObj->basic_group_full_info_.get()) { - if (!pInfo->description_.empty()) - GcChangeTopic(pChat, pInfo->description_); - - g_chatApi.UM_RemoveAll(pChat->m_si); - GcAddMembers(pChat, pInfo->members_, true); - } -} - -void CTelegramProto::ProcessForum(TD::updateForumTopicInfo *pForum) -{ - auto *pUser = FindChat(pForum->chat_id_); - if (!pUser) { - debugLogA("Uknown chat id %lld, skipping", pForum->chat_id_); - return; - } - - auto *pInfo = pForum->info_.get(); - if (pUser->m_si == nullptr) { - debugLogA("No parent chat for id %lld, skipping", pForum->chat_id_); - return; - } - - if (pInfo->is_general_) { - SetId(pUser->m_si->hContact, pForum->info_->message_thread_id_, DBKEY_THREAD); - return; + if (!pInfo->description_.empty()) { + setUString(pChat->hContact, "About", pInfo->description_.c_str()); + GcChangeTopic(pChat, pInfo->description_); } - wchar_t wszId[100]; - mir_snwprintf(wszId, L"%lld_%lld", pForum->chat_id_, pForum->info_->message_thread_id_); - - auto *si = Chat_NewSession(GCW_CHATROOM, m_szModuleName, wszId, Utf2T(pForum->info_->name_.c_str()), pUser); - si->pParent = pUser->m_si; - - SetId(si->hContact, pForum->info_->message_thread_id_, DBKEY_THREAD); - SetId(si->hContact, pUser->id, DBKEY_OWNER); - - Chat_Mute(si->hContact, Chat_IsMuted(pUser->hContact)); - Clist_SetGroup(si->hContact, ptrW(Clist_GetGroup(pUser->hContact))); - - Chat_Control(si, m_bHideGroupchats ? WINDOW_HIDDEN : SESSION_INITDONE); - Chat_Control(si, SESSION_ONLINE); + g_chatApi.UM_RemoveAll(pChat->m_si); + GcAddMembers(pChat, pInfo->members_, true); } -void CTelegramProto::ProcessSuperGroupInfo(TD::updateSupergroupFullInfo *pObj) +void CTelegramProto::ProcessSuperGroupInfo(TG_USER *pUser, TD::supergroupFullInfo *pInfo) { - auto *pChat = FindUser(pObj->supergroup_id_); - if (pChat == nullptr) { - debugLogA("Uknown super group id %lld, skipping", pObj->supergroup_id_); - return; + setDword(pUser->hContact, "MemberCount", pInfo->member_count_); + + if (auto *pLink = pInfo->invite_link_.get()) + setUString(pUser->hContact, "Link", pLink->invite_link_.c_str()); + else if (auto *pGroup = FindSuperGroup(pUser->id)) { + if (pGroup->group->usernames_) { + CMStringA szLink(FORMAT, "https://t.me/%s", pGroup->group->usernames_->editable_username_.c_str()); + setString(pUser->hContact, "Link", szLink); + } + else delSetting(pUser->hContact, "Link"); } + else delSetting(pUser->hContact, "Link"); - auto *pInfo = pObj->supergroup_full_info_.get(); - if (!pInfo->description_.empty()) - GcChangeTopic(pChat, pInfo->description_); + if (!pInfo->description_.empty()) { + setUString(pUser->hContact, "About", pInfo->description_.c_str()); + GcChangeTopic(pUser, pInfo->description_); + } } void CTelegramProto::ProcessSuperGroup(TD::updateSupergroup *pObj) @@ -462,16 +431,16 @@ void CTelegramProto::ProcessSuperGroup(TD::updateSupergroup *pObj) return; } - TG_SUPER_GROUP tmp(pObj->supergroup_->id_, 0); - auto *pGroup = m_arSuperGroups.find(&tmp); + auto id = pObj->supergroup_->id_; + auto *pGroup = FindSuperGroup(id); if (pGroup == nullptr) { - pGroup = new TG_SUPER_GROUP(tmp.id, std::move(pObj->supergroup_)); + pGroup = new TG_SUPER_GROUP(id, std::move(pObj->supergroup_)); m_arSuperGroups.insert(pGroup); } else pGroup->group = std::move(pObj->supergroup_); if (iStatusId == TD::chatMemberStatusLeft::ID) { - auto *pUser = AddFakeUser(tmp.id, true); + auto *pUser = AddFakeUser(id, true); pUser->isForum = pGroup->group->is_forum_; if (pUser->hContact == INVALID_CONTACT_ID) { // cache some information for the search @@ -482,7 +451,7 @@ void CTelegramProto::ProcessSuperGroup(TD::updateSupergroup *pObj) else RemoveFromClist(pUser); } else { - auto *pChat = AddUser(tmp.id, true); + auto *pChat = AddUser(id, true); pChat->isForum = pGroup->group->is_forum_; if (!pGroup->group->is_channel_) pChat->bLoadMembers = true; @@ -506,3 +475,57 @@ void CTelegramProto::ProcessSuperGroup(TD::updateSupergroup *pObj) } } } + +///////////////////////////////////////////////////////////////////////////////////////// +// forums + +void CTelegramProto::OnGetTopics(td::ClientManager::Response &response, void *pUserInfo) +{ + if (!response.object) + return; + + if (response.object->get_id() != TD::forumTopics::ID) + return; + + auto *pUser = (TG_USER *)pUserInfo; + + auto *pInfo = (TD::forumTopics *)response.object.get(); + if (pInfo->topics_.size() >= 100) + SendQuery(new TD::getForumTopics(pUser->chatId, "", pInfo->next_offset_date_, pInfo->next_offset_message_id_, pInfo->next_offset_message_thread_id_, 100), + &CTelegramProto::OnGetTopics, pUser); +} + +void CTelegramProto::ProcessForum(TD::updateForumTopicInfo *pForum) +{ + auto *pUser = FindChat(pForum->chat_id_); + if (!pUser) { + debugLogA("Uknown chat id %lld, skipping", pForum->chat_id_); + return; + } + + auto *pInfo = pForum->info_.get(); + if (pUser->m_si == nullptr) { + debugLogA("No parent chat for id %lld, skipping", pForum->chat_id_); + return; + } + + if (pInfo->is_general_) { + SetId(pUser->m_si->hContact, pForum->info_->message_thread_id_, DBKEY_THREAD); + return; + } + + wchar_t wszId[100]; + mir_snwprintf(wszId, L"%lld_%lld", pForum->chat_id_, pForum->info_->message_thread_id_); + + auto *si = Chat_NewSession(GCW_CHATROOM, m_szModuleName, wszId, Utf2T(pForum->info_->name_.c_str()), pUser); + si->pParent = pUser->m_si; + + SetId(si->hContact, pForum->info_->message_thread_id_, DBKEY_THREAD); + SetId(si->hContact, pUser->id, DBKEY_OWNER); + + Chat_Mute(si->hContact, Chat_IsMuted(pUser->hContact)); + Clist_SetGroup(si->hContact, ptrW(Clist_GetGroup(pUser->hContact))); + + Chat_Control(si, m_bHideGroupchats ? WINDOW_HIDDEN : SESSION_INITDONE); + Chat_Control(si, SESSION_ONLINE); +} diff --git a/protocols/Telegram/src/menus.cpp b/protocols/Telegram/src/menus.cpp index 413193d8b0..f636ad0cb3 100644 --- a/protocols/Telegram/src/menus.cpp +++ b/protocols/Telegram/src/menus.cpp @@ -1,5 +1,5 @@ /* -Copyright (C) 2012-24 Miranda NG team (https://miranda-ng.org) +Copyright (C) 2012-25 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 diff --git a/protocols/Telegram/src/options.cpp b/protocols/Telegram/src/options.cpp index be588e33ea..04a741e829 100644 --- a/protocols/Telegram/src/options.cpp +++ b/protocols/Telegram/src/options.cpp @@ -1,5 +1,5 @@ /*
-Copyright (C) 2012-24 Miranda NG team (https://miranda-ng.org)
+Copyright (C) 2012-25 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
@@ -22,7 +22,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. class COptionsDlg : public CTelegramDlgBase
{
CCtrlButton btnLogout;
- CCtrlCheck chkHideChats, chkCompressFiles, chkIncludePreviews, chkResidentChannels;
+ CCtrlCheck chkHideChats, chkCompressFiles, chkIncludePreviews, chkResidentChannels, chkDeleteContacts;
CCtrlCombo cmbCountry;
CCtrlEdit edtGroup, edtPhone, edtDeviceName;
ptrW m_wszOldGroup;
@@ -37,6 +37,7 @@ public: edtGroup(this, IDC_DEFGROUP),
edtDeviceName(this, IDC_DEVICE_NAME),
chkCompressFiles(this, IDC_COMPRESS_FILES),
+ chkDeleteContacts(this, IDC_DELETE_CONTACTS),
chkIncludePreviews(this, IDC_USE_PREVIEW),
chkResidentChannels(this, IDC_RESIDENT_CHANNELS),
m_wszOldGroup(mir_wstrdup(ppro->m_wszDefaultGroup))
@@ -48,6 +49,7 @@ public: if (bFullDlg) {
CreateLink(chkCompressFiles, ppro->m_bCompressFiles);
+ CreateLink(chkDeleteContacts, ppro->m_bDeleteContacts);
CreateLink(chkIncludePreviews, ppro->m_bIncludePreviews);
CreateLink(chkResidentChannels, ppro->m_bResidentChannels);
}
@@ -170,7 +172,7 @@ public: void onChange_Value1(int val)
{
- bool bEnabled = val != 0;
+ bool bEnabled = val > 0;
spin2.Enable(bEnabled);
edtDiff2.Enable(bEnabled);
cmbStatus1.Enable(bEnabled);
diff --git a/protocols/Telegram/src/proto.cpp b/protocols/Telegram/src/proto.cpp index efb92742fb..66fab24119 100644 --- a/protocols/Telegram/src/proto.cpp +++ b/protocols/Telegram/src/proto.cpp @@ -17,7 +17,10 @@ static int CompareRequests(const TG_REQUEST_BASE *p1, const TG_REQUEST_BASE *p2) } static int CompareChats(const TG_USER *p1, const TG_USER *p2) -{ return CompareId(p1->chatId, p2->chatId); +{ + if (p1->chatId != p2->chatId) + return CompareId(p1->chatId, p2->chatId); + return CompareId(p1->forumId, p2->forumId); } static int CompareUsers(const TG_USER *p1, const TG_USER *p2) @@ -57,6 +60,7 @@ CTelegramProto::CTelegramProto(const char* protoName, const wchar_t* userName) : m_bUsePopups(this, "UsePopups", true), m_bCompressFiles(this, "CompressFiles", true), m_bHideGroupchats(this, "HideChats", true), + m_bDeleteContacts(this, "DeleteContacts", false), m_bIncludePreviews(this, "IncludePreview", true), m_bResidentChannels(this, "ResidentChannels", false) { @@ -108,6 +112,8 @@ CTelegramProto::CTelegramProto(const char* protoName, const wchar_t* userName) : HookProtoEvent(ME_GC_MUTE, &CTelegramProto::GcMuteHook); HookProtoEvent(ME_GC_EVENT, &CTelegramProto::GcEventHook); HookProtoEvent(ME_GC_BUILDMENU, &CTelegramProto::GcMenuHook); + + CheckCompatibility(); } CTelegramProto::~CTelegramProto() @@ -125,6 +131,12 @@ void CTelegramProto::OnCacheInit() if (int64_t id = GetId(cc)) { bool isGroupChat = isChatRoom(cc); auto *pUser = new TG_USER(id, cc, isGroupChat); + if (auto iThreadId = GetId(cc, DBKEY_THREAD)) { + pUser->isForum = true; + pUser->chatId = pUser->id; + pUser->forumId = iThreadId; + m_arChats.insert(pUser); + } pUser->szAvatarHash = getMStringA(cc, DBKEY_AVATAR_HASH); m_arUsers.insert(pUser); if (isGroupChat && iCompatLevel < 3) @@ -174,6 +186,8 @@ void CTelegramProto::OnModulesLoaded() { InitPopups(); + HookProtoEvent(ME_USERINFO_INITIALISE, &CTelegramProto::OnUserInfoInit); + m_bSmileyAdd = ServiceExists(MS_SMILEYADD_REPLACESMILEYS); if (m_bSmileyAdd) SmileyAdd_LoadContactSmileys(SMADD_FOLDER, m_szModuleName, GetAvatarPath() + L"\\Stickers\\*.*"); @@ -183,9 +197,10 @@ void CTelegramProto::OnShutdown() { m_bTerminated = true; - for (auto &cc : m_arUsers) - if (cc->isBot && !cc->chatId && cc->hContact != INVALID_CONTACT_ID) - Contact::RemoveFromList(cc->hContact); + if (m_bDeleteContacts) + for (auto &cc : m_arUsers) + if (cc->isBot && !cc->chatId && cc->hContact != INVALID_CONTACT_ID) + Contact::RemoveFromList(cc->hContact); } int CTelegramProto::OnWindowEvent(WPARAM wParam, LPARAM lParam) @@ -264,9 +279,9 @@ void CTelegramProto::OnEventEdited(MCONTACT hContact, MEVENT, const DBEVENTINFO return; if (dbei.szId && dbei.cbBlob && dbei.pBlob && dbei.eventType == EVENTTYPE_MESSAGE) { - auto text = formatBbcodes((char*)dbei.pBlob); - // auto content = TD::make_object<TD::inputMessageText>(std::move(text), 0, false); - // SendQuery(new TD::editMessageText(pUser->chatId, dbei2id(dbei), 0, std::move(content))); + auto content = TD::make_object<TD::inputMessageText>(); + content->text_ = formatBbcodes((char *)dbei.pBlob); + SendQuery(new TD::editMessageText(pUser->chatId, dbei2id(dbei), 0, std::move(content))); } } @@ -377,6 +392,50 @@ INT_PTR CTelegramProto::GetCaps(int type, MCONTACT hContact) ///////////////////////////////////////////////////////////////////////////////////////// +int CTelegramProto::GetInfo(MCONTACT hContact, int) +{ + if (auto *pUser = FindUser(GetId(hContact))) { + if (!pUser->isGroupChat) + SendQuery(new TD::getUserFullInfo(pUser->id), &CTelegramProto::OnGetUserInfo, pUser); + else { + if (FindSuperGroup(pUser->id)) + SendQuery(new TD::getSupergroupFullInfo(pUser->id), &CTelegramProto::OnGetUserInfo, pUser); + else + SendQuery(new TD::getBasicGroupFullInfo(pUser->id), &CTelegramProto::OnGetUserInfo, pUser); + } + return 1; + } + return 0; +} + +void CTelegramProto::OnGetUserInfo(td::ClientManager::Response &response, void *pUserInfo) +{ + if (!response.object) + return; + + auto *pUser = (TG_USER *)pUserInfo; + + switch (response.object->get_id()) { + case TD::basicGroupFullInfo::ID: + ProcessBasicGroupInfo(pUser, (TD::basicGroupFullInfo *)response.object.get()); + break; + case TD::supergroupFullInfo::ID: + ProcessSuperGroupInfo(pUser, (TD::supergroupFullInfo *)response.object.get()); + break; + case TD::userFullInfo::ID: + ProcessUserInfo(pUser->id, (TD::userFullInfo *)response.object.get()); + break; + + default: + debugLogA("Gotten class ID %d instead of %d, exiting", response.object->get_id(), TD::chats::ID); + return; + } + + ProtoBroadcastAck(pUser->hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, HANDLE(1)); +} + +///////////////////////////////////////////////////////////////////////////////////////// + void CTelegramProto::OnSearchResults(td::ClientManager::Response &response) { int iCount = ::InterlockedDecrement(&m_iSearchCount); @@ -447,6 +506,16 @@ void CTelegramProto::ProcessFileMessage(TG_FILE_REQUEST *ft, const TD::message * return; } + // if that file was sent once, it might be cached at the server & reused + if (auto *pRemote = pFile->remote_.get()) { + if (pRemote->is_uploading_completed_) { + ShowFileProgress(pFile, ft); + ProtoBroadcastAck(ft->m_hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft); + delete ft; + return; + } + } + char szUserId[100]; auto szMsgId(msg2id(pMsg)); @@ -462,24 +531,32 @@ void CTelegramProto::ProcessFileMessage(TG_FILE_REQUEST *ft, const TD::message * dbei.szModule = Proto_GetBaseAccountName(ft->m_hContact); dbei.eventType = EVENTTYPE_FILE; dbei.flags = DBEF_SENT | DBEF_UTF; - dbei.timestamp = time(0); - - TG_FILE_REQUEST localft(TG_FILE_REQUEST::FILE, 0, 0); - localft.m_fileName = Utf2T(pFile->local_->path_.c_str()); - localft.m_fileSize = pFile->size_; - localft.m_uniqueId = szMsgId; - localft.m_szUserId = szUserId; - - DB::FILE_BLOB blob(localft.m_fileName, ft->m_wszDescr); - OnSendOfflineFile(dbei, blob, &localft); + dbei.iTimestamp = time(0); + + auto *localft = new TG_FILE_REQUEST(TG_FILE_REQUEST::FILE, 0, 0); + localft->m_hContact = ft->m_hContact; + localft->m_fileName = Utf2T(pFile->local_->path_.c_str()); + localft->m_fileSize = pFile->size_; + localft->m_uniqueId = szMsgId; + localft->m_szUserId = szUserId; + localft->m_fileId = pFile->id_; + + DB::FILE_BLOB blob(localft->m_fileName, ft->m_wszDescr); + OnSendOfflineFile(dbei, blob, localft); blob.write(dbei); db_event_add(ft->m_hContact, &dbei); + + mir_cslock lck(m_csFiles); + m_arFiles.insert(localft); } else { ft->m_szUserId = szUserId; ft->m_uniqueId = szMsgId; - ProtoBroadcastAck(ft->m_hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft); + ft->m_fileId = pFile->id_; + + mir_cslock lck(m_csFiles); + m_arFiles.insert(ft); } } } @@ -490,7 +567,6 @@ void CTelegramProto::OnSendFile(td::ClientManager::Response &response, void *pUs if (response.object->get_id() == TD::message::ID) { ProcessFileMessage(ft, (TD::message *)response.object.get(), false); - ProtoBroadcastAck(ft->m_hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft); } else if (response.object->get_id() == TD::messages::ID) { int i = 0; @@ -500,8 +576,6 @@ void CTelegramProto::OnSendFile(td::ClientManager::Response &response, void *pUs i++; } } - - delete ft; } HANDLE CTelegramProto::SendFile(MCONTACT hContact, const wchar_t *szDescription, wchar_t **ppszFiles) @@ -586,8 +660,8 @@ HANDLE CTelegramProto::SendFile(MCONTACT hContact, const wchar_t *szDescription, pPart = std::move(pContent); } else if (iFileType == TG_FILE_REQUEST::VOICE) { - auto pContent = TD::make_object<TD::inputMessageVoiceNote>(); - pContent->voice_note_ = makeFile(it->pwszName); + auto pContent = TD::make_object<TD::inputMessageAudio>(); + pContent->audio_ = makeFile(it->pwszName); pContent->caption_ = std::move(caption); pContent->duration_ = 0; pPart = std::move(pContent); @@ -654,6 +728,8 @@ int CTelegramProto::SetStatus(int iNewStatus) // Routing statuses not supported by Telegram switch (iNewStatus) { case ID_STATUS_OFFLINE: + case ID_STATUS_AWAY: + case ID_STATUS_NA: m_iDesiredStatus = iNewStatus; break; diff --git a/protocols/Telegram/src/proto.h b/protocols/Telegram/src/proto.h index 69737ba35c..a465104f01 100644 --- a/protocols/Telegram/src/proto.h +++ b/protocols/Telegram/src/proto.h @@ -99,9 +99,9 @@ struct TG_USER : public MZeroedObject delete pReactions; } - int64_t id, chatId = -1; + int64_t id, chatId = -1, forumId = -1, lastReadId; MCONTACT hContact; - int folderId = -1, nHistoryChunks; + int folderId = -1, nTopics; bool isGroupChat, isChannel, isBot, isForum, bLoadMembers, bStartChat, bInited, bDelOwn = true, bDelAll = true; CMStringA szAvatarHash; CMStringW wszNick, wszFirstName, wszLastName; @@ -154,6 +154,7 @@ class CTelegramProto : public PROTO<CTelegramProto> friend class CReplyDlg; friend class CForwardDlg; friend class CReactionsDlg; + friend class CMyProfileDlg; friend class COptionsDlg; friend class COptSessionsDlg; friend class CAddPhoneContactDlg; @@ -215,11 +216,12 @@ class CTelegramProto : public PROTO<CTelegramProto> OBJLIST<TG_OWN_MESSAGE> m_arOwnMsg; mir_cs m_csRequests; - OBJLIST<TG_REQUEST_BASE> m_arRequests; + LIST<TG_REQUEST_BASE> m_arRequests; mir_cs m_csFiles; LIST<TG_FILE_REQUEST> m_arFiles; TG_FILE_REQUEST* FindFile(const char *pszUniqueId); + TG_FILE_REQUEST* FindFile(int id); static INT_PTR CALLBACK EnterEmail(void *param); static INT_PTR CALLBACK EnterEmailCode(void *param); @@ -236,6 +238,7 @@ class CTelegramProto : public PROTO<CTelegramProto> void OnGetFileLink(td::ClientManager::Response &response); void OnGetHistory(td::ClientManager::Response &response, void *pUserInfo); void OnGetSessions(td::ClientManager::Response &response, void *pUserInfo); + void OnGetUserInfo(td::ClientManager::Response &response, void *pUserInfo); void OnKillSession(td::ClientManager::Response &response, void *pUserInfo); void OnLeaveChat(td::ClientManager::Response &response, void *pUserInfo); void OnSendFile(td::ClientManager::Response &response, void *pUserInfo); @@ -257,7 +260,7 @@ class CTelegramProto : public PROTO<CTelegramProto> void ProcessAvatar(const TD::file *pFile, TG_USER *pUser); void ProcessAuth(TD::updateAuthorizationState *pObj); void ProcessBasicGroup(TD::updateBasicGroup *pObj); - void ProcessBasicGroupInfo(TD::updateBasicGroupFullInfo *pObj); + void ProcessBasicGroupInfo(TG_USER *pUser, TD::basicGroupFullInfo *pObj); void ProcessChat(TD::updateNewChat *pObj); void ProcessChatAction(TD::updateChatAction *pObj); void ProcessChatHasProtected(TD::updateChatHasProtectedContent *pObj); @@ -282,8 +285,9 @@ class CTelegramProto : public PROTO<CTelegramProto> void ProcessServiceNotification(TD::updateServiceNotification *pObj); void ProcessStatus(TD::updateUserStatus *pObj); void ProcessSuperGroup(TD::updateSupergroup *pObj); - void ProcessSuperGroupInfo(TD::updateSupergroupFullInfo *pObj); + void ProcessSuperGroupInfo(TG_USER *pUser, TD::supergroupFullInfo *pObj); void ProcessUser(TD::updateUser *pObj); + void ProcessUserInfo(TD::int53 userId, TD::userFullInfo *pObj); void UnregisterSession(); @@ -300,6 +304,8 @@ class CTelegramProto : public PROTO<CTelegramProto> bool bRead; }; + void ShowFileProgress(const TD::file *pFile, TG_FILE_REQUEST *ft); + bool GetMessageFile(const EmbeddedFile &embed, TG_FILE_REQUEST::Type, const TD::file *pFile, const char *pszFileName, const char *pszCaption); CMStringA GetFormattedText(TD::object_ptr<TD::formattedText> &pText); @@ -340,6 +346,7 @@ class CTelegramProto : public PROTO<CTelegramProto> TD::array<TD::int53> m_searchIds; void OnSearchResults(td::ClientManager::Response &response); + void OnGetTopics(td::ClientManager::Response &response, void *pUserInfo); bool CheckSearchUser(TG_USER *pUser); void ReportSearchUser(TG_USER *pUser); @@ -352,17 +359,21 @@ class CTelegramProto : public PROTO<CTelegramProto> OBJLIST<TG_USER> m_arUsers; TG_USER* FindChat(int64_t id); + TG_USER* FindChat(int64_t id, int64_t forumId); TG_USER* FindUser(int64_t id); TG_USER* AddUser(int64_t id, bool bIsChat); TG_USER* AddFakeUser(int64_t id, bool bIsChat); TG_USER* GetSender(const TD::MessageSender *pSender); + TG_SUPER_GROUP* FindSuperGroup(int64_t id); + int64_t GetId(MCONTACT, const char *pszSetting = DBKEY_ID); void SetId(MCONTACT, int64_t id, const char *pszSetting = DBKEY_ID); int GetDefaultMute(const TG_USER *pUser); - MCONTACT GetRealContact(const TG_USER *pUser); + void CheckCompatibility(void); + MCONTACT GetRealContact(const TG_USER *pUser, int64_t threadId = 0); void RemoveFromClist(TG_USER *pUser); void MarkRead(MCONTACT hContact, const CMStringA &szMaxId, bool bSent); @@ -394,6 +405,7 @@ public: int AuthRequest(MCONTACT hContact, const wchar_t *) override; INT_PTR GetCaps(int type, MCONTACT hContact = NULL) override; + int GetInfo(MCONTACT hContact, int type) override; HANDLE SendFile(MCONTACT hContact, const wchar_t *szDescription, wchar_t **ppszFiles) override; @@ -426,6 +438,8 @@ public: int __cdecl GcMuteHook(WPARAM, LPARAM); int __cdecl GcEventHook(WPARAM, LPARAM); + int __cdecl OnUserInfoInit(WPARAM, LPARAM); + // Services ////////////////////////////////////////////////////////////////////////// INT_PTR __cdecl SvcAddByPhone(WPARAM, LPARAM); @@ -446,6 +460,7 @@ public: CMOption<bool> m_bIncludePreviews; // include URL previews into message text CMOption<bool> m_bResidentChannels; // don't store channel messages in a database CMOption<bool> m_bCompressFiles; // embed pictures & videos into a message on send + CMOption<bool> m_bDeleteContacts; // delete contacts from Miranda when they are deleted from server CMOption<uint32_t> m_iTimeDiff1; // set this status to m_iStatus1 after this interval of secs CMOption<uint32_t> m_iStatus1; CMOption<uint32_t> m_iTimeDiff2; // set this status to m_iStatus2 after this interval of secs diff --git a/protocols/Telegram/src/resource.h b/protocols/Telegram/src/resource.h index 9e6bebafce..5b55af12a3 100644 --- a/protocols/Telegram/src/resource.h +++ b/protocols/Telegram/src/resource.h @@ -13,10 +13,13 @@ #define IDI_REACTION 108
#define IDD_REACTIONS 109
#define IDI_BOT 110
+#define IDD_MYPROFILE 111
#define IDD_OPTIONS_SESSIONS 112
+#define IDD_CHANNEL_INFO 113
#define IDC_PHONE 1001
#define IDC_DEFGROUP 1002
#define IDC_HIDECHATS 1003
+#define IDC_DELETE_CONTACTS 1004
#define IDC_DEVICE_NAME 1005
#define IDC_DIFF1 1006
#define IDC_DIFF2 1007
@@ -33,17 +36,21 @@ #define IDC_REACTIONS 1018
#define IDC_USE_PREVIEW 1018
#define IDC_RESIDENT_CHANNELS 1019
+#define IDC_BIO 1020
+#define IDC_BIRTHDAY 1021
#define IDC_SESSIONS 1023
+#define IDC_LINK 1024
#define IDC_SOFTWARE 1025
-#define IDC_LOGOUT 1025
+#define IDC_LOGOUT 1026
+#define IDC_USER_COUNT 1027
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE 116
+#define _APS_NEXT_RESOURCE_VALUE 120
#define _APS_NEXT_COMMAND_VALUE 40001
-#define _APS_NEXT_CONTROL_VALUE 1027
+#define _APS_NEXT_CONTROL_VALUE 1030
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
diff --git a/protocols/Telegram/src/server.cpp b/protocols/Telegram/src/server.cpp index 952e076940..82e7225f01 100644 --- a/protocols/Telegram/src/server.cpp +++ b/protocols/Telegram/src/server.cpp @@ -1,5 +1,5 @@ /*
-Copyright (C) 2012-24 Miranda NG team (https://miranda-ng.org)
+Copyright (C) 2012-25 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
@@ -194,11 +194,14 @@ void CTelegramProto::ProcessResponse(td::ClientManager::Response response) if (response.request_id) {
TG_REQUEST tmp(response.request_id, 0);
- mir_cslock lck(m_csRequests);
+ mir_cslockfull lck(m_csRequests);
auto *p = m_arRequests.find(&tmp);
if (p) {
- p->Execute(this, response);
m_arRequests.remove(p);
+ lck.unlock();
+
+ p->Execute(this, response);
+ delete p;
}
return;
}
@@ -213,11 +216,15 @@ void CTelegramProto::ProcessResponse(td::ClientManager::Response response) break;
case TD::updateBasicGroup::ID:
- ProcessBasicGroup((TD::updateBasicGroup*)response.object.get());
+ ProcessBasicGroup((TD::updateBasicGroup *)response.object.get());
break;
case TD::updateBasicGroupFullInfo::ID:
- ProcessBasicGroupInfo((TD::updateBasicGroupFullInfo *)response.object.get());
+ {
+ auto *pObj = (TD::updateBasicGroupFullInfo *)response.object.get();
+ if (auto *pChat = FindUser(pObj->basic_group_id_))
+ ProcessBasicGroupInfo(pChat, pObj->basic_group_full_info_.get());
+ }
break;
case TD::updateChatAction::ID:
@@ -241,7 +248,7 @@ void CTelegramProto::ProcessResponse(td::ClientManager::Response response) break;
case TD::updateChatNotificationSettings::ID:
- ProcessChatNotification((TD::updateChatNotificationSettings*)response.object.get());
+ ProcessChatNotification((TD::updateChatNotificationSettings *)response.object.get());
break;
case TD::updateChatPosition::ID:
@@ -257,9 +264,9 @@ void CTelegramProto::ProcessResponse(td::ClientManager::Response response) break;
case TD::updateDeleteMessages::ID:
- ProcessDeleteMessage((TD::updateDeleteMessages*)response.object.get());
+ ProcessDeleteMessage((TD::updateDeleteMessages *)response.object.get());
break;
-
+
case TD::updateConnectionState::ID:
ProcessConnectionState((TD::updateConnectionState *)response.object.get());
break;
@@ -269,7 +276,7 @@ void CTelegramProto::ProcessResponse(td::ClientManager::Response response) break;
case TD::updateForumTopicInfo::ID:
- ProcessForum((TD::updateForumTopicInfo*)response.object.get());
+ ProcessForum((TD::updateForumTopicInfo *)response.object.get());
break;
case TD::updateMessageContent::ID:
@@ -309,8 +316,7 @@ void CTelegramProto::ProcessResponse(td::ClientManager::Response response) ProcessChat((TD::updateNewChat *)response.object.get());
break;
- case TD::updateNewMessage::ID:
- {
+ case TD::updateNewMessage::ID: {
auto *pMessage = ((TD::updateNewMessage *)response.object.get())->message_.get();
TG_OWN_MESSAGE tmp(0, 0, msg2id(pMessage));
if (!m_arOwnMsg.find(&tmp))
@@ -335,7 +341,13 @@ void CTelegramProto::ProcessResponse(td::ClientManager::Response response) break;
case TD::updateSupergroupFullInfo::ID:
- ProcessSuperGroupInfo((TD::updateSupergroupFullInfo *)response.object.get());
+ {
+ auto *pObj = (TD::updateSupergroupFullInfo *)response.object.get();
+ if (auto *pUser = FindUser(pObj->supergroup_id_))
+ ProcessSuperGroupInfo(pUser, pObj->supergroup_full_info_.get());
+ else
+ debugLogA("Uknown super group id %lld, skipping", pObj->supergroup_id_);
+ }
break;
case TD::updateUserStatus::ID:
@@ -345,6 +357,11 @@ void CTelegramProto::ProcessResponse(td::ClientManager::Response response) case TD::updateUser::ID:
ProcessUser((TD::updateUser *)response.object.get());
break;
+
+ case TD::updateUserFullInfo::ID:
+ if (auto *pObj = (TD::updateUserFullInfo *)response.object.get())
+ ProcessUserInfo(pObj->user_id_, pObj->user_full_info_.get());
+ break;
}
}
@@ -448,6 +465,12 @@ void CTelegramProto::OnGetHistory(td::ClientManager::Response &response, void *p auto *pUser = (TG_USER *)pUserInfo;
TD::int53 lastMsgId = INT64_MAX;
auto *pMessages = (TD::messages *)response.object.get();
+ if (pMessages->messages_.size() == 0) {
+ if (pUser->isForum)
+ delete pUser;
+ return;
+ }
+
for (auto &it : pMessages->messages_) {
auto *pMsg = it.get();
if (pMsg->id_ < lastMsgId)
@@ -465,11 +488,13 @@ void CTelegramProto::OnGetHistory(td::ClientManager::Response &response, void *p DBEVENTINFO dbei = {};
dbei.eventType = EVENTTYPE_MESSAGE;
dbei.szModule = m_szModuleName;
- dbei.timestamp = pMsg->date_;
+ dbei.iTimestamp = pMsg->date_;
dbei.cbBlob = szBody.GetLength();
dbei.pBlob = szBody.GetBuffer();
dbei.szId = szMsgId;
- dbei.flags = DBEF_READ | DBEF_UTF;
+ dbei.bRead = dbei.bUtf = true;
+ if (pMsg->edit_date_)
+ dbei.bEdited = true;
if (pMsg->is_outgoing_)
dbei.flags |= DBEF_SENT;
if (this->GetGcUserId(pUser, pMsg, szUserId))
@@ -481,27 +506,15 @@ void CTelegramProto::OnGetHistory(td::ClientManager::Response &response, void *p db_event_add(GetRealContact(pUser), &dbei);
}
- pUser->nHistoryChunks--;
-
- if (pUser->isForum) {
- if (lastMsgId != INT64_MAX && pUser->nHistoryChunks > 0)
- SendQuery(new TD::getMessageThreadHistory(pUser->chatId, lastMsgId, lastMsgId, 0, 100), &CTelegramProto::OnGetHistory, pUser);
- else
- delete pUser;
- }
- else if (lastMsgId != INT64_MAX && pUser->nHistoryChunks > 0)
+ // fetch next portion
+ if (pUser->isForum)
+ SendQuery(new TD::getMessageThreadHistory(pUser->chatId, lastMsgId, lastMsgId, 0, 100), &CTelegramProto::OnGetHistory, pUser);
+ else
SendQuery(new TD::getChatHistory(pUser->chatId, lastMsgId, 0, 100, false), &CTelegramProto::OnGetHistory, pUser);
}
INT_PTR CTelegramProto::SvcLoadServerHistory(WPARAM hContact, LPARAM)
{
- TD::int53 lastMsgId = 0;
-
- if (MEVENT hEvent = db_event_first(hContact)) {
- DB::EventInfo dbei(hEvent, false);
- lastMsgId = dbei2id(dbei);
- }
-
auto userId = GetId(hContact);
if (TD::int53 threadId = GetId(hContact, DBKEY_THREAD)) {
@@ -509,16 +522,13 @@ INT_PTR CTelegramProto::SvcLoadServerHistory(WPARAM hContact, LPARAM) auto *pUser = new TG_USER(-1, hContact, true);
pUser->chatId = userId;
pUser->isForum = pUser->isGroupChat = true;
- pUser->nHistoryChunks = 5;
- SendQuery(new TD::getMessageThreadHistory(pUser->chatId, lastMsgId, lastMsgId, 0, 100), &CTelegramProto::OnGetHistory, pUser);
+ SendQuery(new TD::getMessageThreadHistory(pUser->chatId, 0, 0, 0, 100), &CTelegramProto::OnGetHistory, pUser);
return 0;
}
}
- if (auto *pUser = FindUser(userId)) {
- pUser->nHistoryChunks = 5;
- SendQuery(new TD::getChatHistory(pUser->chatId, lastMsgId, 0, 100, false), &CTelegramProto::OnGetHistory, pUser);
- }
+ if (auto *pUser = FindUser(userId))
+ SendQuery(new TD::getChatHistory(pUser->chatId, 0, 0, 100, false), &CTelegramProto::OnGetHistory, pUser);
return 0;
}
@@ -528,8 +538,7 @@ INT_PTR CTelegramProto::SvcLoadServerHistory(WPARAM hContact, LPARAM) INT_PTR CTelegramProto::SvcCanEmptyHistory(WPARAM hContact, LPARAM bIncoming)
{
if (auto *pUser = FindUser(GetId(hContact))) {
- TG_SUPER_GROUP tmp(pUser->id, 0);
- if (auto *pGroup = m_arSuperGroups.find(&tmp))
+ if (auto *pGroup = FindSuperGroup(pUser->id))
if (pGroup->group->is_channel_)
return 0;
@@ -594,6 +603,7 @@ void CTelegramProto::ProcessChat(TD::updateNewChat *pObj) }
pUser->chatId = pChat->id_;
+ pUser->forumId = -1;
pUser->isChannel = isChannel;
pUser->bDelAll = pChat->can_be_deleted_for_all_users_;
pUser->bDelOwn = pChat->can_be_deleted_only_for_self_;
@@ -603,11 +613,12 @@ void CTelegramProto::ProcessChat(TD::updateNewChat *pObj) if (!m_arChats.find(pUser))
m_arChats.insert(pUser);
+ // small or super group
if (!szTitle.empty()) {
if (hContact != INVALID_CONTACT_ID) {
if (pUser->isForum) {
pUser->wszNick = Utf2T(szTitle.c_str());
- SendQuery(new TD::getForumTopics(pUser->chatId, "", 0, 0, 0, 100));
+ SendQuery(new TD::getForumTopics(pUser->chatId, "", 0, 0, 0, 100), &CTelegramProto::OnGetTopics, pUser);
}
else GcChangeTopic(pUser, szTitle);
}
@@ -633,6 +644,15 @@ void CTelegramProto::ProcessChat(TD::updateNewChat *pObj) if (pUser->isGroupChat && pUser->m_si == nullptr)
InitGroupChat(pUser, (pUser->isForum) ? TranslateT("General") : Utf2T(pChat->title_.c_str()));
}
+ else if (!pUser->isGroupChat) {
+ pUser = AddUser(pChat->id_, false);
+ hContact = pUser->hContact;
+ setWString(hContact, "Nick", pUser->wszNick);
+ if (!pUser->wszFirstName.IsEmpty())
+ setWString(hContact, "FirstName", pUser->wszFirstName);
+ if (!pUser->wszLastName.IsEmpty())
+ setWString(hContact, "LastName", pUser->wszLastName);
+ }
}
void CTelegramProto::ProcessChatAction(TD::updateChatAction *pObj)
@@ -675,11 +695,14 @@ void CTelegramProto::ProcessChatAction(TD::updateChatAction *pObj) Srmm_SetStatusText(hContact, TranslateT("Uploading voice note..."));
break;
case TD::chatActionTyping::ID:
- CallService(MS_PROTO_CONTACTISTYPING, pChat->hContact, 30);
+ if (!pChat->isGroupChat)
+ CallService(MS_PROTO_CONTACTISTYPING, pChat->hContact, 30);
break;
case TD::chatActionCancel::ID:
- Srmm_SetStatusText(hContact, 0);
- CallService(MS_PROTO_CONTACTISTYPING, pChat->hContact, PROTOTYPE_CONTACTTYPING_OFF);
+ if (!pChat->isGroupChat) {
+ Srmm_SetStatusText(hContact, 0);
+ CallService(MS_PROTO_CONTACTISTYPING, pChat->hContact, PROTOTYPE_CONTACTTYPING_OFF);
+ }
break;
}
}
@@ -780,8 +803,9 @@ void CTelegramProto::ProcessChatPosition(TD::updateChatPosition *pObj) debugLogW(L"Existing contact group <%s>, calculated <%s>", pwszExistingGroup.get(), wszGroup.c_str());
wchar_t *pwszDefaultGroup = m_wszDefaultGroup;
+ size_t defLen = mir_wstrlen(pwszDefaultGroup);
if (!pwszExistingGroup || pUser->isForum
- || !mir_wstrncmp(pwszExistingGroup, pwszDefaultGroup, mir_wstrlen(pwszDefaultGroup))
+ || (defLen && !mir_wstrncmp(pwszExistingGroup, pwszDefaultGroup, defLen))
|| (pUser->isGroupChat && !mir_wstrcmp(pwszExistingGroup, Chat_GetGroup())))
{
CMStringW wszNewGroup(pwszDefaultGroup);
@@ -790,6 +814,9 @@ void CTelegramProto::ProcessChatPosition(TD::updateChatPosition *pObj) if (pUser->isForum)
wszNewGroup.AppendFormat(L"\\%s", pUser->wszNick.c_str());
+ if (wszNewGroup[0] == '\\')
+ wszNewGroup.Delete(0, 1);
+
debugLogW(L"Setting group for %d to %s", hContact, wszNewGroup.c_str());
Clist_GroupCreate(0, wszNewGroup);
Clist_SetGroup(hContact, wszNewGroup);
@@ -916,8 +943,10 @@ void CTelegramProto::ProcessMarkRead(TD::updateChatReadInbox *pObj) return;
}
- if (pObj->last_read_inbox_message_id_)
+ if (pObj->last_read_inbox_message_id_) {
pUser->bInited = true;
+ pUser->lastReadId = pObj->last_read_inbox_message_id_;
+ }
CMStringA szMaxId(msg2id(pObj->chat_id_, pObj->last_read_inbox_message_id_));
if (db_event_getById(m_szModuleName, szMaxId) == 0) {
@@ -952,12 +981,6 @@ void CTelegramProto::ProcessMessage(const TD::message *pMessage) auto szMsgId(msg2id(pMessage));
MEVENT hOldEvent = db_event_getById(m_szModuleName, szMsgId);
- CMStringA szText(GetMessageText(pUser, pMessage)), szReplyId;
- if (szText.IsEmpty()) {
- debugLogA("this message was not processed, ignored");
- return;
- }
-
// make a temporary contact if needed
if (pUser->hContact == INVALID_CONTACT_ID) {
if (pUser->isGroupChat) {
@@ -969,14 +992,14 @@ void CTelegramProto::ProcessMessage(const TD::message *pMessage) Contact::RemoveFromList(pUser->hContact);
}
- MCONTACT hContact = GetRealContact(pUser);
- if (pMessage->message_thread_id_) {
- wchar_t buf[100];
- mir_snwprintf(buf, L"%lld_%lld", pMessage->chat_id_, pMessage->message_thread_id_);
- if (auto *si = Chat_Find(buf, m_szModuleName))
- hContact = si->hContact;
+ CMStringA szText(GetMessageText(pUser, pMessage)), szReplyId;
+ if (szText.IsEmpty()) {
+ debugLogA("this message was not processed, ignored");
+ return;
}
+ MCONTACT hContact = GetRealContact(pUser, pMessage->message_thread_id_);
+
if (m_bResidentChannels && pUser->isChannel && pUser->m_si) {
GCEVENT gce = { pUser->m_si, GC_EVENT_MESSAGE };
gce.dwFlags = GCEF_ADDTOLOG | GCEF_UTF8;
@@ -990,11 +1013,15 @@ void CTelegramProto::ProcessMessage(const TD::message *pMessage) DB::EventInfo dbei(hOldEvent);
dbei.szId = szMsgId;
dbei.cbBlob = szText.GetLength();
- dbei.timestamp = pMessage->date_;
+ dbei.iTimestamp = pMessage->date_;
if (pMessage->is_outgoing_)
- dbei.flags |= DBEF_SENT;
+ dbei.bSent = dbei.bRead = true;
+ else if (pMessage->id_ <= pUser->lastReadId)
+ dbei.bRead = true;
+ if (pMessage->edit_date_)
+ dbei.bEdited = true;
if (!pUser->bInited)
- dbei.flags |= DBEF_READ;
+ dbei.bRead = true;
if (GetGcUserId(pUser, pMessage, szUserId))
dbei.szUserId = szUserId;
if (auto iReplyId = getReplyId(pMessage->reply_to_.get())) {
@@ -1079,15 +1106,7 @@ void CTelegramProto::ProcessMessageReactions(TD::updateMessageInteractionInfo *p }
}
- auto &json = dbei.setJson();
- auto it = json.find("r");
- if (it != json.end())
- json.erase(it);
-
- json << reactions;
- dbei.flushJson();
-
- db_event_edit(dbei.getEvent(), &dbei, true);
+ dbei.setReactions(reactions);
}
/////////////////////////////////////////////////////////////////////////////////////////
@@ -1219,6 +1238,8 @@ void CTelegramProto::ProcessStatus(TD::updateUserStatus *pObj) }
}
+/////////////////////////////////////////////////////////////////////////////////////////
+
void CTelegramProto::ProcessUser(TD::updateUser *pObj)
{
auto *pUser = pObj->user_.get();
@@ -1230,6 +1251,7 @@ void CTelegramProto::ProcessUser(TD::updateUser *pObj) case TD::userTypeDeleted::ID:
return;
+ case TD::userTypeBot::ID:
case TD::userTypeRegular::ID:
auto *pu = AddFakeUser(pUser->id_, false);
if (pu->hContact != INVALID_CONTACT_ID)
@@ -1315,3 +1337,17 @@ void CTelegramProto::ProcessUser(TD::updateUser *pObj) }
}
}
+
+void CTelegramProto::ProcessUserInfo(TD::int53 userId, TD::userFullInfo *pObj)
+{
+ if (auto *pUser = FindUser(userId)) {
+ if (auto *pBirthday = pObj->birthdate_.get())
+ Contact::SetBirthday(pUser->hContact, pBirthday->day_, pBirthday->month_, pBirthday->year_);
+
+ if (pObj->bio_) {
+ CMStringA szNotes(GetFormattedText(pObj->bio_));
+ if (!szNotes.IsEmpty())
+ setUString(pUser->hContact, "About", szNotes);
+ }
+ }
+}
diff --git a/protocols/Telegram/src/stdafx.cxx b/protocols/Telegram/src/stdafx.cxx index 87b7477097..72e87c2758 100644 --- a/protocols/Telegram/src/stdafx.cxx +++ b/protocols/Telegram/src/stdafx.cxx @@ -1,5 +1,5 @@ /*
-Copyright (C) 2012-24 Miranda NG team (https://miranda-ng.org)
+Copyright (C) 2012-25 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
diff --git a/protocols/Telegram/src/stdafx.h b/protocols/Telegram/src/stdafx.h index ba59150fbb..2db1d8d4b4 100644 --- a/protocols/Telegram/src/stdafx.h +++ b/protocols/Telegram/src/stdafx.h @@ -34,6 +34,7 @@ #include <m_skin.h>
#include <m_smileyadd.h>
#include <m_timezones.h>
+#include <m_userinfo.h>
#include "../../libs/freeimage/src/FreeImage.h"
diff --git a/protocols/Telegram/src/userinfo.cpp b/protocols/Telegram/src/userinfo.cpp new file mode 100644 index 0000000000..30b3af0050 --- /dev/null +++ b/protocols/Telegram/src/userinfo.cpp @@ -0,0 +1,151 @@ +/* +Copyright (C) 2012-25 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" + +///////////////////////////////////////////////////////////////////////////////////////// +// Dialog for my own profile in Telegram + +class CMyProfileDlg : public CUserInfoPageDlg +{ + CTelegramProto *m_proto; + CCtrlEdit edtNotes; + +public: + CMyProfileDlg(CTelegramProto *ppro) : + CUserInfoPageDlg(g_plugin, IDD_MYPROFILE), + m_proto(ppro), + edtNotes(this, IDC_BIO) + {} + + bool OnRefresh() override + { + HWND _hwndDate = GetDlgItem(m_hwnd, IDC_BIRTHDAY); + SYSTEMTIME st = {}; + st.wDay = m_proto->getWord(m_hContact, "BirthDay"); + st.wMonth = m_proto->getWord(m_hContact, "BirthMonth"); + st.wYear = m_proto->getWord(m_hContact, "BirthYear"); + + if (st.wDay && st.wMonth && st.wYear) { + DateTime_SetSystemtime(_hwndDate, GDT_VALID, &st); + DateTime_SetFormat(_hwndDate, NULL); + } + else DateTime_SetFormat(_hwndDate, TranslateT("Unspecified")); + + edtNotes.SetText(m_proto->getMStringW(m_hContact, "About")); + return true; + } + + bool OnInitDialog() override + { + m_proto->WindowSubscribe(m_hwnd); + + m_proto->GetInfo(0, 0); + return true; + } + + int Resizer(UTILRESIZECONTROL *urc) override + { + switch (urc->wId) { + case IDC_BIO: + return RD_ANCHORX_WIDTH | RD_ANCHORY_HEIGHT; + } + return RD_ANCHORX_LEFT | RD_ANCHORY_TOP; + } + + void OnDestroy() override + { + m_proto->WindowUnsubscribe(m_hwnd); + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// Channel info dialog + +class CChannelInfoDlg : public CUserInfoPageDlg +{ + CMStringA m_szLink; + CTelegramProto *m_proto; + + CCtrlEdit edtUserCount; + CCtrlHyperlink m_link; + +public: + CChannelInfoDlg(CTelegramProto *ppro) : + CUserInfoPageDlg(g_plugin, IDD_CHANNEL_INFO), + m_proto(ppro), + m_link(this, IDC_LINK), + edtUserCount(this, IDC_USER_COUNT) + {} + + bool OnInitDialog() override + { + m_proto->WindowSubscribe(m_hwnd); + return true; + } + + int Resizer(UTILRESIZECONTROL *urc) override + { + switch (urc->wId) { + case IDC_LINK: + return RD_ANCHORX_WIDTH | RD_ANCHORY_TOP; + } + return RD_ANCHORX_RIGHT | RD_ANCHORY_TOP; + } + + void OnDestroy() override + { + m_proto->WindowUnsubscribe(m_hwnd); + } + + bool OnRefresh() override + { + edtUserCount.SetInt(m_proto->getDword(m_hContact, "MemberCount")); + + m_szLink = m_proto->getMStringA(m_hContact, "Link"); + m_link.SetUrl(m_szLink); + m_link.SetTextA(m_szLink); + return true; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// module entry point + +int CTelegramProto::OnUserInfoInit(WPARAM wParam, LPARAM hContact) +{ + USERINFOPAGE uip = {}; + uip.flags = ODPF_UNICODE | ODPF_ICON; + uip.szProto = m_szModuleName; + uip.szTitle.w = m_tszUserName; + uip.dwInitParam = (INT_PTR)Skin_GetProtoIcon(m_szModuleName, ID_STATUS_ONLINE); + + if (hContact != 0) { + // we display this tab only for our contacts + char *szProto = Proto_GetBaseAccountName(hContact); + if (!szProto || mir_strcmp(szProto, m_szModuleName)) + return 0; + + auto *pUser = FindUser(GetId(hContact)); + if (pUser && pUser->isChannel) + uip.pDialog = new CChannelInfoDlg(this); + else + return 0; + } + else uip.pDialog = new CMyProfileDlg(this); + return g_plugin.addUserInfo(wParam, &uip); +} diff --git a/protocols/Telegram/src/utils.cpp b/protocols/Telegram/src/utils.cpp index 4d06f7b807..7589abd500 100644 --- a/protocols/Telegram/src/utils.cpp +++ b/protocols/Telegram/src/utils.cpp @@ -1,5 +1,5 @@ /*
-Copyright (C) 2012-24 Miranda NG team (https://miranda-ng.org)
+Copyright (C) 2012-25 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
@@ -22,7 +22,7 @@ enum class BBCODE BOLD, ITALIC, STRIKE, UNDERLINE, URL, CODE, QUOTE
};
-struct
+struct Bbcode
{
BBCODE type;
const wchar_t *begin, *end;
@@ -75,6 +75,13 @@ TD::object_ptr<TD::formattedText> formatBbcodes(const char *pszText) case BBCODE::UNDERLINE: pNew = TD::make_object<TD::textEntityTypeUnderline>(); break;
}
+ for (auto &jt : res->entities_) {
+ if (i1 >= jt->offset_ && i1 < jt->offset_ + jt->length_)
+ jt->length_ -= it.len1;
+ if (i2 >= jt->offset_ && i2 < jt->offset_ + jt->length_)
+ jt->length_ -= it.len2;
+ }
+
res->entities_.push_back(TD::make_object<TD::textEntity>(TD::int32(i1), TD::int32(i2 - i1), std::move(pNew)));
}
}
@@ -87,7 +94,12 @@ TD::object_ptr<TD::formattedText> formatBbcodes(const char *pszText) CMStringA CTelegramProto::GetFormattedText(TD::object_ptr<TD::formattedText> &pText)
{
CMStringW ret(Utf2T(pText->text_.c_str()));
- unsigned offset = 0;
+
+ struct HistItem {
+ HistItem(int _1, int _2, const Bbcode &_3) : start(_1), length(_2), l1(_3.len1), l2(_3.len2) {}
+ int start, length, l1, l2;
+ };
+ std::vector<HistItem> history;
for (auto &it : pText->entities_) {
int iCode;
@@ -103,10 +115,30 @@ CMStringA CTelegramProto::GetFormattedText(TD::object_ptr<TD::formattedText> &pT continue;
}
+ int off1 = 0, off2 = 0;
+ for (auto &h : history) {
+ if (it->offset_ >= h.start)
+ off1 += h.l1;
+ if (it->offset_ + it->length_ > h.start)
+ off2 += h.l1;
+ if (it->offset_ >= h.start + h.length)
+ off1 += h.l2;
+ if (it->offset_ + it->length_ > h.start + h.length)
+ off2 += h.l2;
+ }
+
auto &bb = bbCodes[iCode];
- ret.Insert(offset + it->offset_ + it->length_, bb.end);
- ret.Insert(offset + it->offset_, bb.begin);
- offset += bb.len1 + bb.len2;
+ HistItem histItem(it->offset_, it->length_, bb);
+ ret.Insert(off2 + it->offset_ + it->length_, bb.end);
+ ret.Insert(off1 + it->offset_, bb.begin);
+ if (iCode == 4) {
+ auto *pUrl = (TD::textEntityTypeTextUrl *)it->type_.get();
+ Utf2T wszUrl(pUrl->url_.c_str());
+ ret.Insert(off1 + it->offset_ + 4, wszUrl);
+ ret.Insert(off1 + it->offset_ + 4, L"=");
+ histItem.l1 += 1 + (int)mir_wstrlen(wszUrl);
+ }
+ history.push_back(histItem);
}
return T2Utf(ret).get();
}
@@ -120,7 +152,11 @@ CMStringA msg2id(TD::int53 chatId, TD::int53 msgId) CMStringA msg2id(const TD::message *pMsg)
{
- return CMStringA(FORMAT, "%lld_%lld", pMsg->chat_id_, pMsg->id_);
+ auto iChatId = pMsg->chat_id_;
+ if (!iChatId && pMsg->sender_id_->get_id() == TD::messageSenderChat::ID)
+ iChatId = ((TD::messageSenderChat *)pMsg->sender_id_.get())->chat_id_;
+
+ return CMStringA(FORMAT, "%lld_%lld", iChatId, pMsg->id_);
}
TD::int53 dbei2id(const DBEVENTINFO &dbei)
@@ -147,19 +183,29 @@ TD::object_ptr<TD::inputFileLocal> makeFile(const wchar_t *pwszFilename) TG_FILE_REQUEST::Type AutoDetectType(const wchar_t *pwszFilename)
{
- if (ProtoGetAvatarFileFormat(pwszFilename) != PA_FORMAT_UNKNOWN)
- return TG_FILE_REQUEST::PICTURE;
+ if (int iFormat = ProtoGetAvatarFileFormat(pwszFilename)) {
+ if (iFormat != PA_FORMAT_GIF)
+ return TG_FILE_REQUEST::PICTURE;
+
+ if (auto *pBitmap = FreeImage_OpenMultiBitmapU(FIF_GIF, pwszFilename, FALSE, TRUE)) {
+ int iPages = FreeImage_GetPageCount(pBitmap);
+ FreeImage_CloseMultiBitmap(pBitmap);
+ if (iPages <= 1)
+ return TG_FILE_REQUEST::PICTURE;
+ }
+ }
CMStringW path(pwszFilename);
int idx = path.ReverseFind('.');
if (idx == -1 || path.Find('\\', idx) != -1)
return TG_FILE_REQUEST::FILE;
- auto wszExt = path.Right(path.GetLength() - idx);
+ auto wszExt = path.Right(path.GetLength() - idx - 1);
wszExt.MakeLower();
- if (wszExt == L"mp4" || wszExt == L"webm")
+ if (wszExt == L"mp4" || wszExt == L"webm" || wszExt == L"gif")
return TG_FILE_REQUEST::VIDEO;
- else if (wszExt == L"mp3" || wszExt == "ogg" || wszExt == "oga" || wszExt == "wav")
+
+ if (wszExt == L"mp3" || wszExt == "ogg" || wszExt == "oga" || wszExt == "wav")
return TG_FILE_REQUEST::VOICE;
return TG_FILE_REQUEST::FILE;
@@ -216,11 +262,10 @@ void CTelegramProto::MarkRead(MCONTACT hContact, const CMStringA &szMaxId, bool if (dbei.szId > szMaxId)
break;
- bool isSent = (dbei.flags & DBEF_SENT) != 0;
- if (isSent != bSent)
+ if (dbei.bSent != bSent)
continue;
- if (!dbei.markedRead())
+ if (!dbei.bRead)
db_event_markRead(hContact, hEvent, true);
}
}
@@ -232,8 +277,12 @@ int CTelegramProto::GetDefaultMute(const TG_USER *pUser) return m_iDefaultMutePrivate;
}
-MCONTACT CTelegramProto::GetRealContact(const TG_USER *pUser)
+MCONTACT CTelegramProto::GetRealContact(const TG_USER *pUser, int64_t threadId)
{
+ if (threadId)
+ if (auto *pu = FindChat(pUser->chatId, threadId))
+ return pu->hContact;
+
return (pUser->hContact != 0) ? pUser->hContact : m_iSavedMessages;
}
@@ -252,6 +301,21 @@ TG_USER* CTelegramProto::GetSender(const TD::MessageSender *pSender) /////////////////////////////////////////////////////////////////////////////////////////
+void CTelegramProto::CheckCompatibility()
+{
+ int iLevel = db_get_b(0, "Compatibility", m_szModuleName);
+
+ if (iLevel < 1) {
+ for (auto &cc : AccContacts())
+ delSetting(cc, "Notes");
+ delSetting("Notes");
+ }
+
+ db_set_b(0, "Compatibility", m_szModuleName, 1);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
bool CTelegramProto::CheckSearchUser(TG_USER *pUser)
{
auto pSearchId = std::find(m_searchIds.begin(), m_searchIds.end(), pUser->chatId);
@@ -317,6 +381,12 @@ void CTelegramProto::UpdateString(MCONTACT hContact, const char *pszSetting, con setUString(hContact, pszSetting, str.c_str());
}
+TG_SUPER_GROUP* CTelegramProto::FindSuperGroup(int64_t id)
+{
+ TG_SUPER_GROUP tmp(id, 0);
+ return m_arSuperGroups.find(&tmp);
+}
+
/////////////////////////////////////////////////////////////////////////////////////////
// Users
@@ -324,6 +394,15 @@ TG_USER* CTelegramProto::FindChat(int64_t id) {
auto *tmp = (TG_USER *)_alloca(sizeof(TG_USER));
tmp->chatId = id;
+ tmp->forumId = -1;
+ return m_arChats.find(tmp);
+}
+
+TG_USER* CTelegramProto::FindChat(int64_t id, int64_t forumId)
+{
+ auto *tmp = (TG_USER *)_alloca(sizeof(TG_USER));
+ tmp->chatId = id;
+ tmp->forumId = forumId;
return m_arChats.find(tmp);
}
@@ -366,6 +445,8 @@ TG_USER* CTelegramProto::AddUser(int64_t id, bool bIsChat) }
else {
pUser->hContact = hContact;
+ if (pUser->wszNick[0] == '@')
+ pUser->wszNick.Delete(0, 1);
setWString(hContact, "Nick", pUser->wszNick);
if (!pUser->isGroupChat) {
setWString(hContact, "FirstName", pUser->wszFirstName);
@@ -452,7 +533,7 @@ bool CTelegramProto::GetMessageFile(const EmbeddedFile &F, TG_FILE_REQUEST::Type pRequest->m_fileName = Utf2T(pszFileName);
pRequest->m_fileSize = pFile->size_;
pRequest->m_bRecv = !F.pMsg->is_outgoing_;
- pRequest->m_hContact = GetRealContact(F.pUser);
+ pRequest->m_hContact = GetRealContact(F.pUser, F.pMsg->message_thread_id_);
if (mir_strlen(pszCaption))
F.szBody += pszCaption;
@@ -460,14 +541,15 @@ bool CTelegramProto::GetMessageFile(const EmbeddedFile &F, TG_FILE_REQUEST::Type char szReplyId[100];
DB::EventInfo dbei(db_event_getById(m_szModuleName, F.pszId));
- dbei.flags = DBEF_TEMPORARY;
- dbei.timestamp = F.pMsg->date_;
+ dbei.bTemporary = true;
dbei.szId = F.pszId;
dbei.szUserId = F.pszUser;
+ if (F.pMsg->date_)
+ dbei.iTimestamp = F.pMsg->date_;
if (F.pMsg->is_outgoing_)
- dbei.flags |= DBEF_SENT;
+ dbei.bSent = dbei.bRead = true;
if (!F.pUser->bInited || F.bRead)
- dbei.flags |= DBEF_READ;
+ dbei.bRead = true;
if (auto iReplyId = getReplyId(F.pMsg->reply_to_.get())) {
_i64toa(iReplyId, szReplyId, 10);
dbei.szReplyId = szReplyId;
@@ -476,6 +558,7 @@ bool CTelegramProto::GetMessageFile(const EmbeddedFile &F, TG_FILE_REQUEST::Type if (dbei) {
if (!Ignore_IsIgnored(pRequest->m_hContact, IGNOREEVENT_FILE)) {
DB::FILE_BLOB blob(dbei);
+ blob.setDescr(Utf2T(pszCaption));
OnReceiveOfflineFile(dbei, blob);
blob.write(dbei);
db_event_edit(dbei.getEvent(), &dbei, true);
@@ -587,8 +670,10 @@ CMStringA CTelegramProto::GetMessageText(TG_USER *pUser, const TD::message *pMsg wszNick = Utf2T(p->sender_name_.c_str());
break;
case TD::messageOriginChannel::ID:
- if (auto *p = FindChat(((TD::messageOriginChannel *)pForward->origin_.get())->chat_id_))
- wszNick = p->getDisplayName();
+ if (auto *p = FindChat(((TD::messageOriginChannel *)pForward->origin_.get())->chat_id_)) {
+ auto str = p->getDisplayName();
+ wszNick.Format(L"[url=https://t.me/%s]%s[/url]", str.c_str(), str.c_str());
+ }
break;
default:
wszNick = TranslateT("Unknown");
diff --git a/protocols/Telegram/src/version.h b/protocols/Telegram/src/version.h index ea7e3f3bab..b26ac7e7fb 100644 --- a/protocols/Telegram/src/version.h +++ b/protocols/Telegram/src/version.h @@ -10,4 +10,4 @@ #define __DESCRIPTION "Telegram protocol support for Miranda NG."
#define __AUTHOR "Miranda NG team"
#define __AUTHORWEB "https://miranda-ng.org/p/Telegram"
-#define __COPYRIGHT "© 2018-24 Miranda NG team"
+#define __COPYRIGHT "© 2018-25 Miranda NG team"
|