File indexing completed on 2024-04-21 04:56:55

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 <QObject>
0011 
0012 #include <core/kdeconnectplugin.h>
0013 
0014 #include "conversationsdbusinterface.h"
0015 #include "interfaces/conversationmessage.h"
0016 
0017 /**
0018  * Packet used to indicate a batch of messages has been pushed from the remote device
0019  *
0020  * The body should contain the key "messages" mapping to an array of messages
0021  *
0022  * For example:
0023  * {
0024  *   "version": 2                     // This is the second version of this packet type and
0025  *                                    // version 1 packets (which did not carry this flag)
0026  *                                    // are incompatible with the new format
0027  *   "messages" : [
0028  *   { "event"     : 1,               // 32-bit field containing a bitwise-or of event flags
0029  *                                    // See constants declared in SMSHelper.Message for defined
0030  *                                    // values and explanations
0031  *     "body"      : "Hello",         // Text message body
0032  *     "addresses": <List<Address>>   // List of Address objects, one for each participant of the conversation
0033  *                                    // The user's Address is excluded so:
0034  *                                    // If this is a single-target message, there will only be one
0035  *                                    // Address (the other party)
0036  *                                    // If this is an incoming multi-target message, the first Address is the
0037  *                                    // sender and all other addresses are other parties to the conversation
0038  *                                    // If this is an outgoing multi-target message, the sender is implicit
0039  *                                    // (the user's phone number) and all Addresses are recipients
0040  *     "date"      : "1518846484880", // Timestamp of the message
0041  *     "type"      : "2",   // Compare with Android's
0042  *                          // Telephony.TextBasedSmsColumns.MESSAGE_TYPE_*
0043  *     "thread_id" : 132    // Thread to which the message belongs
0044  *     "read"      : true   // Boolean representing whether a message is read or unread
0045  *   },
0046  *   { ... },
0047  *   ...
0048  * ]
0049  *
0050  * The following optional fields of a message object may be defined
0051  * "sub_id": <int> // Android's subscriber ID, which is basically used to determine which SIM card the message
0052  *                 // belongs to. This is mostly useful when attempting to reply to an SMS with the correct
0053  *                 // SIM card using PACKET_TYPE_SMS_REQUEST.
0054  *                 // If this value is not defined or if it does not match a valid subscriber_id known by
0055  *                 // Android, we will use whatever subscriber ID Android gives us as the default
0056  *
0057  * "attachments": <List<Attachment>>    // List of Attachment objects, one for each attached file in the message.
0058  *
0059  * An Attachment object looks like:
0060  * {
0061  *     "part_id": <long>                // part_id of the attachment used to read the file from MMS database
0062  *     "mime_type": <int>               // contains the mime type of the file (image, video, audio, etc.)
0063  *     "encoded_thumbnail": <String>    // Optional base64-encoded thumbnail preview of the content for types which support it
0064  *     "unique_identifier": <String>    // Unique name of te file
0065  * }
0066  *
0067  * An Address object looks like:
0068  * {
0069  *     "address": <String> // Address (phone number, email address, etc.) of this object
0070  * }
0071  */
0072 #define PACKET_TYPE_SMS_MESSAGES QStringLiteral("kdeconnect.sms.messages")
0073 
0074 /**
0075  * Packet sent to request a message be sent
0076  *
0077  * The body should look like so:
0078  * {
0079  *   "version": 2,                     // The version of the packet being sent. Compare to SMS_REQUEST_PACKET_VERSION before attempting to handle.
0080  *   "addresses": <List<Addresses>>,   // The one or many targets of this message
0081  *   "messageBody": "Hi mom!",         // Plain-text string to be sent as the body of the message
0082  *   "attachments": <List<Attachment>>,// Send one or more attachments with this message. See AttachmentContainer documentation for formatting. (Optional)
0083  *   "sub_id": 3859358340534           // Some magic number which tells Android which SIM card to use (Optional, if omitted, sends with the default SIM card)
0084  * }
0085  *
0086  * An AttachmentContainer object looks like:
0087  * {
0088  *   "fileName": <String>             // Name of the file
0089  *   "base64EncodedFile": <String>    // Base64 encoded file
0090  *   "mimeType": <String>             // File type (eg: image/jpg, video/mp4 etc.)
0091  * }
0092  *
0093  */
0094 #define PACKET_TYPE_SMS_REQUEST QStringLiteral("kdeconnect.sms.request")
0095 #define SMS_REQUEST_PACKET_VERSION 2 // We *send* packets of this version
0096 
0097 /**
0098  * Packet sent to request the most-recent message in each conversations on the device
0099  *
0100  * The request packet shall contain no body
0101  */
0102 #define PACKET_TYPE_SMS_REQUEST_CONVERSATIONS QStringLiteral("kdeconnect.sms.request_conversations")
0103 
0104 /**
0105  * Packet sent to request all the messages in a particular conversation
0106  *
0107  * The following fields are available:
0108  * "threadID": <long>            // (Required) ThreadID to request
0109  * "rangeStartTimestamp": <long> // (Optional) Millisecond epoch timestamp indicating the start of the range from which to return messages
0110  * "numberToRequest": <long>     // (Optional) Number of messages to return, starting from rangeStartTimestamp.
0111  *                               // May return fewer than expected if there are not enough or more than expected if many
0112  *                               // messages have the same timestamp.
0113  */
0114 #define PACKET_TYPE_SMS_REQUEST_CONVERSATION QStringLiteral("kdeconnect.sms.request_conversation")
0115 
0116 /**
0117  * Packet sent to request an attachment file in a particular message of a conversation
0118  *
0119  * The body should look like so:
0120  * "part_id": <long>                 // Part id of the attachment
0121  * "unique_identifier": <String>     // It can be any hash code or unique name of the file
0122  */
0123 #define PACKET_TYPE_SMS_REQUEST_ATTACHMENT QStringLiteral("kdeconnect.sms.request_attachment")
0124 
0125 /**
0126  * Packet used to send original attachment file from mms database to desktop
0127  * <p>
0128  * The following fields are available:
0129  * "thread_id": <long>      // Thread to which the attachment belongs
0130  * "filename": <String>     // Name of the attachment file in the database
0131  */
0132 #define PACKET_TYPE_SMS_ATTACHMENT_FILE QStringLiteral("kdeconnect.sms.attachment_file")
0133 
0134 Q_DECLARE_LOGGING_CATEGORY(KDECONNECT_PLUGIN_SMS)
0135 
0136 #define CODEC_NAME "CP1251"
0137 
0138 class QTextCodec;
0139 
0140 class SmsPlugin : public KdeConnectPlugin
0141 {
0142     Q_OBJECT
0143     Q_CLASSINFO("D-Bus Interface", "org.kde.kdeconnect.device.sms")
0144 
0145 public:
0146     explicit SmsPlugin(QObject *parent, const QVariantList &args);
0147     ~SmsPlugin() override;
0148 
0149     void receivePacket(const NetworkPacket &np) override;
0150 
0151     QString dbusPath() const override;
0152 
0153 public Q_SLOTS:
0154     Q_SCRIPTABLE void sendSms(const QVariantList &addresses, const QString &textMessage, const QVariantList &attachmentUrls, const qint64 subID = -1);
0155 
0156     /**
0157      * Send a request to the remote for all of its conversations
0158      */
0159     Q_SCRIPTABLE void requestAllConversations();
0160 
0161     /**
0162      * Send a request to the remote for a particular conversation
0163      *
0164      * @param conversationID The conversation to query
0165      * @param rangeStartTimestamp Return messages with timestamp >= this value. Value <= 0 indicates no limit.
0166      * @param numberToRequest Request this many messages. May return more, may return less. Value <= 0 indicates no limit.
0167      */
0168     Q_SCRIPTABLE void requestConversation(const qint64 conversationID, const qint64 rangeStartTimestamp = -1, const qint64 numberToRequest = -1) const;
0169 
0170     Q_SCRIPTABLE void launchApp();
0171 
0172     /**
0173      * Send a request to the remote device for a particulr attachment file
0174      */
0175     Q_SCRIPTABLE void requestAttachment(const qint64 &partID, const QString &uniqueIdentifier);
0176 
0177     /**
0178      * Searches the requested file in the application's cache directory,
0179      * if not found then sends the request to remote device
0180      */
0181     Q_SCRIPTABLE void getAttachment(const qint64 &partID, const QString &uniqueIdentifier);
0182 
0183 private:
0184     /**
0185      * Send to the telepathy plugin if it is available
0186      */
0187     void forwardToTelepathy(const ConversationMessage &message);
0188 
0189     /**
0190      * Handle a packet which contains many messages, such as PACKET_TYPE_TELEPHONY_MESSAGE
0191      */
0192     bool handleBatchMessages(const NetworkPacket &np);
0193 
0194     /**
0195      * Handle a packet of type PACKET_TYPE_SMS_ATTACHMENT_FILE which contains an attachment file
0196      */
0197     bool handleSmsAttachmentFile(const NetworkPacket &np);
0198 
0199     /**
0200      * Encode a local file so it can be sent to the remote device as part of an MMS message.
0201      */
0202     Attachment createAttachmentFromUrl(const QString &url);
0203 
0204     QDBusInterface m_telepathyInterface;
0205     ConversationsDbusInterface *m_conversationInterface;
0206     QTextCodec *m_codec;
0207 };