diff --git a/account-data.cpp b/account-data.cpp index 58c7b0a..318ac20 100644 --- a/account-data.cpp +++ b/account-data.cpp @@ -878,10 +878,27 @@ void TdAccountData::removeActiveCall() void TdAccountData::addPendingReadReceipt(ChatId chatId, MessageId messageId) { - m_pendingReadReceipts.push_back(ReadReceipt{chatId, messageId}); + auto pChatReceipts = std::find_if(m_pendingReadReceipts.begin(), m_pendingReadReceipts.end(), + [chatId](const std::vector &receipts) { + return (!receipts.empty() && (receipts[0].chatId == chatId)); + }); + if (pChatReceipts != m_pendingReadReceipts.end()) + pChatReceipts->push_back(ReadReceipt{chatId, messageId}); + else { + m_pendingReadReceipts.emplace_back(); + m_pendingReadReceipts.back().push_back(ReadReceipt{chatId, messageId}); + } } -void TdAccountData::extractPendingReadReceipts(std::vector& receipts) +void TdAccountData::extractPendingReadReceipts(ChatId chatId, std::vector& receipts) { - receipts = std::move(m_pendingReadReceipts); + auto pChatReceipts = std::find_if(m_pendingReadReceipts.begin(), m_pendingReadReceipts.end(), + [chatId](const std::vector &receipts) { + return (!receipts.empty() && (receipts[0].chatId == chatId)); + }); + if (pChatReceipts != m_pendingReadReceipts.end()) { + receipts = std::move(*pChatReceipts); + m_pendingReadReceipts.erase(pChatReceipts); + } else + receipts.clear(); } diff --git a/account-data.h b/account-data.h index c1960ae..63b9cb1 100644 --- a/account-data.h +++ b/account-data.h @@ -3,6 +3,7 @@ #include "buildopt.h" #include "identifiers.h" +#include "transceiver.h" #include #include @@ -286,8 +287,10 @@ public: unsigned maxMessageLength = 0; } options; - PurpleAccount *const purpleAccount; - TdAccountData(PurpleAccount *purpleAccount) : purpleAccount(purpleAccount) {} + PurpleAccount *const purpleAccount; + TdTransceiver &transceiver; + TdAccountData(PurpleAccount *purpleAccount, TdTransceiver &transceiver) + : purpleAccount(purpleAccount), transceiver(transceiver) {} void updateUser(TdUserPtr user); void setUserStatus(UserId UserId, td::td_api::object_ptr status); @@ -388,7 +391,7 @@ public: PendingMessageQueue pendingMessages; void addPendingReadReceipt(ChatId chatId, MessageId messageId); - void extractPendingReadReceipts(std::vector &receipts); + void extractPendingReadReceipts(ChatId chatId, std::vector &receipts); private: TdAccountData(const TdAccountData &other) = delete; TdAccountData &operator=(const TdAccountData &other) = delete; @@ -463,8 +466,8 @@ private: std::unique_ptr getPendingRequestImpl(uint64_t requestId); PendingRequest * findPendingRequestImpl(uint64_t requestId); - // Read receipts not sent immediately due to away status - std::vector m_pendingReadReceipts; + // Read receipts not sent immediately due to away status (grouped per chat) + std::vector> m_pendingReadReceipts; }; #endif diff --git a/call.h b/call.h index df40d57..9126283 100644 --- a/call.h +++ b/call.h @@ -1,7 +1,6 @@ #ifndef _CALL_H #define _CALL_H -#include "transceiver.h" #include "account-data.h" bool initiateCall(int32_t userId, TdAccountData &account, TdTransceiver &transceiver); diff --git a/client-utils.h b/client-utils.h index d8598b0..62d0884 100644 --- a/client-utils.h +++ b/client-utils.h @@ -2,7 +2,6 @@ #define _CLIENT_UTILS_H #include "account-data.h" -#include "transceiver.h" #include #include diff --git a/file-transfer.h b/file-transfer.h index 2235745..93321d6 100644 --- a/file-transfer.h +++ b/file-transfer.h @@ -2,7 +2,6 @@ #define _FILE_TRANSFER_H #include "account-data.h" -#include "transceiver.h" enum { FILE_DOWNLOAD_PRIORITY = 1, diff --git a/receiving.cpp b/receiving.cpp index 5c43f8e..0d41cb1 100644 --- a/receiving.cpp +++ b/receiving.cpp @@ -42,6 +42,39 @@ void sendConversationReadReceipts(TdAccountData &account, PurpleConversation *co { if (!conversationHasFocus(conv)) return; + ChatId chatId; + PurpleConversationType convType = purple_conversation_get_type(conv); + const char *convName = purple_conversation_get_name(conv); + + if (convType == PURPLE_CONV_TYPE_IM) { + UserId privateChatUserId = purpleBuddyNameToUserId(convName); + SecretChatId secretChatId = purpleBuddyNameToSecretChatId(convName); + const td::td_api::chat *tdlibChat = nullptr; + + if (privateChatUserId.valid()) + tdlibChat = account.getPrivateChatByUserId(privateChatUserId); + else if (secretChatId.valid()) + tdlibChat = account.getChatBySecretChat(secretChatId); + + if (tdlibChat) + chatId = getId(*tdlibChat); + } else if (convType == PURPLE_CONV_TYPE_CHAT) + chatId = getTdlibChatId(convName); + + std::vector receipts; + account.extractPendingReadReceipts(chatId, receipts); + + if (!receipts.empty()) { + purple_debug_misc(config::pluginId, "Sending %zu read receipts for chat %" G_GINT64_FORMAT "\n", + receipts.size(), chatId.value()); + td::td_api::object_ptr viewMessagesReq = td::td_api::make_object(); + viewMessagesReq->chat_id_ = chatId.value(); + viewMessagesReq->force_read_ = true; // no idea what "closed chats" are at this point + viewMessagesReq->message_ids_.resize(receipts.size()); + for (size_t i = 0; i < receipts.size(); i++) + viewMessagesReq->message_ids_[i] = receipts[i].messageId.value(); + account.transceiver.sendQuery(std::move(viewMessagesReq), nullptr); + } } void showMessageTextIm(TdAccountData &account, const char *purpleUserName, const char *text, diff --git a/receiving.h b/receiving.h index 043c5dd..3778e38 100644 --- a/receiving.h +++ b/receiving.h @@ -2,7 +2,6 @@ #define _RECEIVING_H #include "account-data.h" -#include "transceiver.h" #include std::string makeNoticeWithSender(const td::td_api::chat &chat, const TgMessageInfo &message, diff --git a/secret-chat.h b/secret-chat.h index e932ebd..cd2d697 100644 --- a/secret-chat.h +++ b/secret-chat.h @@ -2,7 +2,6 @@ #define _SECRET_CHAT_H #include "account-data.h" -#include "transceiver.h" #include "format.h" void updateSecretChat(td::td_api::object_ptr secretChat, diff --git a/td-client.cpp b/td-client.cpp index 3e8ed13..5ebf521 100644 --- a/td-client.cpp +++ b/td-client.cpp @@ -20,7 +20,7 @@ enum { PurpleTdClient::PurpleTdClient(PurpleAccount *acct, ITransceiverBackend *testBackend) : m_transceiver(this, acct, &PurpleTdClient::processUpdate, testBackend), - m_data(acct) + m_data(acct, m_transceiver) { StickerConversionThread::setCallback(&PurpleTdClient::onAnimatedStickerConverted); m_account = acct; @@ -919,28 +919,6 @@ void PurpleTdClient::sendReadReceipts(PurpleConversation *conversation) sendConversationReadReceipts(m_data, conversation); return; } - - // temporary - std::vector receipts; - m_data.extractPendingReadReceipts(receipts); - - std::sort(receipts.begin(), receipts.end(), - [](const ReadReceipt &r1, const ReadReceipt &r2) { - return (r1.chatId.value() < r2.chatId.value()); - }); - - unsigned i = 0; - while (i < receipts.size()) { - ChatId chatId = receipts[i].chatId; - td::td_api::object_ptr viewMessagesReq = td::td_api::make_object(); - viewMessagesReq->chat_id_ = chatId.value(); - viewMessagesReq->force_read_ = true; // no idea what "closed chats" are at this point - while ((i < receipts.size()) && (receipts[i].chatId == chatId)) { - viewMessagesReq->message_ids_.push_back(receipts[i].messageId.value()); - i++; - } - m_transceiver.sendQuery(std::move(viewMessagesReq), nullptr); - } } void PurpleTdClient::onIncomingMessage(td::td_api::object_ptr message) @@ -956,10 +934,8 @@ void PurpleTdClient::onIncomingMessage(td::td_api::object_ptr #include diff --git a/tdlib-purple.cpp b/tdlib-purple.cpp index 68cbcc3..20283bf 100644 --- a/tdlib-purple.cpp +++ b/tdlib-purple.cpp @@ -276,12 +276,22 @@ void tgprpl_set_single_thread() AccountThread::setSingleThread(); } +struct PurpleConversationInfo { + std::string accountName; + std::string convName; + PurpleConversationType type; +}; + static gboolean sendConversationReadReceipts(void *arg) { - PurpleConversation *conv = static_cast(arg); - PurpleTdClient *tdClient = getTdClient(purple_conversation_get_account(conv)); + std::unique_ptr info(static_cast(arg)); + PurpleAccount *account = purple_accounts_find(info->accountName.c_str(), config::pluginId); + PurpleConversation *conv = NULL; + if (account != NULL) + conv = purple_find_conversation_with_account(info->type, info->convName.c_str(), account); - tdClient->sendReadReceipts(conv); + if (conv != NULL) + getTdClient(account)->sendReadReceipts(conv); return G_SOURCE_REMOVE; } @@ -293,7 +303,11 @@ conversation_updated_cb(PurpleConversation *conv, PurpleConvUpdateType type) if (!strcmp(purple_account_get_protocol_id(account), config::pluginId) && (type == PURPLE_CONV_UPDATE_UNSEEN)) { - g_timeout_add(500, sendConversationReadReceipts, conv); + PurpleConversationInfo *arg = new PurpleConversationInfo; + arg->accountName = purple_account_get_username(account); + arg->convName = purple_conversation_get_name(conv); + arg->type = purple_conversation_get_type(conv); + g_timeout_add(500, sendConversationReadReceipts, arg); } }