File indexing completed on 2024-12-01 04:33:08
0001 /** 0002 * SPDX-FileCopyrightText: 2013 Albert Vaca <albertvaka@gmail.com> 0003 * SPDX-FileCopyrightText: 2018 Simon Redman <simon@ergotech.com> 0004 * 0005 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0006 */ 0007 0008 #pragma once 0009 0010 #include <QDBusAbstractAdaptor> 0011 #include <QDir> 0012 #include <QHash> 0013 #include <QList> 0014 #include <QMap> 0015 #include <QPointer> 0016 #include <QString> 0017 #include <QStringList> 0018 0019 #include "interfaces/conversationmessage.h" 0020 #include "interfaces/dbusinterfaces.h" 0021 0022 class KdeConnectPlugin; 0023 class Device; 0024 0025 Q_DECLARE_LOGGING_CATEGORY(KDECONNECT_CONVERSATIONS) 0026 0027 // There is some amount of overhead and delay to making a request, so make sure to request at least a few 0028 #define MIN_NUMBER_TO_REQUEST 25 0029 // Some low-water mark after which we want to fill the cache 0030 #define CACHE_LOW_WATER_MARK_PERCENT 10 0031 0032 class ConversationsDbusInterface : public QDBusAbstractAdaptor 0033 { 0034 Q_OBJECT 0035 Q_CLASSINFO("D-Bus Interface", "org.kde.kdeconnect.device.conversations") 0036 0037 public: 0038 explicit ConversationsDbusInterface(KdeConnectPlugin *plugin); 0039 ~ConversationsDbusInterface() override; 0040 0041 void addMessages(const QList<ConversationMessage> &messages); 0042 void removeMessage(const QString &internalId); 0043 0044 /** 0045 * Return a shallow copy of the requested conversation 0046 */ 0047 QList<ConversationMessage> getConversation(const qint64 &conversationID) const; 0048 0049 /** 0050 * Get some new messages for the requested conversation from the remote device 0051 * Requests a quantity of new messages equal to the current number of messages in the conversation 0052 */ 0053 void updateConversation(const qint64 &conversationID); 0054 0055 /** 0056 * Gets the path of the succesfully downloaded attachment file and send 0057 * update to the conversationModel 0058 */ 0059 void attachmentDownloaded(const QString &filePath, const QString &fileName); 0060 0061 public Q_SLOTS: 0062 /** 0063 * Return a list of the first message in every conversation 0064 * 0065 * Note that the return value is a list of QVariants, which in turn have a value of 0066 * QVariantMap created from each message 0067 */ 0068 QVariantList activeConversations(); 0069 0070 /** 0071 * Request the specified range of the specified conversation 0072 * 0073 * Emits conversationUpdated for every message in the requested range 0074 * 0075 * If the conversation does not have enough messages to fill the request, 0076 * this method may return fewer messages 0077 */ 0078 void requestConversation(const qint64 &conversationID, int start, int end); 0079 0080 /** 0081 * Send a new message to this conversation 0082 */ 0083 void replyToConversation(const qint64 &conversationID, const QString &message, const QVariantList &attachmentUrls); 0084 0085 /** 0086 * Send a new message to the contact having no previous coversation with 0087 */ 0088 void sendWithoutConversation(const QVariantList &addressList, const QString &message, const QVariantList &attachmentUrls); 0089 0090 /** 0091 * Send the request to the Telephony plugin to update the list of conversation threads 0092 */ 0093 void requestAllConversationThreads(); 0094 0095 /** 0096 * Send the request to SMS plugin to fetch original attachment file path 0097 */ 0098 void requestAttachmentFile(const qint64 &partID, const QString &uniqueIdentifier); 0099 0100 Q_SIGNALS: 0101 0102 /** 0103 * This signal is never emitted, but if it's not here then qdbuscpp2xml in Qt6 0104 * will not generate all the signals that use QDBusVariant in the output XML 0105 */ 0106 Q_SCRIPTABLE void veryHackyWorkaround(const QVariant &); 0107 0108 /** 0109 * Emitted whenever a conversation with no cached messages is added, either because the cache 0110 * is being populated or because a new conversation has been created 0111 */ 0112 Q_SCRIPTABLE void conversationCreated(const QDBusVariant &msg); 0113 0114 /** 0115 * Emitted whenever a conversation is being deleted 0116 */ 0117 Q_SCRIPTABLE void conversationRemoved(const qint64 &conversationID); 0118 0119 /** 0120 * Emitted whenever a message is added to a conversation and it is the newest message in the 0121 * conversation 0122 */ 0123 Q_SCRIPTABLE void conversationUpdated(const QDBusVariant &msg); 0124 0125 /** 0126 * Emitted whenever we have handled a response from the phone indicating the total number of 0127 * (locally-known) messages in the given conversation 0128 */ 0129 Q_SCRIPTABLE void conversationLoaded(qint64 conversationID, quint64 messageCount); 0130 0131 /** 0132 * Emitted whenever we have succesfully download a requested attachment file from the phone 0133 */ 0134 Q_SCRIPTABLE void attachmentReceived(QString filePath, QString fileName); 0135 0136 private /*methods*/: 0137 QString newId(); // Generates successive identifiers to use as public ids 0138 0139 private /*attributes*/: 0140 const QString m_device; 0141 0142 /** 0143 * Mapping of threadID to the messages which make up that thread 0144 * 0145 * The messages are stored as a QMap of the timestamp to the actual message object so that 0146 * we can use .values() to get a sorted list of messages from least- to most-recent 0147 */ 0148 QHash<qint64, QMap<qint64, ConversationMessage>> m_conversations; 0149 0150 /** 0151 * Mapping of threadID to the set of uIDs known in the corresponding conversation 0152 */ 0153 QHash<qint64, QSet<qint32>> m_known_messages; 0154 0155 /* 0156 * Keep a map of all interfaces ever constructed 0157 * Because of how Qt's Dbus is designed, we are unable to immediately delete the interface once 0158 * the device has disconnected. We save the list of existing interfaces and delete them only after 0159 * we have replaced them (in ConversationsDbusInterface's constructor) 0160 * See the comment in ~NotificationsPlugin() for more information 0161 */ 0162 static QMap<QString, ConversationsDbusInterface *> liveConversationInterfaces; 0163 0164 int m_lastId; 0165 0166 SmsDbusInterface m_smsInterface; 0167 0168 QSet<qint64> conversationsWaitingForMessages; 0169 QMutex waitingForMessagesLock; 0170 QWaitCondition waitingForMessages; 0171 };