diff --git a/cli/kdeconnect-cli.cpp b/cli/kdeconnect-cli.cpp index aa8ea06ee..1fd32390e 100644 --- a/cli/kdeconnect-cli.cpp +++ b/cli/kdeconnect-cli.cpp @@ -41,7 +41,7 @@ int main(int argc, char** argv) QStringLiteral("kdeconnect-cli"), QStringLiteral(KDECONNECT_VERSION_STRING), i18n("KDE Connect CLI tool"), - KAboutLicense::GPL, + KAboutLicense::GPL, i18n("(C) 2015 Aleix Pol Gonzalez")); KAboutData::setApplicationData(about); @@ -214,7 +214,7 @@ int main(int argc, char** argv) blockOnReply(QDBusConnection::sessionBus().asyncCall(msg)); } else if(parser.isSet(QStringLiteral("send-sms"))) { if (parser.isSet(QStringLiteral("destination"))) { - QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("org.kde.kdeconnect"), "/modules/kdeconnect/devices/"+device+"/telephony", QStringLiteral("org.kde.kdeconnect.device.telephony"), QStringLiteral("sendSms")); + QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("org.kde.kdeconnect"), "/modules/kdeconnect/devices/"+device+"/sms", QStringLiteral("org.kde.kdeconnect.device.sms"), QStringLiteral("sendSms")); msg.setArguments({ parser.value("destination"), parser.value("send-sms") }); blockOnReply(QDBusConnection::sessionBus().asyncCall(msg)); } else { diff --git a/declarativeplugin/kdeconnectdeclarativeplugin.cpp b/declarativeplugin/kdeconnectdeclarativeplugin.cpp index 6728b5cef..d86c0b117 100644 --- a/declarativeplugin/kdeconnectdeclarativeplugin.cpp +++ b/declarativeplugin/kdeconnectdeclarativeplugin.cpp @@ -75,9 +75,9 @@ QObject* createDeviceLockInterface(const QVariant& deviceId) return new LockDeviceDbusInterface(deviceId.toString()); } -QObject* createTelephonyInterface(const QVariant& deviceId) +QObject* createSmsInterface(const QVariant& deviceId) { - return new TelephonyDbusInterface(deviceId.toString()); + return new SmsDbusInterface(deviceId.toString()); } QObject* createDBusResponse() @@ -138,8 +138,8 @@ void KdeConnectDeclarativePlugin::initializeEngine(QQmlEngine* engine, const cha engine->rootContext()->setContextProperty(QStringLiteral("LockDeviceDbusInterfaceFactory") , new ObjectFactory(engine, createDeviceLockInterface)); - engine->rootContext()->setContextProperty(QStringLiteral("TelephonyDbusInterfaceFactory") - , new ObjectFactory(engine, createTelephonyInterface)); + engine->rootContext()->setContextProperty(QStringLiteral("SmsDbusInterfaceFactory") + , new ObjectFactory(engine, createSmsInterface)); engine->rootContext()->setContextProperty(QStringLiteral("DBusResponseFactory") , new ObjectFactory(engine, createDBusResponse)); diff --git a/interfaces/CMakeLists.txt b/interfaces/CMakeLists.txt index 886759d39..7f7e00fd2 100644 --- a/interfaces/CMakeLists.txt +++ b/interfaces/CMakeLists.txt @@ -48,8 +48,8 @@ geninterface(${CMAKE_SOURCE_DIR}/plugins/remotecontrol/remotecontrolplugin.h rem geninterface(${CMAKE_SOURCE_DIR}/plugins/lockdevice/lockdeviceplugin.h lockdeviceinterface) geninterface(${CMAKE_SOURCE_DIR}/plugins/remotecommands/remotecommandsplugin.h remotecommandsinterface) geninterface(${CMAKE_SOURCE_DIR}/plugins/remotekeyboard/remotekeyboardplugin.h remotekeyboardinterface) -geninterface(${CMAKE_SOURCE_DIR}/plugins/telephony/telephonyplugin.h telephonyinterface) -geninterface(${CMAKE_SOURCE_DIR}/plugins/telephony/conversationsdbusinterface.h conversationsinterface) +geninterface(${CMAKE_SOURCE_DIR}/plugins/sms/smsplugin.h smsinterface) +geninterface(${CMAKE_SOURCE_DIR}/plugins/sms/conversationsdbusinterface.h conversationsinterface) add_library(kdeconnectinterfaces SHARED ${libkdeconnect_SRC}) diff --git a/interfaces/dbusinterfaces.cpp b/interfaces/dbusinterfaces.cpp index 0f0fdfdd6..c36861eff 100644 --- a/interfaces/dbusinterfaces.cpp +++ b/interfaces/dbusinterfaces.cpp @@ -176,9 +176,9 @@ RemoteKeyboardDbusInterface::RemoteKeyboardDbusInterface(const QString& deviceId RemoteKeyboardDbusInterface::~RemoteKeyboardDbusInterface() = default; -TelephonyDbusInterface::TelephonyDbusInterface(const QString& deviceId, QObject* parent): - OrgKdeKdeconnectDeviceTelephonyInterface(DaemonDbusInterface::activatedService(), "/modules/kdeconnect/devices/" + deviceId + "/telephony", QDBusConnection::sessionBus(), parent) +SmsDbusInterface::SmsDbusInterface(const QString& deviceId, QObject* parent): + OrgKdeKdeconnectDeviceSmsInterface(DaemonDbusInterface::activatedService(), "/modules/kdeconnect/devices/" + deviceId + "/sms", QDBusConnection::sessionBus(), parent) { } -TelephonyDbusInterface::~TelephonyDbusInterface() = default; +SmsDbusInterface::~SmsDbusInterface() = default; diff --git a/interfaces/dbusinterfaces.h b/interfaces/dbusinterfaces.h index 348159d5a..f75ef7454 100644 --- a/interfaces/dbusinterfaces.h +++ b/interfaces/dbusinterfaces.h @@ -35,7 +35,7 @@ #include "interfaces/lockdeviceinterface.h" #include "interfaces/remotecommandsinterface.h" #include "interfaces/remotekeyboardinterface.h" -#include "interfaces/telephonyinterface.h" +#include "interfaces/smsinterface.h" #include "interfaces/conversationsinterface.h" /** @@ -210,13 +210,13 @@ Q_SIGNALS: void remoteStateChanged(bool state); }; -class KDECONNECTINTERFACES_EXPORT TelephonyDbusInterface - : public OrgKdeKdeconnectDeviceTelephonyInterface +class KDECONNECTINTERFACES_EXPORT SmsDbusInterface + : public OrgKdeKdeconnectDeviceSmsInterface { Q_OBJECT public: - explicit TelephonyDbusInterface(const QString& deviceId, QObject* parent = nullptr); - ~TelephonyDbusInterface() override; + explicit SmsDbusInterface(const QString& deviceId, QObject* parent = nullptr); + ~SmsDbusInterface() override; }; template diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 4f771c7dd..04ca88fd2 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -19,6 +19,7 @@ if(NOT SAILFISHOS) add_subdirectory(findmyphone) add_subdirectory(telephony) add_subdirectory(mousepad) + add_subdirectory(sms) if(NOT WIN32) add_subdirectory(runcommand) add_subdirectory(pausemusic) diff --git a/plugins/sms/CMakeLists.txt b/plugins/sms/CMakeLists.txt new file mode 100644 index 000000000..db6b61b54 --- /dev/null +++ b/plugins/sms/CMakeLists.txt @@ -0,0 +1,22 @@ +set(kdeconnect_sms_SRCS + smsplugin.cpp + conversationsdbusinterface.cpp +) + +include_directories(${CMAKE_BINARY_DIR}) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../notifications/) # needed for the sendreplydialog + +ki18n_wrap_ui(kdeconnect_sms_SRCS ../notifications/sendreplydialog.ui) + +kdeconnect_add_plugin(kdeconnect_sms JSON kdeconnect_sms.json SOURCES ../notifications/sendreplydialog.cpp ${kdeconnect_sms_SRCS}) + + +target_link_libraries(kdeconnect_sms + kdeconnectcore + kdeconnectinterfaces + Qt5::DBus + KF5::I18n + KF5::Notifications + Qt5::Widgets +) diff --git a/plugins/telephony/conversationsdbusinterface.cpp b/plugins/sms/conversationsdbusinterface.cpp similarity index 89% rename from plugins/telephony/conversationsdbusinterface.cpp rename to plugins/sms/conversationsdbusinterface.cpp index 345ddbb95..88d573686 100644 --- a/plugins/telephony/conversationsdbusinterface.cpp +++ b/plugins/sms/conversationsdbusinterface.cpp @@ -27,14 +27,14 @@ #include #include -#include "telephonyplugin.h" +Q_LOGGING_CATEGORY(KDECONNECT_CONVERSATIONS, "kdeconnect.conversations") ConversationsDbusInterface::ConversationsDbusInterface(KdeConnectPlugin* plugin) : QDBusAbstractAdaptor(const_cast(plugin->device())) , m_device(plugin->device()) , m_plugin(plugin) , m_lastId(0) - , m_telephonyInterface(m_device->id()) + , m_smsInterface(m_device->id()) { ConversationMessage::registerDbusType(); } @@ -55,10 +55,10 @@ void ConversationsDbusInterface::requestConversation(const QString& conversation if (messagesList.isEmpty()) { // Since there are no messages in the conversation, it's likely that it is a junk ID, but go ahead anyway - qCWarning(KDECONNECT_PLUGIN_TELEPHONY) << "Got a conversationID for a conversation with no messages!" << conversationID; + qCWarning(KDECONNECT_CONVERSATIONS) << "Got a conversationID for a conversation with no messages!" << conversationID; } - m_telephonyInterface.requestConversation(conversationID); + m_smsInterface.requestConversation(conversationID); // Messages are sorted in ascending order of keys, meaning the front of the list has the oldest // messages (smallest timestamp number) @@ -111,7 +111,7 @@ void ConversationsDbusInterface::replyToConversation(const QString& conversation if (messagesList.isEmpty()) { // Since there are no messages in the conversation, we can't do anything sensible - qCWarning(KDECONNECT_PLUGIN_TELEPHONY) << "Got a conversationID for a conversation with no messages!"; + qCWarning(KDECONNECT_CONVERSATIONS) << "Got a conversationID for a conversation with no messages!"; return; } // Caution: @@ -119,13 +119,13 @@ void ConversationsDbusInterface::replyToConversation(const QString& conversation // with .first()) will be the same. This works fine for single-target SMS but might break down // for group MMS, etc. const QString& address = messagesList.first().address(); - m_telephonyInterface.sendSms(address, message); + m_smsInterface.sendSms(address, message); } void ConversationsDbusInterface::requestAllConversationThreads() { // Prepare the list of conversations by requesting the first in every thread - m_telephonyInterface.requestAllConversations(); + m_smsInterface.requestAllConversations(); } QString ConversationsDbusInterface::newId() diff --git a/plugins/telephony/conversationsdbusinterface.h b/plugins/sms/conversationsdbusinterface.h similarity index 97% rename from plugins/telephony/conversationsdbusinterface.h rename to plugins/sms/conversationsdbusinterface.h index 2270caf48..f69c84963 100644 --- a/plugins/telephony/conversationsdbusinterface.h +++ b/plugins/sms/conversationsdbusinterface.h @@ -36,6 +36,8 @@ class KdeConnectPlugin; class Device; +Q_DECLARE_LOGGING_CATEGORY(KDECONNECT_CONVERSATIONS) + class ConversationsDbusInterface : public QDBusAbstractAdaptor { @@ -95,7 +97,7 @@ private /*attributes*/: int m_lastId; - TelephonyDbusInterface m_telephonyInterface; + SmsDbusInterface m_smsInterface; }; #endif // CONVERSATIONSDBUSINTERFACE_H diff --git a/plugins/sms/kdeconnect_sms.json b/plugins/sms/kdeconnect_sms.json new file mode 100644 index 000000000..88798a2e1 --- /dev/null +++ b/plugins/sms/kdeconnect_sms.json @@ -0,0 +1,30 @@ +{ + "KPlugin": { + "Authors": [ + { + "Email": "simon@ergotech.com", + "Name": "Simon Redman" + } + ], + "Description": "Send and receive SMS", + "EnabledByDefault": true, + "Icon": "dialog-ok", + "Id": "kdeconnect_sms", + "License": "GPL", + "Name": "SMS", + "ServiceTypes": [ + "KdeConnect/Plugin" + ], + "Version": "0.1", + "Website": "https://nicolasfella.wordpress.com" + }, + "X-KdeConnect-OutgoingPacketType": [ + "kdeconnect.sms.request", + "kdeconnect.telephony.request_conversations", + "kdeconnect.telephony.request_conversation" + ], + "X-KdeConnect-SupportedPacketType": [ + "kdeconnect.telephony.message", + "kdeconnect.telephony" + ] +} diff --git a/plugins/sms/smsplugin.cpp b/plugins/sms/smsplugin.cpp new file mode 100644 index 000000000..aaa9c8d7f --- /dev/null +++ b/plugins/sms/smsplugin.cpp @@ -0,0 +1,201 @@ +/** + * Copyright 2013 Albert Vaca + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "smsplugin.h" + +#include +#include + +#include +#include +#include + +#include +#include + +#include "sendreplydialog.h" + +K_PLUGIN_FACTORY_WITH_JSON( KdeConnectPluginFactory, "kdeconnect_sms.json", registerPlugin< SmsPlugin >(); ) + +Q_LOGGING_CATEGORY(KDECONNECT_PLUGIN_SMS, "kdeconnect.plugin.sms") + +SmsPlugin::SmsPlugin(QObject* parent, const QVariantList& args) + : KdeConnectPlugin(parent, args) + , m_telepathyInterface(QStringLiteral("org.freedesktop.Telepathy.ConnectionManager.kdeconnect"), QStringLiteral("/kdeconnect")) + , m_conversationInterface(new ConversationsDbusInterface(this)) +{ +} + +SmsPlugin::~SmsPlugin() +{ +} + +bool SmsPlugin::receivePacket(const NetworkPacket& np) +{ + if (np.get(QStringLiteral("isCancel"))) { + + //TODO: Clear the old notification + return true; + } + + const QString& event = np.get(QStringLiteral("event"), QStringLiteral("unknown")); + + // Handle old-style packets + // TODO Drop support? + if (np.type() == PACKET_TYPE_TELEPHONY) + { + if (event == QLatin1String("sms")) + { + // New-style packets should be a PACKET_TYPE_TELEPHONY_MESSAGE (15 May 2018) + qCDebug(KDECONNECT_PLUGIN_SMS) << "Handled an old-style Telephony sms packet. You should update your Android app to get the latest features!"; + ConversationMessage message(np.body()); + + // In case telepathy can handle the message, don't do anything else + if (m_telepathyInterface.isValid()) { + forwardToTelepathy(message); + return true; + } + + KNotification* n = createNotification(np); + if (n != nullptr) n->sendEvent(); + return true; + + } + } + + if (np.type() == PACKET_TYPE_TELEPHONY_MESSAGE) { + return handleBatchMessages(np); + } + + return true; +} + +KNotification* SmsPlugin::createNotification(const NetworkPacket& np) +{ + const QString event = np.get(QStringLiteral("event")); + const QString phoneNumber = np.get(QStringLiteral("phoneNumber"), i18n("unknown number")); + const QString contactName = np.get(QStringLiteral("contactName"), phoneNumber); + const QByteArray phoneThumbnail = QByteArray::fromBase64(np.get(QStringLiteral("phoneThumbnail"), "")); + const QString messageBody = np.get(QStringLiteral("messageBody"),{}); + + const QString title = device()->name(); + + QString type = QStringLiteral("smsReceived"); + QString icon = QStringLiteral("mail-receive"); + QString content = i18n("SMS from %1
%2", contactName, messageBody); + KNotification::NotificationFlags flags = KNotification::Persistent; //Note that in Unity this generates a message box! + + qCDebug(KDECONNECT_PLUGIN_SMS) << "Creating notification with type:" << type; + + KNotification* notification = new KNotification(type, flags, this); + if (!phoneThumbnail.isEmpty()) { + QPixmap photo; + photo.loadFromData(phoneThumbnail, "JPEG"); + notification->setPixmap(photo); + } else { + notification->setIconName(icon); + } + notification->setComponentName(QStringLiteral("kdeconnect")); + notification->setTitle(title); + notification->setText(content); + + notification->setActions( QStringList(i18n("Reply")) ); + notification->setProperty("phoneNumber", phoneNumber); + notification->setProperty("contactName", contactName); + notification->setProperty("originalMessage", messageBody); + connect(notification, &KNotification::action1Activated, this, &SmsPlugin::showSendSmsDialog); + + return notification; + +} + +void SmsPlugin::sendSms(const QString& phoneNumber, const QString& messageBody) +{ + NetworkPacket np(PACKET_TYPE_SMS_REQUEST, { + {"sendSms", true}, + {"phoneNumber", phoneNumber}, + {"messageBody", messageBody} + }); + qDebug() << "sending sms!"; + sendPacket(np); +} + +void SmsPlugin::showSendSmsDialog() +{ + qCDebug(KDECONNECT_PLUGIN_SMS) << "Show dialog"; + QString phoneNumber = sender()->property("phoneNumber").toString(); + QString contactName = sender()->property("contactName").toString(); + QString originalMessage = sender()->property("originalMessage").toString(); + SendReplyDialog* dialog = new SendReplyDialog(originalMessage, phoneNumber, contactName); + connect(dialog, &SendReplyDialog::sendReply, this, &SmsPlugin::sendSms); + dialog->show(); + dialog->raise(); +} + +void SmsPlugin::requestAllConversations() +{ + NetworkPacket np(PACKET_TYPE_TELEPHONY_REQUEST_CONVERSATIONS); + + sendPacket(np); +} + +void SmsPlugin::requestConversation (const QString& conversationID) const +{ + NetworkPacket np(PACKET_TYPE_TELEPHONY_REQUEST_CONVERSATION); + np.set("threadID", conversationID.toInt()); + + sendPacket(np); +} + +void SmsPlugin::forwardToTelepathy(const ConversationMessage& message) +{ + // If we don't have a valid Telepathy interface, bail out + if (!(m_telepathyInterface.isValid())) return; + + qCDebug(KDECONNECT_PLUGIN_SMS) << "Passing a text message to the telepathy interface"; + connect(&m_telepathyInterface, SIGNAL(messageReceived(QString,QString)), SLOT(sendSms(QString,QString)), Qt::UniqueConnection); + const QString messageBody = message.body(); + const QString contactName; // TODO: When telepathy support is improved, look up the contact with KPeople + const QString phoneNumber = message.address(); + m_telepathyInterface.call(QDBus::NoBlock, QStringLiteral("sendMessage"), phoneNumber, contactName, messageBody); +} + +bool SmsPlugin::handleBatchMessages(const NetworkPacket& np) +{ + const auto messages = np.get("messages"); + + for (const QVariant& body : messages) + { + ConversationMessage message(body.toMap()); + forwardToTelepathy(message); + m_conversationInterface->addMessage(message); + } + + return true; +} + + +QString SmsPlugin::dbusPath() const +{ + return "/modules/kdeconnect/devices/" + device()->id() + "/sms"; +} + +#include "smsplugin.moc" + diff --git a/plugins/sms/smsplugin.h b/plugins/sms/smsplugin.h new file mode 100644 index 000000000..09c3308c4 --- /dev/null +++ b/plugins/sms/smsplugin.h @@ -0,0 +1,135 @@ +/** + * Copyright 2013 Albert Vaca + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SMSPLUGIN_H +#define SMSPLUGIN_H + +#include + +#include + +#include + +#include "conversationsdbusinterface.h" +#include "interfaces/conversationmessage.h" + +#include "sendreplydialog.h" + +#define PACKET_TYPE_TELEPHONY QStringLiteral("kdeconnect.telephony") + +/** + * Packet used to indicate a batch of messages has been pushed from the remote device + * + * The body should contain the key "messages" mapping to an array of messages + * + * For example: + * { "messages" : [ + * { "event" : "sms", + * "messageBody" : "Hello", + * "phoneNumber" : "2021234567", + * "messageDate" : "1518846484880", + * "messageType" : "2", + * "threadID" : "132" + * }, + * { ... }, + * ... + * ] + * } + */ + +#define PACKET_TYPE_TELEPHONY_MESSAGE QStringLiteral("kdeconnect.telephony.message") + +#define PACKET_TYPE_SMS_REQUEST QStringLiteral("kdeconnect.sms.request") + +/** + * Packet sent to request all the most-recent messages in all conversations on the device + * + * The request packet shall contain no body + */ +#define PACKET_TYPE_TELEPHONY_REQUEST_CONVERSATIONS QStringLiteral("kdeconnect.telephony.request_conversations") + +/** + * Packet sent to request all the messages in a particular conversation + * + * The body should contain the key "threadID" mapping to the threadID (as a string) being requested + * For example: + * { "threadID": 203 } + */ +#define PACKET_TYPE_TELEPHONY_REQUEST_CONVERSATION QStringLiteral("kdeconnect.telephony.request_conversation") + +Q_DECLARE_LOGGING_CATEGORY(KDECONNECT_PLUGIN_SMS) + +class Q_DECL_EXPORT SmsPlugin + : public KdeConnectPlugin +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.kde.kdeconnect.device.sms") + +public: + explicit SmsPlugin(QObject* parent, const QVariantList& args); + ~SmsPlugin() override; + + bool receivePacket(const NetworkPacket& np) override; + void connected() override {} + + QString dbusPath() const override; + +public Q_SLOTS: + Q_SCRIPTABLE void sendSms(const QString& phoneNumber, const QString& messageBody); + + /** + * Send a request to the remote for all of its conversations + */ + Q_SCRIPTABLE void requestAllConversations(); + + /** + * Send a request to the remote for a particular conversation + */ + Q_SCRIPTABLE void requestConversation(const QString& conversationID) const; + +private Q_SLOTS: + void showSendSmsDialog(); + +private: + + /** + * Send to the telepathy plugin if it is available + */ + void forwardToTelepathy(const ConversationMessage& message); + + /** + * Create a notification for incoming SMS (with the option to reply) + * This comment is being written while SMS handling is in the process of being improved. + * As such, any code in createNotification which deals with SMS is legacy support + */ + KNotification* createNotification(const NetworkPacket& np); + + /** + * Handle a packet which contains many messages, such as PACKET_TYPE_TELEPHONY_MESSAGE + */ + bool handleBatchMessages(const NetworkPacket& np); + + + QDBusInterface m_telepathyInterface; + ConversationsDbusInterface* m_conversationInterface; + +}; + +#endif diff --git a/plugins/telephony/CMakeLists.txt b/plugins/telephony/CMakeLists.txt index 4c2ec9ed3..4eb34fa17 100644 --- a/plugins/telephony/CMakeLists.txt +++ b/plugins/telephony/CMakeLists.txt @@ -1,19 +1,14 @@ set(kdeconnect_telephony_SRCS telephonyplugin.cpp - conversationsdbusinterface.cpp ) include_directories(${CMAKE_BINARY_DIR}) -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../notifications/) # needed for the sendreplydialog -ki18n_wrap_ui(kdeconnect_telephony_SRCS ../notifications/sendreplydialog.ui) -kdeconnect_add_plugin(kdeconnect_telephony JSON kdeconnect_telephony.json SOURCES ../notifications/sendreplydialog.cpp ${kdeconnect_telephony_SRCS}) +kdeconnect_add_plugin(kdeconnect_telephony JSON kdeconnect_telephony.json SOURCES ${kdeconnect_telephony_SRCS}) target_link_libraries(kdeconnect_telephony kdeconnectcore - kdeconnectinterfaces KF5::I18n KF5::Notifications Qt5::DBus - Qt5::Widgets ) diff --git a/plugins/telephony/kdeconnect_telephony.json b/plugins/telephony/kdeconnect_telephony.json index 70c78d349..b1804af6f 100644 --- a/plugins/telephony/kdeconnect_telephony.json +++ b/plugins/telephony/kdeconnect_telephony.json @@ -89,13 +89,9 @@ "Website": "http://albertvaka.wordpress.com" }, "X-KdeConnect-OutgoingPacketType": [ - "kdeconnect.telephony.request", - "kdeconnect.sms.request", - "kdeconnect.telephony.request_conversations", - "kdeconnect.telephony.request_conversation" + "kdeconnect.telephony.request" ], "X-KdeConnect-SupportedPacketType": [ - "kdeconnect.telephony", - "kdeconnect.telephony.message" + "kdeconnect.telephony" ] } diff --git a/plugins/telephony/telephonyplugin.cpp b/plugins/telephony/telephonyplugin.cpp index 2a5ba4183..63db2c3d9 100644 --- a/plugins/telephony/telephonyplugin.cpp +++ b/plugins/telephony/telephonyplugin.cpp @@ -21,10 +21,6 @@ #include "telephonyplugin.h" -#include "sendreplydialog.h" -#include "conversationsdbusinterface.h" -#include "interfaces/conversationmessage.h" - #include #include #include @@ -38,18 +34,11 @@ Q_LOGGING_CATEGORY(KDECONNECT_PLUGIN_TELEPHONY, "kdeconnect.plugin.telephony") TelephonyPlugin::TelephonyPlugin(QObject* parent, const QVariantList& args) : KdeConnectPlugin(parent, args) - , m_telepathyInterface(QStringLiteral("org.freedesktop.Telepathy.ConnectionManager.kdeconnect"), QStringLiteral("/kdeconnect")) - , m_conversationInterface(new ConversationsDbusInterface(this)) { } TelephonyPlugin::~TelephonyPlugin() { - // FIXME: Same problem as discussed in the BatteryPlugin destructor and for the same reason: - // QtDbus does not allow us to delete m_conversationInterface. If we do so, we get a crash in the - // next DBus access to the parent - - //m_conversationInterface->deleteLater(); } KNotification* TelephonyPlugin::createNotification(const NetworkPacket& np) @@ -60,14 +49,6 @@ KNotification* TelephonyPlugin::createNotification(const NetworkPacket& np) const QByteArray phoneThumbnail = QByteArray::fromBase64(np.get(QStringLiteral("phoneThumbnail"), "")); const QString messageBody = np.get(QStringLiteral("messageBody"),{}); - // In case telepathy can handle the message, don't do anything else - if (event == QLatin1String("sms") && m_telepathyInterface.isValid()) { - // Telepathy has already been tried (in receivePacket) - // There is a chance that it somehow failed, but since nobody uses Telepathy anyway... - // TODO: When upgrading telepathy, handle failure case (in case m_telepathyInterface.call returns false) - return nullptr; - } - QString content, type, icon; KNotification::NotificationFlags flags = KNotification::CloseOnTimeout; @@ -82,12 +63,6 @@ KNotification* TelephonyPlugin::createNotification(const NetworkPacket& np) icon = QStringLiteral("call-start"); content = i18n("Missed call from %1", contactName); flags |= KNotification::Persistent; //Note that in Unity this generates a message box! - } else if (event == QLatin1String("sms")) { - type = QStringLiteral("smsReceived"); - icon = QStringLiteral("mail-receive"); - QString messageBody = np.get(QStringLiteral("messageBody"), QLatin1String("")); - content = i18n("SMS from %1
%2", contactName, messageBody); - flags |= KNotification::Persistent; //Note that in Unity this generates a message box! } else if (event == QLatin1String("talking")) { return nullptr; } else { @@ -117,16 +92,8 @@ KNotification* TelephonyPlugin::createNotification(const NetworkPacket& np) if (event == QLatin1String("ringing")) { notification->setActions( QStringList(i18n("Mute Call")) ); connect(notification, &KNotification::action1Activated, this, &TelephonyPlugin::sendMutePacket); - } else if (event == QLatin1String("sms")) { - notification->setActions( QStringList(i18n("Reply")) ); - notification->setProperty("phoneNumber", phoneNumber); - notification->setProperty("contactName", contactName); - notification->setProperty("originalMessage", messageBody); - connect(notification, &KNotification::action1Activated, this, &TelephonyPlugin::showSendSmsDialog); } - return notification; - } bool TelephonyPlugin::receivePacket(const NetworkPacket& np) @@ -144,21 +111,13 @@ bool TelephonyPlugin::receivePacket(const NetworkPacket& np) { if (event == QLatin1String("sms")) { - // New-style packets should be a PACKET_TYPE_TELEPHONY_MESSAGE (15 May 2018) - qCDebug(KDECONNECT_PLUGIN_TELEPHONY) << "Handled an old-style Telephony sms packet. You should update your Android app to get the latest features!"; - ConversationMessage message(np.body()); - forwardToTelepathy(message); + return false; } KNotification* n = createNotification(np); if (n != nullptr) n->sendEvent(); return true; } - if (np.type() == PACKET_TYPE_TELEPHONY_MESSAGE) - { - return handleBatchMessages(np); - } - return true; } @@ -168,70 +127,6 @@ void TelephonyPlugin::sendMutePacket() sendPacket(packet); } -void TelephonyPlugin::sendSms(const QString& phoneNumber, const QString& messageBody) -{ - NetworkPacket np(PACKET_TYPE_SMS_REQUEST, { - {"sendSms", true}, - {"phoneNumber", phoneNumber}, - {"messageBody", messageBody} - }); - qDebug() << "sending sms!"; - sendPacket(np); -} - -void TelephonyPlugin::showSendSmsDialog() -{ - QString phoneNumber = sender()->property("phoneNumber").toString(); - QString contactName = sender()->property("contactName").toString(); - QString originalMessage = sender()->property("originalMessage").toString(); - SendReplyDialog* dialog = new SendReplyDialog(originalMessage, phoneNumber, contactName); - connect(dialog, &SendReplyDialog::sendReply, this, &TelephonyPlugin::sendSms); - dialog->show(); - dialog->raise(); -} - -void TelephonyPlugin::requestAllConversations() -{ - NetworkPacket np(PACKET_TYPE_TELEPHONY_REQUEST_CONVERSATIONS); - - sendPacket(np); -} - -void TelephonyPlugin::requestConversation (const QString& conversationID) const -{ - NetworkPacket np(PACKET_TYPE_TELEPHONY_REQUEST_CONVERSATION); - np.set("threadID", conversationID.toInt()); - - sendPacket(np); -} - -void TelephonyPlugin::forwardToTelepathy(const ConversationMessage& message) -{ - // In case telepathy can handle the message, don't do anything else - if (m_telepathyInterface.isValid()) { - qCDebug(KDECONNECT_PLUGIN_TELEPHONY) << "Passing a text message to the telepathy interface"; - connect(&m_telepathyInterface, SIGNAL(messageReceived(QString,QString)), SLOT(sendSms(QString,QString)), Qt::UniqueConnection); - const QString messageBody = message.body(); - const QString contactName; // TODO: When telepathy support is improved, look up the contact with KPeople - const QString phoneNumber = message.address(); - m_telepathyInterface.call(QDBus::NoBlock, QStringLiteral("sendMessage"), phoneNumber, contactName, messageBody); - } -} - -bool TelephonyPlugin::handleBatchMessages(const NetworkPacket& np) -{ - const auto messages = np.get("messages"); - - for (const QVariant& body : messages) - { - ConversationMessage message(body.toMap()); - forwardToTelepathy(message); - m_conversationInterface->addMessage(message); - } - - return true; -} - QString TelephonyPlugin::dbusPath() const { return "/modules/kdeconnect/devices/" + device()->id() + "/telephony"; diff --git a/plugins/telephony/telephonyplugin.h b/plugins/telephony/telephonyplugin.h index e5912fbdd..6121a5dcf 100644 --- a/plugins/telephony/telephonyplugin.h +++ b/plugins/telephony/telephonyplugin.h @@ -22,9 +22,6 @@ #ifndef TELEPHONYPLUGIN_H #define TELEPHONYPLUGIN_H -#include "conversationsdbusinterface.h" -#include "interfaces/conversationmessage.h" - #include #include @@ -32,59 +29,18 @@ #include -/** - * Packet used to indicate a batch of messages has been pushed from the remote device - * - * The body should contain the key "messages" mapping to an array of messages - * - * For example: - * { "messages" : [ - * { "event" : "sms", - * "messageBody" : "Hello", - * "phoneNumber" : "2021234567", - * "messageDate" : "1518846484880", - * "messageType" : "2", - * "threadID" : "132" - * }, - * { ... }, - * ... - * ] - * } - */ -#define PACKET_TYPE_TELEPHONY_MESSAGE QStringLiteral("kdeconnect.telephony.message") - /** * Packet used for simple telephony events * * It contains the key "event" which maps to a string indicating the type of event: * - "ringing" - A phone call is incoming * - "missedCall" - An incoming call was not answered - * - "sms" - An incoming SMS message - * - Note: As of this writing (15 May 2018) the SMS interface is being improved and this type of event - * is no longer the preferred way of retrieving SMS. Use PACKET_TYPE_TELEPHONY_MESSAGE instead. * * Depending on the event, other fields may be defined */ #define PACKET_TYPE_TELEPHONY QStringLiteral("kdeconnect.telephony") #define PACKET_TYPE_TELEPHONY_REQUEST QStringLiteral("kdeconnect.telephony.request") -#define PACKET_TYPE_SMS_REQUEST QStringLiteral("kdeconnect.sms.request") - -/** - * Packet sent to request all the most-recent messages in all conversations on the device - * - * The request packet shall contain no body - */ -#define PACKET_TYPE_TELEPHONY_REQUEST_CONVERSATIONS QStringLiteral("kdeconnect.telephony.request_conversations") - -/** - * Packet sent to request all the messages in a particular conversation - * - * The body should contain the key "threadID" mapping to the threadID (as a string) being requested - * For example: - * { "threadID": 203 } - */ -#define PACKET_TYPE_TELEPHONY_REQUEST_CONVERSATION QStringLiteral("kdeconnect.telephony.request_conversation") Q_DECLARE_LOGGING_CATEGORY(KDECONNECT_PLUGIN_TELEPHONY) @@ -102,50 +58,19 @@ public: void connected() override {} QString dbusPath() const override; -public Q_SLOTS: - Q_SCRIPTABLE void sendSms(const QString& phoneNumber, const QString& messageBody); - - /** - * Send a request to the remote for all of its conversations - */ - Q_SCRIPTABLE void requestAllConversations(); - - /** - * Send a request to the remote for a particular conversation - */ - Q_SCRIPTABLE void requestConversation(const QString& conversationID) const; - public: Q_SIGNALS: private Q_SLOTS: void sendMutePacket(); - void showSendSmsDialog(); - -protected: - /** - * Send to the telepathy plugin if it is available - */ - void forwardToTelepathy(const ConversationMessage& message); - - /** - * Handle a packet which contains many messages, such as PACKET_TYPE_TELEPHONY_MESSAGE - */ - bool handleBatchMessages(const NetworkPacket& np); private: /** * Create a notification for: * - Incoming call (with the option to mute the ringing) * - Missed call - * - Incoming SMS (with the option to reply) - * - This comment is being written while SMS handling is in the process of being improved. - * As such, any code in createNotification which deals with SMS is legacy support */ KNotification* createNotification(const NetworkPacket& np); - - QDBusInterface m_telepathyInterface; - ConversationsDbusInterface* m_conversationInterface; }; #endif