From fe8e65a6696f1a4623111125ad10019caf3141dd Mon Sep 17 00:00:00 2001 From: George Hazan Date: Fri, 2 Jun 2023 22:13:31 +0300 Subject: fixes #3392 ([Telegram] Add support for file transfers (images etc) both incoming and outgoing) --- protocols/Telegram/src/proto.cpp | 84 +++++++++++++++++++++++++++++++++++++++ protocols/Telegram/src/proto.h | 10 ++++- protocols/Telegram/src/server.cpp | 43 ++++++++++++++++++-- protocols/Telegram/src/utils.cpp | 25 ++++++++++++ protocols/Telegram/src/utils.h | 2 + 5 files changed, 158 insertions(+), 6 deletions(-) (limited to 'protocols/Telegram/src') diff --git a/protocols/Telegram/src/proto.cpp b/protocols/Telegram/src/proto.cpp index c7da8568ec..a7fe012792 100644 --- a/protocols/Telegram/src/proto.cpp +++ b/protocols/Telegram/src/proto.cpp @@ -331,6 +331,90 @@ HANDLE CTelegramProto::SearchByName(const wchar_t *nick, const wchar_t *firstNam ///////////////////////////////////////////////////////////////////////////////////////// +HANDLE CTelegramProto::SendFile(MCONTACT hContact, const wchar_t *szDescription, wchar_t **ppszFiles) +{ + auto *pUser = FindUser(GetId(hContact)); + if (pUser == nullptr) { + debugLogA("request from unknown contact %d, ignored", hContact); + return nullptr; + } + + TG_FILE_REQUEST *pTransfer = nullptr; + + for (int i = 0; ppszFiles[i] != 0; i++) { + struct _stat statbuf; + if (_wstat(ppszFiles[0], &statbuf)) { + debugLogW(L"'%s' is an invalid filename", ppszFiles[i]); + continue; + } + + pTransfer = new TG_FILE_REQUEST(TG_FILE_REQUEST::FILE, 0, ""); + pTransfer->m_fileName = ppszFiles[i]; + if (m_bCompressFiles) + pTransfer->AutoDetectType(); + + pTransfer->m_hContact = hContact; + pTransfer->m_fileSize = statbuf.st_size; + if (mir_wstrlen(szDescription)) + pTransfer->m_wszDescr = szDescription; + + // create a message with embedded file + auto *pMessage = new TD::sendMessage(); + pMessage->chat_id_ = pUser->chatId; + auto caption = TD::make_object(); + caption->text_ = T2Utf(szDescription).get(); + + if (pTransfer->m_type == TG_FILE_REQUEST::FILE) { + auto pContent = TD::make_object(); + pContent->document_= makeFile(pTransfer->m_fileName); + pContent->caption_ = std::move(caption); + pContent->thumbnail_ = 0; + pMessage->input_message_content_ = std::move(pContent); + } + else if (pTransfer->m_type == TG_FILE_REQUEST::PICTURE) { + auto pContent = TD::make_object(); + pContent->photo_ = makeFile(pTransfer->m_fileName); + pContent->thumbnail_ = 0; + pContent->caption_ = std::move(caption); + pContent->ttl_ = 0; + pContent->height_ = 0; + pContent->width_ = 0; + pMessage->input_message_content_ = std::move(pContent); + } + else if (pTransfer->m_type == TG_FILE_REQUEST::VOICE) { + auto pContent = TD::make_object(); + pContent->voice_note_ = makeFile(pTransfer->m_fileName); + pContent->caption_ = std::move(caption); + pContent->duration_ = 0; + pMessage->input_message_content_ = std::move(pContent); + } + else if (pTransfer->m_type == TG_FILE_REQUEST::VIDEO) { + auto pContent = TD::make_object(); + pContent->video_ = makeFile(pTransfer->m_fileName); + pContent->caption_ = std::move(caption); + pContent->duration_ = 0; + pContent->height_ = 0; + pContent->width_ = 0; + pContent->ttl_ = 0; + pMessage->input_message_content_ = std::move(pContent); + } + else return nullptr; + + SendQuery(pMessage, &CTelegramProto::OnSendFile, pTransfer); + } + + return pTransfer; +} + +void CTelegramProto::OnSendFile(td::ClientManager::Response &, void *pUserInfo) +{ + auto *ft = (TG_FILE_REQUEST *)pUserInfo; + ProtoBroadcastAck(ft->m_hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft); + delete ft; +} + +///////////////////////////////////////////////////////////////////////////////////////// + int CTelegramProto::SendMsg(MCONTACT hContact, int, const char *pszMessage) { ptrA szId(getStringA(hContact, DBKEY_ID)); diff --git a/protocols/Telegram/src/proto.h b/protocols/Telegram/src/proto.h index eaeb187795..e03405560a 100644 --- a/protocols/Telegram/src/proto.h +++ b/protocols/Telegram/src/proto.h @@ -70,12 +70,15 @@ struct TG_FILE_REQUEST : public MZeroedObject m_uniqueId(_3) {} + void AutoDetectType(); + Type m_type; bool m_bOpen = false; MEVENT m_hEvent = 0; + MCONTACT m_hContact = 0; TD::int53 m_fileId, m_fileSize = 0; CMStringA m_uniqueId; - CMStringW m_destPath, m_fileName; + CMStringW m_destPath, m_fileName, m_wszDescr; }; struct TG_USER : public MZeroedObject @@ -196,6 +199,7 @@ class CTelegramProto : public PROTO void OnGetFileInfo(td::ClientManager::Response &response, void *pUserInfo); void OnGetHistory(td::ClientManager::Response &response, void *pUserInfo); void OnSearchResults(td::ClientManager::Response &response); + void OnSendFile(td::ClientManager::Response &response, void *pUserInfo); void OnSendMessage(td::ClientManager::Response &response, void *pUserInfo); void OnUpdateAuth(td::ClientManager::Response &response); @@ -221,7 +225,8 @@ class CTelegramProto : public PROTO void ProcessFile(TD::updateFile *pObj); void ProcessGroups(TD::updateChatFilters *pObj); void ProcessMarkRead(TD::updateChatReadInbox *pObj); - void ProcessMessage(TD::updateNewMessage *pObj); + void ProcessMessage(const TD::message *pMsg); + void ProcessMessageContent(TD::updateMessageContent *pObj); void ProcessOption(TD::updateOption *pObj); void ProcessStatus(TD::updateUserStatus *pObj); void ProcessSuperGroup(TD::updateSupergroup *pObj); @@ -303,6 +308,7 @@ public: INT_PTR GetCaps(int type, MCONTACT hContact = NULL) override; + HANDLE SendFile(MCONTACT hContact, const wchar_t *szDescription, wchar_t **ppszFiles) override; MEVENT RecvFile(MCONTACT hContact, PROTORECVFILE *pre) override; HANDLE SearchByName(const wchar_t *nick, const wchar_t *firstName, const wchar_t *lastName) override; diff --git a/protocols/Telegram/src/server.cpp b/protocols/Telegram/src/server.cpp index 2b83443ec8..3b8ddda8ca 100644 --- a/protocols/Telegram/src/server.cpp +++ b/protocols/Telegram/src/server.cpp @@ -176,12 +176,20 @@ void CTelegramProto::ProcessResponse(td::ClientManager::Response response) ProcessFile((TD::updateFile *)response.object.get()); break; + case TD::updateMessageContent::ID: + ProcessMessageContent((TD::updateMessageContent *)response.object.get()); + break; + + case TD::updateMessageSendSucceeded::ID: + ProcessMessage(((TD::updateMessageSendSucceeded *)response.object.get())->message_.get()); + break; + case TD::updateNewChat::ID: ProcessChat((TD::updateNewChat *)response.object.get()); break; case TD::updateNewMessage::ID: - ProcessMessage((TD::updateNewMessage *)response.object.get()); + ProcessMessage(((TD::updateNewMessage *)response.object.get())->message_.get()); break; case TD::updateOption::ID: @@ -588,16 +596,18 @@ void CTelegramProto::ProcessMarkRead(TD::updateChatReadInbox *pObj) } } -void CTelegramProto::ProcessMessage(TD::updateNewMessage *pObj) +void CTelegramProto::ProcessMessage(const TD::message *pMessage) { - auto *pMessage = pObj->message_.get(); - auto *pUser = FindChat(pMessage->chat_id_); if (pUser == nullptr) { debugLogA("message from unknown chat/user, ignored"); return; } + if (pMessage->sending_state_) + if (pMessage->sending_state_->get_id() == TD::messageSendingStatePending::ID) + return; + CMStringA szText(GetMessageText(pUser, pMessage)); if (szText.IsEmpty()) { debugLogA("this message was not processed, ignored"); @@ -629,6 +639,31 @@ void CTelegramProto::ProcessMessage(TD::updateNewMessage *pObj) ProtoChainRecvMsg((pUser->hContact) ? pUser->hContact : m_iSavedMessages, &pre); } +void CTelegramProto::ProcessMessageContent(TD::updateMessageContent *pObj) +{ + auto *pUser = FindChat(pObj->chat_id_); + if (pUser == nullptr) { + debugLogA("message from unknown chat/user, ignored"); + return; + } + + char szMsgId[100]; + _i64toa(pObj->message_id_, szMsgId, 10); + + MEVENT hDbEvent = db_event_getById(m_szModuleName, szMsgId); + if (hDbEvent == 0) { + debugLogA("Unknown message with id=%lld (chat id %lld, ignored", pObj->message_id_, pObj->chat_id_); + return; + } + + /* + CMStringA szText(GetMessageText(pUser, pObj->new_content_.get())); + if (szText.IsEmpty()) { + debugLogA("this message was not processed, ignored"); + return; + }*/ +} + void CTelegramProto::ProcessOption(TD::updateOption *pObj) { TD::int53 iValue = 0; diff --git a/protocols/Telegram/src/utils.cpp b/protocols/Telegram/src/utils.cpp index 5fabcb2c61..cc8aff096e 100644 --- a/protocols/Telegram/src/utils.cpp +++ b/protocols/Telegram/src/utils.cpp @@ -22,6 +22,31 @@ const char *getName(const TD::usernames *pName) return (pName == nullptr) ? TranslateU("none") : pName->editable_username_.c_str(); } +TD::object_ptr makeFile(const CMStringW &wszFile) +{ + std::string szPath = T2Utf(wszFile); + return TD::make_object(std::move(szPath)); +} + +void TG_FILE_REQUEST::AutoDetectType() +{ + if (ProtoGetAvatarFileFormat(m_fileName) != PA_FORMAT_UNKNOWN) { + m_type = this->PICTURE; + return; + } + + int idx = m_fileName.ReverseFind('.'); + if (idx == -1 || m_fileName.Find('\\', idx) != -1) + return; + + auto wszExt = m_fileName.Right(m_fileName.GetLength() - idx); + wszExt.MakeLower(); + if (wszExt == L"mp4" || wszExt == L"webm") + m_type = this->VIDEO; + else if (wszExt == L"mp3" || wszExt == "ogg" || wszExt == "oga" || wszExt == "wav") + m_type = this->VOICE; +} + CMStringW TG_USER::getDisplayName() const { if (!wszFirstName.IsEmpty()) diff --git a/protocols/Telegram/src/utils.h b/protocols/Telegram/src/utils.h index 7f98ecbcf6..ad42a3e425 100644 --- a/protocols/Telegram/src/utils.h +++ b/protocols/Telegram/src/utils.h @@ -1,3 +1,5 @@ #pragma once const char *getName(const TD::usernames *pName); + +TD::object_ptr makeFile(const CMStringW &wszFile); -- cgit v1.2.3