/
NeoChapay
/
telegraf
Обзор
Документация
Войти
/
NeoChapay
/
telegraf
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
develop
src/tdlibreceiver.cpp
1 221 строка
50 KB
mbarashkov
Исправляем предупреждение о глобальных QString
28 дек 2024, 18:43
28 дек 2024, 18:43
9190e19
Код
Авторство
О чём код?
#include "tdlibreceiver.h" #define DEBUG_MODULE TDLibReceiver #include <QJsonArray> #include <td/telegram/td_json_client.h> #include "debuglog.h" #include "QElapsedTimer" namespace { const char ID[] = "id"; const char LIST[] = "list"; const char CHAT_ID[] = "chat_id"; const char USER_ID[] = "user_id"; const char OLD_MESSAGE_ID[] = "old_message_id"; const char MESSAGE_ID[] = "message_id"; const char MESSAGE_IDS[] = "message_ids"; const char MESSAGE[] = "message"; const char MESSAGES[] = "messages"; const char TITLE[] = "title"; const char NAME[] = "name"; const char VALUE[] = "value"; const char POSITION[] = "position"; const char POSITIONS[] = "positions"; const char PHOTO[] = "photo"; const char ORDER[] = "order"; const char IS_PINNED[] = "is_pinned"; const char BASIC_GROUP[] = "basic_group"; const char SUPERGROUP[] = "supergroup"; const char LAST_MESSAGE[] = "last_message"; const char TOTAL_COUNT[] = "total_count"; const char UNREAD_COUNT[] = "unread_count"; const char UNREAD_UNMUTED_COUNT[] = "unread_unmuted_count"; const char UNREAD_MENTION_COUNT[] = "unread_mention_count"; const char UNREAD_REACTION_COUNT[] = "unread_reaction_count"; const char AVAILABLE_REACTIONS[] = "available_reactions"; const char TEXT[] = "text"; const char LAST_READ_INBOX_MESSAGE_ID[] = "last_read_inbox_message_id"; const char LAST_READ_OUTBOX_MESSAGE_ID[] = "last_read_outbox_message_id"; const char SECRET_CHAT[] = "secret_chat"; const char INTERACTION_INFO[] = "interaction_info"; const char ANIMATED_EMOJI[] = "animated_emoji"; const char COLOR_REPLACEMENTS[] = "color_replacements"; const char STICKER[] = "sticker"; const char STICKERS[] = "stickers"; const char COVERS[] = "covers"; const char OUTLINE[] = "outline"; const char CONTENT[] = "content"; const char NEW_CONTENT[] = "new_content"; const char SETS[] = "sets"; const char EMOJIS[] = "emojis"; const char REPLY_TO[] = "reply_to"; const char REPLY_IN_CHAT_ID[] = "reply_in_chat_id"; const char REPLY_TO_MESSAGE_ID[] = "reply_to_message_id"; const char DRAFT_MESSAGE[] = "draft_message"; const char CHAT_FOLDERS[] = "chat_folders"; const char MAIN_CHAT_LIST_POSITION_IN_FOLDERS[] = "main_chat_list_position"; const char _TYPE[] = "@type"; const char _EXTRA[] = "@extra"; const char TYPE_CHAT_POSITION[] = "chatPosition"; const char TYPE_CHAT_LIST_MAIN[] = "chatListMain"; const char TYPE_CHAT_LIST_ARCHIVE[] = "chatListArchive"; const char TYPE_CHAT_LIST_FOLDER[] = "chatListFolder"; const char TYPE_STICKER_SET_INFO[] = "stickerSetInfo"; const char TYPE_STICKER_SET[] = "stickerSet"; const char TYPE_MESSAGE[] = "message"; const char TYPE_STICKER[] = "sticker"; const char TYPE_MESSAGE_STICKER[] = "messageSticker"; const char TYPE_MESSAGE_REPLY_TO_MESSAGE[] = "messageReplyToMessage"; const char TYPE_MESSAGE_ANIMATED_EMOJI[] = "messageAnimatedEmoji"; const char TYPE_ANIMATED_EMOJI[] = "animatedEmoji"; const char TYPE_INPUT_MESSAGE_REPLY_TO_MESSAGE[] = "inputMessageReplyToMessage"; const char TYPE_DRAFT_MESSAGE[] = "draftMessage"; } static QString getChatPositionOrder(const QVariantMap &position) { if (position.value(_TYPE).toString() == TYPE_CHAT_POSITION && position.value(LIST).toMap().value(_TYPE) == TYPE_CHAT_LIST_MAIN) { return position.value(ORDER).toString(); } return QString(); } static QString findChatPositionOrder(const QVariantList &positions) { const int n = positions.count(); for (int i = 0; i < n; i++) { const QString order = getChatPositionOrder(positions.at(i).toMap()); if (!order.isEmpty()) { return order; } } return QString(); } static QString parseNumberOrString(const QJsonValue &id) { return id.isString() ? id.toString() : id.toVariant().toString(); } static qlonglong parseId(const QJsonValue &id) { return id.toVariant().toLongLong(); } TDLibReceiver::TDLibReceiver(int tdLibClientId, QObject *parent) : QThread(parent) { _tdLibClientId = tdLibClientId; _active = true; _handlers.insert("updateOption", &TDLibReceiver::processUpdateOption); _handlers.insert("updateAuthorizationState", &TDLibReceiver::processUpdateAuthorizationState); _handlers.insert("updateConnectionState", &TDLibReceiver::processUpdateConnectionState); _handlers.insert("updateUser", &TDLibReceiver::processUpdateUser); _handlers.insert("updateUserStatus", &TDLibReceiver::processUpdateUserStatus); _handlers.insert("updateFile", &TDLibReceiver::processUpdateFile); _handlers.insert("file", &TDLibReceiver::processFile); _handlers.insert("updateNewChat", &TDLibReceiver::processUpdateNewChat); _handlers.insert("updateUnreadMessageCount", &TDLibReceiver::processUpdateUnreadMessageCount); _handlers.insert("updateUnreadChatCount", &TDLibReceiver::processUpdateUnreadChatCount); _handlers.insert("updateChatFolders", &TDLibReceiver::processUpdateChatFolders); _handlers.insert("updateChatAddedToList", &TDLibReceiver::processUpdateChatAddedToList); _handlers.insert("updateChatLastMessage", &TDLibReceiver::processUpdateChatLastMessage); _handlers.insert("updateChatOrder", &TDLibReceiver::processUpdateChatOrder); _handlers.insert("updateChatPosition", &TDLibReceiver::processUpdateChatPosition); _handlers.insert("updateChatReadInbox", &TDLibReceiver::processUpdateChatReadInbox); _handlers.insert("updateChatReadOutbox", &TDLibReceiver::processUpdateChatReadOutbox); _handlers.insert("updateChatAvailableReactions", &TDLibReceiver::processUpdateChatAvailableReactions); _handlers.insert("updateBasicGroup", &TDLibReceiver::processUpdateBasicGroup); _handlers.insert("updateSupergroup", &TDLibReceiver::processUpdateSuperGroup); _handlers.insert("updateChatOnlineMemberCount", &TDLibReceiver::processChatOnlineMemberCountUpdated); _handlers.insert("messages", &TDLibReceiver::processMessages); _handlers.insert("foundChatMessages", &TDLibReceiver::processFoundChatMessages); _handlers.insert("sponsoredMessage", &TDLibReceiver::processSponsoredMessage); // TdLib <= 1.8.7 _handlers.insert("sponsoredMessages", &TDLibReceiver::processSponsoredMessages); // TdLib >= 1.8.8 _handlers.insert("updateNewMessage", &TDLibReceiver::processUpdateNewMessage); _handlers.insert("message", &TDLibReceiver::processMessage); _handlers.insert("messageLinkInfo", &TDLibReceiver::processMessageLinkInfo); _handlers.insert("updateMessageSendSucceeded", &TDLibReceiver::processMessageSendSucceeded); _handlers.insert("updateActiveNotifications", &TDLibReceiver::processUpdateActiveNotifications); _handlers.insert("updateNotificationGroup", &TDLibReceiver::processUpdateNotificationGroup); _handlers.insert("updateChatNotificationSettings", &TDLibReceiver::processUpdateChatNotificationSettings); _handlers.insert("updateMessageContent", &TDLibReceiver::processUpdateMessageContent); _handlers.insert("updateDeleteMessages", &TDLibReceiver::processUpdateDeleteMessages); _handlers.insert("chats", &TDLibReceiver::processChats); _handlers.insert("chat", &TDLibReceiver::processChat); _handlers.insert("updateRecentStickers", &TDLibReceiver::processUpdateRecentStickers); _handlers.insert("stickers", &TDLibReceiver::processStickers); _handlers.insert("updateInstalledStickerSets", &TDLibReceiver::processUpdateInstalledStickerSets); _handlers.insert("stickerSets", &TDLibReceiver::processStickerSets); _handlers.insert("stickerSet", &TDLibReceiver::processStickerSet); _handlers.insert("chatMembers", &TDLibReceiver::processChatMembers); _handlers.insert("chatFolder", &TDLibReceiver::processChatFolder); _handlers.insert("userFullInfo", &TDLibReceiver::processUserFullInfo); _handlers.insert("updateUserFullInfo", &TDLibReceiver::processUpdateUserFullInfo); _handlers.insert("basicGroupFullInfo", &TDLibReceiver::processBasicGroupFullInfo); _handlers.insert("updateBasicGroupFullInfo", &TDLibReceiver::processUpdateBasicGroupFullInfo); _handlers.insert("supergroupFullInfo", &TDLibReceiver::processSupergroupFullInfo); _handlers.insert("updateSupergroupFullInfo", &TDLibReceiver::processUpdateSupergroupFullInfo); _handlers.insert("chatPhotos", &TDLibReceiver::processUserProfilePhotos); _handlers.insert("updateChatPermissions", &TDLibReceiver::processUpdateChatPermissions); _handlers.insert("updateChatPhoto", &TDLibReceiver::processUpdateChatPhoto); _handlers.insert("updateChatTitle", &TDLibReceiver::processUpdateChatTitle); _handlers.insert("updateChatPinnedMessage", &TDLibReceiver::processUpdateChatPinnedMessage); _handlers.insert("updateMessageIsPinned", &TDLibReceiver::processUpdateMessageIsPinned); _handlers.insert("users", &TDLibReceiver::processUsers); _handlers.insert("messageSenders", &TDLibReceiver::processMessageSenders); _handlers.insert("error", &TDLibReceiver::processError); _handlers.insert("ok", &TDLibReceiver::ok); _handlers.insert("secretChat", &TDLibReceiver::processSecretChat); _handlers.insert("updateSecretChat", &TDLibReceiver::processUpdateSecretChat); _handlers.insert("importedContacts", &TDLibReceiver::processImportedContacts); _handlers.insert("updateMessageEdited", &TDLibReceiver::processUpdateMessageEdited); _handlers.insert("updateChatIsMarkedAsUnread", &TDLibReceiver::processUpdateChatIsMarkedAsUnread); _handlers.insert("updateChatDraftMessage", &TDLibReceiver::processUpdateChatDraftMessage); _handlers.insert("inlineQueryResults", &TDLibReceiver::processInlineQueryResults); _handlers.insert("callbackQueryAnswer", &TDLibReceiver::processCallbackQueryAnswer); _handlers.insert("userPrivacySettingRules", &TDLibReceiver::processUserPrivacySettingRules); _handlers.insert("updateUserPrivacySettingRules", &TDLibReceiver::processUpdateUserPrivacySettingRules); _handlers.insert("updateMessageInteractionInfo", &TDLibReceiver::processUpdateMessageInteractionInfo); _handlers.insert("sessions", &TDLibReceiver::processSessions); _handlers.insert("availableReactions", &TDLibReceiver::processAvailableReactions); _handlers.insert("updateMessageMentionRead", &TDLibReceiver::processUpdateChatUnreadMentionCount); _handlers.insert("updateChatUnreadMentionCount", &TDLibReceiver::processUpdateChatUnreadMentionCount); _handlers.insert("updateChatUnreadReactionCount", &TDLibReceiver::processUpdateChatUnreadReactionCount); _handlers.insert("updateActiveEmojiReactions", &TDLibReceiver::processUpdateActiveEmojiReactions); } void TDLibReceiver::setActive(bool active) { if (active) { LOG("Activating receiver loop..."); } else { LOG("Deactivating receiver loop, this may take a while..."); } // _powerSavingMode = false; _active = active; } /*! * \brief Основной цикл приложения, в котором происходит получение обновлений от tdlib. Выполняется в отдельном потоке. */ void TDLibReceiver::receiverLoop() { LOG("Starting receiver loop"); const double WAIT_TIMEOUT = 5.0; while (_active) { const char *result = td_receive(WAIT_TIMEOUT); if (result) { const char typeToken[] = "\"@type\":"; auto typePosition = strstr(result, typeToken); Handler handler = nullptr; if(typePosition != nullptr) { auto nextTokenStart = typePosition + strlen(typeToken); auto nextQuote = strstr(nextTokenStart + 1, "\""); auto tokenLength = nextQuote - nextTokenStart - 1; char* typeToken = new char[tokenLength + 1]; strncpy(typeToken, nextTokenStart + 1, tokenLength); typeToken[tokenLength] = 0; handler = _handlers.value(typeToken); delete[] typeToken; } if(handler) { QJsonObject object = QJsonDocument::fromJson(QByteArray(result)).object(); (this->*handler)(object); } } //if (_powerSavingMode) // msleep(POWERSAVING_TDLIB_REQUEST_INTERVAL); } LOG("Stopping receiver loop"); } void TDLibReceiver::processUpdateOption(const QJsonObject &receivedInformation) { const QString currentOption = receivedInformation.value(NAME).toString(); const QJsonValue value = receivedInformation.value(VALUE).toObject().value(VALUE); if (currentOption == "version") { QString detectedVersion = value.toString(); LOG("TD Lib version detected: " << detectedVersion); emit versionDetected(detectedVersion); } else { LOG("Option updated: " << currentOption << value); emit optionUpdated(currentOption, value.toVariant()); } } void TDLibReceiver::processUpdateAuthorizationState(const QJsonObject &receivedInformation) { const QString authorizationState = receivedInformation.value("authorization_state").toObject().value(_TYPE).toString(); LOG("Authorization state changed: " << authorizationState); emit authorizationStateChanged(authorizationState, receivedInformation.toVariantMap()); } void TDLibReceiver::processUpdateConnectionState(const QJsonObject &receivedInformation) { const QString connectionState = receivedInformation.value("state").toObject().value(_TYPE).toString(); LOG("Connection state changed: " << connectionState); emit connectionStateChanged(connectionState); } void TDLibReceiver::processUpdateUser(const QJsonObject &receivedInformation) { const QVariantMap userInformation = receivedInformation.value("user").toObject().toVariantMap(); VERBOSE("User was updated: " << userInformation.value("username").toString() << userInformation.value("first_name").toString() << userInformation.value("last_name").toString()); emit userUpdated(userInformation); } void TDLibReceiver::processUpdateUserStatus(const QJsonObject &receivedInformation) { const qlonglong userId = parseId(receivedInformation.value(USER_ID)); const QJsonObject userStatusInformation = receivedInformation.value("status").toObject(); VERBOSE("User status was updated: " << userId << userStatusInformation.value(_TYPE).toString()); emit userStatusUpdated(userId, userStatusInformation.toVariantMap()); } void TDLibReceiver::processUpdateFile(const QJsonObject &receivedInformation) { const QJsonObject fileInformation = receivedInformation.value("file").toObject(); LOG("File was updated: " << parseNumberOrString(fileInformation.value(ID))); emit fileUpdated(fileInformation.toVariantMap()); } void TDLibReceiver::processFile(const QJsonObject &receivedInformation) { LOG("File was updated: " << parseNumberOrString(receivedInformation.value(ID))); emit fileUpdated(receivedInformation.toVariantMap()); } void TDLibReceiver::processUpdateNewChat(const QJsonObject &receivedInformation) { const QJsonObject chatInformation = receivedInformation.value("chat").toObject(); LOG("New chat discovered: " << parseNumberOrString(chatInformation.value(ID)) << chatInformation.value(TITLE).toString()); emit newChatDiscovered(chatInformation.toVariantMap()); } void TDLibReceiver::processUpdateUnreadMessageCount(const QJsonObject &receivedInformation) { QVariantMap messageCountInformation; messageCountInformation.insert("chat_list_type", receivedInformation.value("chat_list").toObject().value(_TYPE).toVariant()); messageCountInformation.insert(UNREAD_COUNT, receivedInformation.value(UNREAD_COUNT).toVariant()); messageCountInformation.insert(UNREAD_UNMUTED_COUNT, receivedInformation.value(UNREAD_UNMUTED_COUNT).toVariant()); // LOG("Unread UNMUTED message count updated: " << messageCountInformation.value("chat_list_type").toString() << messageCountInformation.value(UNREAD_UNMUTED_COUNT).toString()); // qDebug() <<" Unread message count updated: " << messageCountInformation.value("chat_list_type").toString() << messageCountInformation.value(UNREAD_COUNT).toString(); emit unreadMessageCountUpdated(messageCountInformation); } void TDLibReceiver::processUpdateUnreadChatCount(const QJsonObject &receivedInformation) { QVariantMap chatCountInformation; chatCountInformation.insert("chat_list_type", receivedInformation.value("chat_list").toObject().value(_TYPE).toVariant()); if(chatCountInformation["chat_list_type"].toString() == TYPE_CHAT_LIST_FOLDER) { chatCountInformation.insert("chat_folder_id", receivedInformation.value("chat_list").toObject().value("chat_folder_id").toVariant()); } else { chatCountInformation.insert("chat_folder_id", QVariant("-1")); } chatCountInformation.insert("marked_as_unread_count", receivedInformation.value("marked_as_unread_count").toVariant()); chatCountInformation.insert("marked_as_unread_unmuted_count", receivedInformation.value("marked_as_unread_unmuted_count").toVariant()); chatCountInformation.insert(TOTAL_COUNT, receivedInformation.value(TOTAL_COUNT).toVariant()); chatCountInformation.insert(UNREAD_COUNT, receivedInformation.value(UNREAD_COUNT).toVariant()); chatCountInformation.insert(UNREAD_UNMUTED_COUNT, receivedInformation.value(UNREAD_UNMUTED_COUNT).toVariant()); // LOG("Unread chat count updated: " << chatCountInformation.value("chat_list_type").toString() // << chatCountInformation.value(UNREAD_COUNT).toString()); // qDebug() << "Unread chat count updated: " // << chatCountInformation.value("chat_list_type").toString() // << " chat_folder_id: " // << chatCountInformation.value("chat_folder_id").toString() // << " count: " // << chatCountInformation.value(UNREAD_COUNT).toString(); emit unreadChatCountUpdated(chatCountInformation); } void TDLibReceiver::processUpdateChatFolders(const QJsonObject &receivedInformation) { const qlonglong mainChatPosition = receivedInformation.value(MAIN_CHAT_LIST_POSITION_IN_FOLDERS).toVariant().toLongLong(); const QVariantList folders = receivedInformation.value(CHAT_FOLDERS).toArray().toVariantList(); LOG("Received folder:" << folders.size() << ", main chat list position: " << mainChatPosition); emit updateChatFolders(folders, mainChatPosition); } void TDLibReceiver::processUpdateChatAddedToList(const QJsonObject &receivedInformation) { QString chatType; qlonglong chatID; chatType = receivedInformation.value("chat_list").toObject().value(_TYPE).toVariant().toString(); if(chatType.contains(TYPE_CHAT_LIST_ARCHIVE)) { chatID = parseNumberOrString(receivedInformation.value(CHAT_ID)).toLongLong(); emit updateChatInArchive(chatID); } } void TDLibReceiver::processChatFolder(const QJsonObject &chatFolderInformation) { LOG("Received chatFolder information"); emit gotChatFolder(chatFolderInformation.toVariantMap()); } void TDLibReceiver::processUpdateChatLastMessage(const QJsonObject &receivedInformation) { const QString chatId = parseNumberOrString(receivedInformation.value(CHAT_ID)); const QString order = receivedInformation.contains(POSITIONS) ? findChatPositionOrder(receivedInformation.value(POSITIONS).toArray().toVariantList()) : parseNumberOrString(receivedInformation.value(ORDER)); const QJsonObject lastMessage = receivedInformation.value(LAST_MESSAGE).toObject(); // LOG("Last message of chat" << chatId << "updated, order" << order << "type" << lastMessage.value(_TYPE).toString()); emit chatLastMessageUpdated(chatId, order, cleanupMap(lastMessage).toVariantMap()); } void TDLibReceiver::processUpdateChatOrder(const QJsonObject &receivedInformation) { const QString chatId = parseNumberOrString(receivedInformation.value(CHAT_ID)); const QString order = parseNumberOrString(receivedInformation.value(ORDER)); const QString chatListType(receivedInformation.value(POSITION).toObject().toVariantMap().value(LIST).toMap().value(_TYPE).toString()); // LOG("Chat order updated for ID" << chat_id << "to" << order); emit chatOrderUpdated(chatId, order, chatListType); } void TDLibReceiver::processUpdateChatPosition(const QJsonObject &receivedInformation) { const QJsonObject positionObject = receivedInformation.value(POSITION).toObject(); const QString updateForChatList = positionObject.value(LIST).toObject().value(_TYPE).toString(); // We are only processing main chat list updates at the moment... if ((updateForChatList == "chatListMain") || (updateForChatList == "chatListArchive")) { const QString chatId = parseNumberOrString(receivedInformation.value(CHAT_ID)); const QString order = parseNumberOrString(positionObject.value(ORDER)); bool pinned = positionObject.value(IS_PINNED).toBool(); LOG("Chat position updated for ID" << chatId << "new order" << order << "is pinned" << pinned); emit chatOrderUpdated(chatId, order, updateForChatList); emit chatPinnedUpdated(chatId.toLongLong(), pinned, updateForChatList); } else { // LOG("Received chat position update for uninteresting list" << updateForChatList << "ID" << chatId << "new order" << order << "is pinned" << pinned); } } void TDLibReceiver::processUpdateChatReadInbox(const QJsonObject &receivedInformation) { const QString chatId = parseNumberOrString(receivedInformation.value(CHAT_ID)); const int unreadCount = receivedInformation.value(UNREAD_COUNT).toInt(); LOG("Chat read information updated for" << chatId << "unread count:" << unreadCount); emit chatReadInboxUpdated(chatId, parseNumberOrString(receivedInformation.value(LAST_READ_INBOX_MESSAGE_ID)), unreadCount); } void TDLibReceiver::processUpdateChatReadOutbox(const QJsonObject &receivedInformation) { const QString chatId = parseNumberOrString(receivedInformation.value(CHAT_ID)); const QString lastReadOutboxMessageId = parseNumberOrString(receivedInformation.value(LAST_READ_OUTBOX_MESSAGE_ID)); LOG("Sent messages read information updated for" << chatId << "last read message ID:" << lastReadOutboxMessageId); emit chatReadOutboxUpdated(chatId, lastReadOutboxMessageId); } void TDLibReceiver::processUpdateChatAvailableReactions(const QJsonObject &receivedInformation) { const qlonglong chatId = receivedInformation.value(CHAT_ID).toVariant().toLongLong(); const QVariantMap availableReactions = receivedInformation.value(AVAILABLE_REACTIONS).toObject().toVariantMap(); LOG("Available reactions updated for" << chatId << "new information:" << availableReactions); emit chatAvailableReactionsUpdated(chatId, availableReactions); } void TDLibReceiver::processUpdateBasicGroup(const QJsonObject &receivedInformation) { const QVariantMap basicGroup = receivedInformation.value(BASIC_GROUP).toObject().toVariantMap(); const qlonglong basicGroupId = basicGroup.value(ID).toLongLong(); LOG("Basic group information updated for " << basicGroupId); emit basicGroupUpdated(basicGroupId, basicGroup); } void TDLibReceiver::processUpdateSuperGroup(const QJsonObject &receivedInformation) { const QVariantMap supergroup = receivedInformation.value(SUPERGROUP).toObject().toVariantMap(); const qlonglong superGroupId = supergroup.value(ID).toLongLong(); LOG("Super group information updated for " << superGroupId); emit superGroupUpdated(superGroupId, supergroup); } void TDLibReceiver::processChatOnlineMemberCountUpdated(const QJsonObject &receivedInformation) { const QString chatId = parseNumberOrString(receivedInformation.value(CHAT_ID)); LOG("Online member count updated for chat " << chatId); emit chatOnlineMemberCountUpdated(chatId, receivedInformation.value("online_member_count").toInt()); } void TDLibReceiver::processMessages(const QJsonObject &receivedInformation) { const int totalCount = receivedInformation.value(TOTAL_COUNT).toInt(); LOG("Received new messages, amount: " << totalCount); emit messagesReceived(cleanupList(receivedInformation.value(MESSAGES).toArray()).toVariantList(), totalCount); } void TDLibReceiver::processFoundChatMessages(const QJsonObject &receivedInformation) { const int totalCount = receivedInformation.value(TOTAL_COUNT).toInt(); LOG("Received found chat messages, amount: " << totalCount); emit messagesReceived(cleanupList(receivedInformation.value(MESSAGES).toArray()).toVariantList(), totalCount); } void TDLibReceiver::processSponsoredMessage(const QJsonObject &receivedInformation) { // TdLib <= 1.8.7 const QVariantMap data = receivedInformation.toVariantMap(); const qlonglong chatId = data.value(_EXTRA).toLongLong(); // See TDLibWrapper::getChatSponsoredMessage LOG("Received sponsored message for chat" << chatId); emit sponsoredMessageReceived(chatId, data); } void TDLibReceiver::processSponsoredMessages(const QJsonObject &receivedInformation) { // TdLib >= 1.8.8 const qlonglong chatId = receivedInformation.value(_EXTRA).toVariant().toLongLong(); // See TDLibWrapper::getChatSponsoredMessage const QVariantList messages = receivedInformation.value(MESSAGES).toArray().toVariantList(); LOG("Received" << messages.count() << "sponsored messages for chat" << chatId); QListIterator<QVariant> it(messages); while (it.hasNext()) emit sponsoredMessageReceived(chatId, it.next().toMap()); } void TDLibReceiver::processUpdateNewMessage(const QJsonObject &receivedInformation) { const QJsonObject message = receivedInformation.value(MESSAGE).toObject(); const qlonglong chatId = message.value(CHAT_ID).toVariant().toLongLong(); LOG("Received new message for chat" << chatId); emit newMessageReceived(chatId, cleanupMap(message).toVariantMap()); } void TDLibReceiver::processMessage(const QJsonObject &receivedInformation) { const qlonglong chatId = receivedInformation.value(CHAT_ID).toVariant().toLongLong(); const qlonglong messageId = receivedInformation.value(ID).toVariant().toLongLong(); LOG("Received message " << chatId << messageId); emit messageInformation(chatId, messageId, cleanupMap(receivedInformation).toVariantMap()); } void TDLibReceiver::processMessageLinkInfo(const QJsonObject &receivedInformation) { const QVariantMap data = receivedInformation.toVariantMap(); const QString oldExtra = data.value(_EXTRA).toString(); QString url = ""; QString extra = ""; // qDebug() << "processMessageLinkInfo" << oldExtra; LOG("Received message link info " << oldExtra); if (oldExtra.contains("|")) { const int midIndex = oldExtra.indexOf("|"); url = oldExtra.left(midIndex); extra = oldExtra.mid(midIndex + 1); } else { url = oldExtra; } emit messageLinkInfoReceived(url, data, extra); } void TDLibReceiver::processMessageSendSucceeded(const QJsonObject &receivedInformation) { const qlonglong oldMessageId = receivedInformation.value(OLD_MESSAGE_ID).toVariant().toLongLong(); const QJsonObject message = receivedInformation.value(MESSAGE).toObject(); const qlonglong messageId = message.value(ID).toVariant().toLongLong(); LOG("Message send succeeded" << messageId << oldMessageId); emit messageSendSucceeded(messageId, oldMessageId, cleanupMap(message).toVariantMap()); } void TDLibReceiver::processUpdateActiveNotifications(const QJsonObject &receivedInformation) { LOG("Received active notification groups"); emit activeNotificationsUpdated(receivedInformation.value("groups").toArray().toVariantList()); } void TDLibReceiver::processUpdateNotificationGroup(const QJsonObject &receivedInformation) { LOG("Received updated notification group"); emit notificationGroupUpdated(receivedInformation.toVariantMap()); } void TDLibReceiver::processUpdateNotification(const QJsonObject &receivedInformation) { LOG("Received notification update"); emit notificationUpdated(receivedInformation.toVariantMap()); } void TDLibReceiver::processUpdateChatNotificationSettings(const QJsonObject &receivedInformation) { const QString chatId = parseNumberOrString(receivedInformation.value(CHAT_ID)); LOG("Received new notification settings for chat " << chatId); emit chatNotificationSettingsUpdated(chatId, receivedInformation.value("notification_settings").toObject().toVariantMap()); } void TDLibReceiver::processUpdateMessageContent(const QJsonObject &receivedInformation) { const qlonglong chatId = receivedInformation.value(CHAT_ID).toVariant().toLongLong(); const qlonglong messageId = receivedInformation.value(MESSAGE_ID).toVariant().toLongLong(); LOG("Message content updated" << chatId << messageId); emit messageContentUpdated(chatId, messageId, cleanupMap(receivedInformation.value(NEW_CONTENT).toObject()).toVariantMap()); } void TDLibReceiver::processUpdateDeleteMessages(const QJsonObject &receivedInformation) { const qlonglong chatId = receivedInformation.value(CHAT_ID).toVariant().toLongLong(); const QJsonArray messageIds = receivedInformation.value(MESSAGE_IDS).toArray(); QList<qlonglong> ids; const int n = messageIds.size(); ids.reserve(n); for (auto it = messageIds.begin(); it != messageIds.end(); ++it) { ids.append(it->toVariant().toLongLong()); } LOG(n << "messages were deleted from chat" << chatId); emit messagesDeleted(chatId, ids); } void TDLibReceiver::processChats(const QJsonObject &receivedInformation) { emit chats(receivedInformation.toVariantMap()); } void TDLibReceiver::processChat(const QJsonObject &receivedInformation) { emit chat(receivedInformation.toVariantMap()); } void TDLibReceiver::processUpdateRecentStickers(const QJsonObject &receivedInformation) { LOG("Recent stickers updated"); emit recentStickersUpdated(receivedInformation.value("sticker_ids").toArray().toVariantList()); } void TDLibReceiver::processStickers(const QJsonObject &receivedInformation) { LOG("Received some stickers..."); emit stickers(cleanupList(receivedInformation.value(STICKERS).toArray()).toVariantList()); } void TDLibReceiver::processUpdateInstalledStickerSets(const QJsonObject &receivedInformation) { LOG("Recent sticker sets updated"); emit installedStickerSetsUpdated(receivedInformation.value("sticker_set_ids").toArray().toVariantList()); } void TDLibReceiver::processStickerSets(const QJsonObject &receivedInformation) { LOG("Received some sticker sets..."); emit stickerSets(cleanupList(receivedInformation.value(SETS).toArray()).toVariantList()); } void TDLibReceiver::processStickerSet(const QJsonObject &receivedInformation) { LOG("Received a sticker set..."); emit stickerSet(cleanupMap(receivedInformation).toVariantMap()); } void TDLibReceiver::processChatMembers(const QJsonObject &receivedInformation) { LOG("Received super group members"); const QString extra = parseNumberOrString(receivedInformation.value(_EXTRA)); // qDebug() << "processChatMembers" << extra; emit chatMembers(extra, receivedInformation.value("members").toArray().toVariantList(), receivedInformation.value(TOTAL_COUNT).toInt()); } void TDLibReceiver::processUserFullInfo(const QJsonObject &receivedInformation) { LOG("Received UserFullInfo"); emit userFullInfo(receivedInformation.toVariantMap()); } void TDLibReceiver::processUpdateUserFullInfo(const QJsonObject &receivedInformation) { const QString userId = parseNumberOrString(receivedInformation.value(USER_ID)); LOG("Received UserFullInfoUpdate"); emit userFullInfoUpdated(userId, receivedInformation.value("user_full_info").toObject().toVariantMap()); } void TDLibReceiver::processBasicGroupFullInfo(const QJsonObject &receivedInformation) { const QVariantMap data = receivedInformation.toVariantMap(); const QString groupId = receivedInformation.value(_EXTRA).toString(); // qDebug() << "processBasicGroupFullInfo" << groupId; LOG("Received BasicGroupFullInfo"); emit basicGroupFullInfo(groupId, data); } void TDLibReceiver::processUpdateBasicGroupFullInfo(const QJsonObject &receivedInformation) { const QString groupId = parseNumberOrString(receivedInformation.value("basic_group_id")); LOG("Received BasicGroupFullInfoUpdate"); emit basicGroupFullInfoUpdated(groupId, receivedInformation.value("basic_group_full_info").toObject().toVariantMap()); } void TDLibReceiver::processSupergroupFullInfo(const QJsonObject &receivedInformation) { QVariantMap data = receivedInformation.toVariantMap(); const QString groupId = data.value(_EXTRA).toString(); // qDebug() << "processSupergroupFullInfo" << groupId; LOG("Received SuperGroupFullInfoUpdate"); emit supergroupFullInfo(groupId, data); } void TDLibReceiver::processUpdateSupergroupFullInfo(const QJsonObject &receivedInformation) { const QString groupId = parseNumberOrString(receivedInformation.value("supergroup_id")); // int64_t LOG("Received SuperGroupFullInfoUpdate"); emit supergroupFullInfoUpdated(groupId, receivedInformation.value("supergroup_full_info").toObject().toVariantMap()); } void TDLibReceiver::processUserProfilePhotos(const QJsonObject &receivedInformation) { const QString extra = parseNumberOrString(receivedInformation.value(_EXTRA)); // int64 emit userProfilePhotos(extra, receivedInformation.value("photos").toArray().toVariantList(), receivedInformation.value(TOTAL_COUNT).toInt()); } void TDLibReceiver::processUpdateChatPermissions(const QJsonObject &receivedInformation) { const QString chatId = parseNumberOrString(receivedInformation.value(CHAT_ID)); emit chatPermissionsUpdated(chatId, receivedInformation.value("permissions").toObject().toVariantMap()); } void TDLibReceiver::processUpdateChatPhoto(const QJsonObject &receivedInformation) { const qlonglong chatId = receivedInformation.value(CHAT_ID).toVariant().toLongLong(); LOG("Photo updated for chat" << chatId); emit chatPhotoUpdated(chatId, receivedInformation.value(PHOTO).toObject().toVariantMap()); } void TDLibReceiver::processUpdateChatTitle(const QJsonObject &receivedInformation) { const QString chatId = parseNumberOrString(receivedInformation.value(CHAT_ID)); const QString title = receivedInformation.value(TITLE).toString(); LOG("Received UpdateChatTitle"); emit chatTitleUpdated(chatId, title); } void TDLibReceiver::processUpdateChatPinnedMessage(const QJsonObject &receivedInformation) { LOG("Received UpdateChatPinnedMessage"); emit chatPinnedMessageUpdated(receivedInformation.value(CHAT_ID).toVariant().toLongLong(), receivedInformation.value("pinned_message_id").toVariant().toLongLong()); } void TDLibReceiver::processUpdateMessageIsPinned(const QJsonObject &receivedInformation) { LOG("Received UpdateMessageIsPinned"); emit messageIsPinnedUpdated(receivedInformation.value(CHAT_ID).toVariant().toLongLong(), receivedInformation.value(MESSAGE_ID).toVariant().toLongLong(), receivedInformation.value("is_pinned").toBool()); } void TDLibReceiver::processUsers(const QJsonObject &receivedInformation) { LOG("Received Users"); emit usersReceived(receivedInformation.value(_EXTRA).toString(), // string receivedInformation.value("user_ids").toArray().toVariantList(), receivedInformation.value(TOTAL_COUNT).toInt()); } void TDLibReceiver::processMessageSenders(const QJsonObject &receivedInformation) { const QString extra = parseNumberOrString(receivedInformation.value(_EXTRA)); // qDebug() << "processMessageSenders" << extra; LOG("Received Message Senders"); emit messageSendersReceived(extra, receivedInformation.value("senders").toArray().toVariantList(), receivedInformation.value(TOTAL_COUNT).toInt()); } void TDLibReceiver::processError(const QJsonObject &receivedInformation) { const QString extra = receivedInformation.value(_EXTRA).toString(); const QString message = receivedInformation.value(MESSAGE).toString(); LOG("Received an error"); emit errorReceived(receivedInformation.value("code").toInt(), message, extra); } void TDLibReceiver::ok(const QJsonObject &receivedInformation) { LOG("Received an OK"); if (receivedInformation.contains(_EXTRA)) { emit okReceived(parseNumberOrString(receivedInformation.value(_EXTRA))); } } void TDLibReceiver::processSecretChat(const QJsonObject &receivedInformation) { LOG("Received a secret chat"); emit secretChat(receivedInformation.value(ID).toVariant().toLongLong(), receivedInformation.toVariantMap()); } void TDLibReceiver::processUpdateSecretChat(const QJsonObject &receivedInformation) { LOG("A secret chat was updated"); QVariantMap updatedSecretChat = receivedInformation.value(SECRET_CHAT).toObject().toVariantMap(); emit secretChatUpdated(updatedSecretChat.value(ID).toLongLong(), updatedSecretChat); } void TDLibReceiver::processUpdateMessageEdited(const QJsonObject &receivedInformation) { const qlonglong chatId = receivedInformation.value(CHAT_ID).toVariant().toLongLong(); const qlonglong messageId = receivedInformation.value(MESSAGE_ID).toVariant().toLongLong(); LOG("Message was edited" << chatId << messageId); emit messageEditedUpdated(chatId, messageId, receivedInformation.value("reply_markup").toObject().toVariantMap()); } void TDLibReceiver::processImportedContacts(const QJsonObject &receivedInformation) { LOG("Contacts were imported"); emit contactsImported(receivedInformation.value("importer_count").toArray().toVariantList(), receivedInformation.value("user_ids").toArray().toVariantList()); } void TDLibReceiver::processUpdateChatIsMarkedAsUnread(const QJsonObject &receivedInformation) { LOG("The unread state of a chat was updated"); emit chatIsMarkedAsUnreadUpdated(receivedInformation.value(CHAT_ID).toVariant().toLongLong(), receivedInformation.value("is_marked_as_unread").toBool()); } void TDLibReceiver::processUpdateChatDraftMessage(const QJsonObject &receivedInformation) { LOG("Draft message was updated"); emit chatDraftMessageUpdated(receivedInformation.value(CHAT_ID).toVariant().toLongLong(), cleanupMap(receivedInformation.value(DRAFT_MESSAGE).toObject()).toVariantMap(), findChatPositionOrder(receivedInformation.value(POSITIONS).toArray().toVariantList())); } void TDLibReceiver::processInlineQueryResults(const QJsonObject &receivedInformation) { const QString inlineQueryId = parseNumberOrString(receivedInformation.value("inline_query_id")); const QString nextOffset = parseNumberOrString(receivedInformation.value("next_offset")); const QString switchPmText = parseNumberOrString(receivedInformation.value("switch_pm_text")); const QString switchPmParameter = parseNumberOrString(receivedInformation.value("switch_pm_parameter")); const QString extra = parseNumberOrString(receivedInformation.value(_EXTRA)); // qDebug() << "processInlineQueryResults" << inlineQueryId << nextOffset << switchPmText << switchPmParameter << extra; LOG("Inline Query results"); emit inlineQueryResults(inlineQueryId, nextOffset, receivedInformation.value("results").toArray().toVariantList(), switchPmText, switchPmParameter, extra); } void TDLibReceiver::processCallbackQueryAnswer(const QJsonObject &receivedInformation) { LOG("Callback Query answer"); emit callbackQueryAnswer(receivedInformation.value(TEXT).toString(), receivedInformation.value("alert").toBool(), receivedInformation.value("url").toString()); } void TDLibReceiver::processUserPrivacySettingRules(const QJsonObject &receivedInformation) { LOG("User privacy setting rules"); emit userPrivacySettingRules(receivedInformation.toVariantMap()); } void TDLibReceiver::processUpdateUserPrivacySettingRules(const QJsonObject &receivedInformation) { LOG("User privacy setting rules updated"); emit userPrivacySettingRulesUpdated(receivedInformation.toVariantMap()); } void TDLibReceiver::processUpdateMessageInteractionInfo(const QJsonObject &receivedInformation) { const qlonglong chatId = receivedInformation.value(CHAT_ID).toVariant().toLongLong(); const qlonglong messageId = receivedInformation.value(MESSAGE_ID).toVariant().toLongLong(); LOG("Message interaction info updated" << chatId << messageId); emit messageInteractionInfoUpdated(chatId, messageId, receivedInformation.value(INTERACTION_INFO).toObject().toVariantMap()); } void TDLibReceiver::processSessions(const QJsonObject &receivedInformation) { const int inactiveSessionTtlDays = receivedInformation.value("inactive_session_ttl_days").toInt(); const QVariantList sessions = receivedInformation.value("sessions").toArray().toVariantList(); emit sessionsReceived(inactiveSessionTtlDays, sessions); } void TDLibReceiver::processAvailableReactions(const QJsonObject &receivedInformation) { const qlonglong messageId = receivedInformation.value(_EXTRA).toVariant().toLongLong(); const QJsonArray jsonReactions = receivedInformation.value("reactions").toArray(); if (!jsonReactions.isEmpty()) { QStringList reactions; reactions.reserve(jsonReactions.size()); for (auto it = jsonReactions.begin(); it != jsonReactions.end(); ++it) { reactions.append(it->toString()); } emit availableReactionsReceived(messageId, reactions); } } void TDLibReceiver::processUpdateChatUnreadMentionCount(const QJsonObject &receivedInformation) { // Handles both updateMessageMentionRead and updateChatUnreadMentionCount // They both have chat_id and unread_mention_count which is all we need const qlonglong chatId = receivedInformation.value(CHAT_ID).toVariant().toLongLong(); const int unreadMentionCount = receivedInformation.value(UNREAD_MENTION_COUNT).toInt(); LOG("Chat unread mention count updated" << chatId << unreadMentionCount); emit chatUnreadMentionCountUpdated(chatId, unreadMentionCount); } void TDLibReceiver::processUpdateChatUnreadReactionCount(const QJsonObject &receivedInformation) { const qlonglong chatId = receivedInformation.value(CHAT_ID).toVariant().toLongLong(); const int unreadReactionCount = receivedInformation.value(UNREAD_REACTION_COUNT).toInt(); LOG("Chat unread reaction count updated" << chatId << unreadReactionCount); emit chatUnreadReactionCountUpdated(chatId, unreadReactionCount); } void TDLibReceiver::processUpdateActiveEmojiReactions(const QJsonObject &receivedInformation) { // updateActiveEmojiReactions was introduced between 1.8.5 and 1.8.6 // See https://github.com/tdlib/td/commit/d29d367 const QJsonArray jsonEmojis = receivedInformation.value(EMOJIS).toArray(); QStringList emojis; emojis.reserve(jsonEmojis.size()); for (auto it = jsonEmojis.begin(); it != jsonEmojis.end(); ++it) { emojis.append(it->toString()); } emit activeEmojiReactionsUpdated(emojis); } // Recursively removes (some) unused entries from QVariantMaps to reduce // memory usage. QStrings allocated by QVariantMaps are the top consumers // of memory. The biggest saving is achieved by removing "outline" from // stickers. const QJsonObject TDLibReceiver::cleanupMap(const QJsonObject &map, bool *updated) { const QString type(map.value(_TYPE).toString()); if (type == TYPE_STICKER) { QJsonObject sticker(map); if (sticker.contains(OUTLINE)) { sticker.remove(OUTLINE); sticker.remove(_TYPE); sticker.insert(_TYPE, TYPE_STICKER); // Replace with a shared value if (updated) *updated = true; return sticker; } } else if (type == TYPE_ANIMATED_EMOJI) { bool cleaned = false; const QJsonObject sticker(cleanupMap(map.value(STICKER).toObject(), &cleaned)); if (cleaned) { QJsonObject animatedEmoji(map); animatedEmoji.remove(STICKER); animatedEmoji.insert(STICKER, sticker); animatedEmoji.remove(COLOR_REPLACEMENTS); animatedEmoji.remove(_TYPE); animatedEmoji.insert(_TYPE, TYPE_ANIMATED_EMOJI); // Replace with a shared value if (updated) *updated = true; return animatedEmoji; } } else if (type == TYPE_MESSAGE) { QJsonObject message(map); bool messageChanged = false; const QJsonObject content(cleanupMap(map.value(CONTENT).toObject(), &messageChanged)); if (messageChanged) { message.remove(CONTENT); message.insert(CONTENT, content); } if (map.contains(REPLY_TO)) { // In TdLib 1.8.15 reply_to_message_id and reply_in_chat_id attributes // had been replaced with reply_to structure, e.g: // // "reply_to": { // "@type": "messageReplyToMessage", // "chat_id": -1001234567890, // "is_quote_manual": false, // "message_id": 234567890, // "origin_send_date": 0 // } // QJsonObject replyTo(message.value(REPLY_TO).toObject()); if (replyTo.value(_TYPE).toString() == TYPE_MESSAGE_REPLY_TO_MESSAGE) { if (replyTo.contains(MESSAGE_ID) && !message.contains(REPLY_TO_MESSAGE_ID)) { message.insert(REPLY_TO_MESSAGE_ID, replyTo.value(MESSAGE_ID)); } if (replyTo.contains(CHAT_ID) && !message.contains(REPLY_IN_CHAT_ID)) { message.insert(REPLY_IN_CHAT_ID, replyTo.value(CHAT_ID)); } replyTo.remove(_TYPE); replyTo.insert(_TYPE, TYPE_MESSAGE_REPLY_TO_MESSAGE); message.insert(REPLY_TO, replyTo); messageChanged = true; } } if (messageChanged) { message.remove(_TYPE); message.insert(_TYPE, TYPE_MESSAGE); // Replace with a shared value if (updated) *updated = true; return message; } } else if (type == TYPE_DRAFT_MESSAGE) { QJsonObject draftMessage(map); QJsonObject replyTo(draftMessage.value(REPLY_TO).toObject()); // In TdLib 1.8.21 reply_to_message_id has been replaced with reply_to if (replyTo.value(_TYPE).toString() == TYPE_INPUT_MESSAGE_REPLY_TO_MESSAGE) { if (replyTo.contains(MESSAGE_ID) && !draftMessage.contains(REPLY_TO_MESSAGE_ID)) { // reply_to_message_id is what QML (still) expects draftMessage.insert(REPLY_TO_MESSAGE_ID, replyTo.value(MESSAGE_ID)); } replyTo.remove(_TYPE); replyTo.insert(_TYPE, TYPE_INPUT_MESSAGE_REPLY_TO_MESSAGE); // Shared value draftMessage.insert(REPLY_TO, replyTo); draftMessage.remove(_TYPE); draftMessage.insert(_TYPE, DRAFT_MESSAGE); // Shared value if (updated) *updated = true; return draftMessage; } } else if (type == TYPE_MESSAGE_STICKER) { bool cleaned = false; const QJsonObject content(cleanupMap(map.value(CONTENT).toObject(), &cleaned)); if (cleaned) { QJsonObject messageSticker(map); messageSticker.remove(CONTENT); messageSticker.insert(CONTENT, content); messageSticker.remove(_TYPE); messageSticker.insert(_TYPE, TYPE_MESSAGE_STICKER); // Replace with a shared value if (updated) *updated = true; return messageSticker; } } else if (type == TYPE_MESSAGE_ANIMATED_EMOJI) { bool cleaned = false; const QJsonObject animated_emoji(cleanupMap(map.value(ANIMATED_EMOJI).toObject(), &cleaned)); if (cleaned) { QJsonObject messageAnimatedEmoji(map); messageAnimatedEmoji.remove(ANIMATED_EMOJI); messageAnimatedEmoji.insert(ANIMATED_EMOJI, animated_emoji); messageAnimatedEmoji.remove(_TYPE); messageAnimatedEmoji.insert(_TYPE, TYPE_MESSAGE_ANIMATED_EMOJI); // Replace with a shared value if (updated) *updated = true; return messageAnimatedEmoji; } } else if (type == TYPE_STICKER_SET_INFO) { bool cleaned = false; const QJsonArray covers(cleanupList(map.value(COVERS).toArray(), &cleaned)); if (cleaned) { QJsonObject stickerSetInfo(map); stickerSetInfo.remove(COVERS); stickerSetInfo.insert(COVERS, covers); stickerSetInfo.remove(_TYPE); stickerSetInfo.insert(_TYPE, TYPE_STICKER_SET_INFO); // Replace with a shared value if (updated) *updated = true; return stickerSetInfo; } } else if (type == TYPE_STICKER_SET) { bool cleaned = false; const QJsonArray stickers(cleanupList(map.value(STICKERS).toArray(), &cleaned)); if (cleaned) { QJsonObject stickerSet(map); stickerSet.remove(STICKERS); stickerSet.insert(STICKERS, stickers); stickerSet.remove(_TYPE); stickerSet.insert(_TYPE, TYPE_STICKER_SET); // Replace with a shared value if (updated) *updated = true; return stickerSet; } } if (updated) *updated = false; return map; } const QJsonArray TDLibReceiver::cleanupList(const QJsonArray &list, bool *updated) { QJsonArray newList(list); bool somethingChanged = false; const int n = list.count(); for (int i = 0; i < n; i++) { bool cleaned = false; const QJsonObject entry(cleanupMap(list[i].toObject(), &cleaned)); if (cleaned) { newList.replace(i, entry); somethingChanged = true; } } if (somethingChanged) { if (updated) *updated = true; return newList; } return list; }