Changeset View
Standalone View
plugins/telephony/telephonyplugin.cpp
1 | /** | 1 | /** | ||
---|---|---|---|---|---|
2 | * Copyright 2013 Albert Vaca <albertvaka@gmail.com> | 2 | * Copyright 2013 Albert Vaca <albertvaka@gmail.com> | ||
3 | * Copyright 2018 Simon Redman <simon@ergotech.com> | ||||
3 | * | 4 | * | ||
4 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License as | 6 | * modify it under the terms of the GNU General Public License as | ||
6 | * published by the Free Software Foundation; either version 2 of | 7 | * published by the Free Software Foundation; either version 2 of | ||
7 | * the License or (at your option) version 3 or any later version | 8 | * the License or (at your option) version 3 or any later version | ||
8 | * accepted by the membership of KDE e.V. (or its successor approved | 9 | * accepted by the membership of KDE e.V. (or its successor approved | ||
9 | * by the membership of KDE e.V.), which shall act as a proxy | 10 | * by the membership of KDE e.V.), which shall act as a proxy | ||
10 | * defined in Section 14 of version 3 of the license. | 11 | * defined in Section 14 of version 3 of the license. | ||
11 | * | 12 | * | ||
12 | * This program is distributed in the hope that it will be useful, | 13 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. | ||
16 | * | 17 | * | ||
17 | * You should have received a copy of the GNU General Public License | 18 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 19 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
19 | */ | 20 | */ | ||
20 | 21 | | |||
21 | #include "telephonyplugin.h" | 22 | #include "telephonyplugin.h" | ||
22 | 23 | | |||
23 | #include "sendreplydialog.h" | 24 | #include "sendreplydialog.h" | ||
25 | #include "conversationsdbusinterface.h" | ||||
26 | #include "interfaces/conversationmessage.h" | ||||
24 | 27 | | |||
25 | #include <KLocalizedString> | 28 | #include <KLocalizedString> | ||
26 | #include <QIcon> | | |||
27 | #include <QDebug> | 29 | #include <QDebug> | ||
28 | #include <QDBusReply> | 30 | #include <QDBusReply> | ||
29 | 31 | | |||
30 | #include <KPluginFactory> | 32 | #include <KPluginFactory> | ||
33 | #include <KNotification> | ||||
31 | 34 | | |||
32 | K_PLUGIN_FACTORY_WITH_JSON( KdeConnectPluginFactory, "kdeconnect_telephony.json", registerPlugin< TelephonyPlugin >(); ) | 35 | K_PLUGIN_FACTORY_WITH_JSON( KdeConnectPluginFactory, "kdeconnect_telephony.json", registerPlugin< TelephonyPlugin >(); ) | ||
33 | 36 | | |||
34 | Q_LOGGING_CATEGORY(KDECONNECT_PLUGIN_TELEPHONY, "kdeconnect.plugin.telephony") | 37 | Q_LOGGING_CATEGORY(KDECONNECT_PLUGIN_TELEPHONY, "kdeconnect.plugin.telephony") | ||
35 | 38 | | |||
36 | TelephonyPlugin::TelephonyPlugin(QObject* parent, const QVariantList& args) | 39 | TelephonyPlugin::TelephonyPlugin(QObject* parent, const QVariantList& args) | ||
37 | : KdeConnectPlugin(parent, args) | 40 | : KdeConnectPlugin(parent, args) | ||
38 | , m_telepathyInterface(QStringLiteral("org.freedesktop.Telepathy.ConnectionManager.kdeconnect"), QStringLiteral("/kdeconnect")) | 41 | , m_telepathyInterface(QStringLiteral("org.freedesktop.Telepathy.ConnectionManager.kdeconnect"), QStringLiteral("/kdeconnect")) | ||
42 | , m_conversationInterface(new ConversationsDbusInterface(this)) | ||||
39 | { | 43 | { | ||
40 | } | 44 | } | ||
41 | 45 | | |||
46 | TelephonyPlugin::~TelephonyPlugin() | ||||
47 | { | ||||
48 | // FIXME: Same problem as discussed in the BatteryPlugin destructor and for the same reason: | ||||
49 | // QtDbus does not allow us to delete m_conversationInterface. If we do so, we get a crash in the | ||||
50 | // next DBus access to the parent | ||||
51 | | ||||
52 | //m_conversationInterface->deleteLater(); | ||||
53 | } | ||||
54 | | ||||
42 | KNotification* TelephonyPlugin::createNotification(const NetworkPacket& np) | 55 | KNotification* TelephonyPlugin::createNotification(const NetworkPacket& np) | ||
43 | { | 56 | { | ||
44 | const QString event = np.get<QString>(QStringLiteral("event")); | 57 | const QString event = np.get<QString>(QStringLiteral("event")); | ||
45 | const QString phoneNumber = np.get<QString>(QStringLiteral("phoneNumber"), i18n("unknown number")); | 58 | const QString phoneNumber = np.get<QString>(QStringLiteral("phoneNumber"), i18n("unknown number")); | ||
46 | const QString contactName = np.get<QString>(QStringLiteral("contactName"), phoneNumber); | 59 | const QString contactName = np.get<QString>(QStringLiteral("contactName"), phoneNumber); | ||
47 | const QByteArray phoneThumbnail = QByteArray::fromBase64(np.get<QByteArray>(QStringLiteral("phoneThumbnail"), "")); | 60 | const QByteArray phoneThumbnail = QByteArray::fromBase64(np.get<QByteArray>(QStringLiteral("phoneThumbnail"), "")); | ||
61 | const QString messageBody = np.get<QString>(QStringLiteral("messageBody"),{}); | ||||
apol: Instead of passing "" or QLatin1String(""), pass `QString()` or even `{}`. | |||||
48 | 62 | | |||
49 | // In case telepathy can handle the message, don't do anything else | 63 | // In case telepathy can handle the message, don't do anything else | ||
50 | if (event == QLatin1String("sms") && m_telepathyInterface.isValid()) { | 64 | if (event == QLatin1String("sms") && m_telepathyInterface.isValid()) { | ||
51 | qCDebug(KDECONNECT_PLUGIN_TELEPHONY) << "Passing a text message to the telepathy interface"; | 65 | // Telepathy has already been tried (in receivePacket) | ||
apol: Shouldn't this be `!m_telepathyInterface.isValid()`? | |||||
No, this is handling the case where the telepathy interface was valid. If the message has been passed to telepathy, it does not keep trying to process it using a notification sredman: No, this is handling the case where the telepathy interface was valid. If the message has been… | |||||
52 | connect(&m_telepathyInterface, SIGNAL(messageReceived(QString,QString)), SLOT(sendSms(QString,QString)), Qt::UniqueConnection); | 66 | // There is a chance that it somehow failed, but since nobody uses Telepathy anyway... | ||
53 | const QString messageBody = np.get<QString>(QStringLiteral("messageBody"),QLatin1String("")); | 67 | // TODO: When upgrading telepathy, handle failure case (in case m_telepathyInterface.call returns false) | ||
54 | QDBusReply<bool> reply = m_telepathyInterface.call(QStringLiteral("sendMessage"), phoneNumber, contactName, messageBody); | | |||
55 | if (reply) { | | |||
56 | return nullptr; | 68 | return nullptr; | ||
57 | } else { | | |||
58 | qCDebug(KDECONNECT_PLUGIN_TELEPHONY) << "Telepathy failed, falling back to the default handling"; | | |||
59 | } | | |||
60 | } | 69 | } | ||
61 | 70 | | |||
62 | QString content, type, icon; | 71 | QString content, type, icon; | ||
63 | KNotification::NotificationFlags flags = KNotification::CloseOnTimeout; | 72 | KNotification::NotificationFlags flags = KNotification::CloseOnTimeout; | ||
64 | 73 | | |||
65 | const QString title = device()->name(); | 74 | const QString title = device()->name(); | ||
66 | 75 | | |||
67 | if (event == QLatin1String("ringing")) { | 76 | if (event == QLatin1String("ringing")) { | ||
Show All 36 Lines | 100 | #endif | |||
104 | notification->setComponentName(QStringLiteral("kdeconnect")); | 113 | notification->setComponentName(QStringLiteral("kdeconnect")); | ||
105 | notification->setTitle(title); | 114 | notification->setTitle(title); | ||
106 | notification->setText(content); | 115 | notification->setText(content); | ||
107 | 116 | | |||
108 | if (event == QLatin1String("ringing")) { | 117 | if (event == QLatin1String("ringing")) { | ||
109 | notification->setActions( QStringList(i18n("Mute Call")) ); | 118 | notification->setActions( QStringList(i18n("Mute Call")) ); | ||
110 | connect(notification, &KNotification::action1Activated, this, &TelephonyPlugin::sendMutePacket); | 119 | connect(notification, &KNotification::action1Activated, this, &TelephonyPlugin::sendMutePacket); | ||
111 | } else if (event == QLatin1String("sms")) { | 120 | } else if (event == QLatin1String("sms")) { | ||
112 | const QString messageBody = np.get<QString>(QStringLiteral("messageBody"),QLatin1String("")); | | |||
113 | notification->setActions( QStringList(i18n("Reply")) ); | 121 | notification->setActions( QStringList(i18n("Reply")) ); | ||
114 | notification->setProperty("phoneNumber", phoneNumber); | 122 | notification->setProperty("phoneNumber", phoneNumber); | ||
115 | notification->setProperty("contactName", contactName); | 123 | notification->setProperty("contactName", contactName); | ||
116 | notification->setProperty("originalMessage", messageBody); | 124 | notification->setProperty("originalMessage", messageBody); | ||
117 | connect(notification, &KNotification::action1Activated, this, &TelephonyPlugin::showSendSmsDialog); | 125 | connect(notification, &KNotification::action1Activated, this, &TelephonyPlugin::showSendSmsDialog); | ||
118 | } | 126 | } | ||
119 | 127 | | |||
120 | return notification; | 128 | return notification; | ||
121 | 129 | | |||
122 | } | 130 | } | ||
123 | 131 | | |||
124 | bool TelephonyPlugin::receivePacket(const NetworkPacket& np) | 132 | bool TelephonyPlugin::receivePacket(const NetworkPacket& np) | ||
125 | { | 133 | { | ||
126 | if (np.get<bool>(QStringLiteral("isCancel"))) { | 134 | if (np.get<bool>(QStringLiteral("isCancel"))) { | ||
127 | 135 | | |||
128 | //TODO: Clear the old notification | 136 | //TODO: Clear the old notification | ||
129 | return true; | 137 | return true; | ||
130 | } | 138 | } | ||
131 | 139 | | |||
140 | const QString& event = np.get<QString>(QStringLiteral("event"), QStringLiteral("unknown")); | ||||
141 | | ||||
142 | // Handle old-style packets | ||||
143 | if (np.type() == PACKET_TYPE_TELEPHONY) | ||||
144 | { | ||||
145 | if (event == QLatin1String("sms")) | ||||
146 | { | ||||
nicolasfella: "->this" is weird, never seen it in a KDE Project | |||||
147 | // New-style packets should be a PACKET_TYPE_TELEPHONY_MESSAGE (15 May 2018) | ||||
148 | qCDebug(KDECONNECT_PLUGIN_TELEPHONY) << "Handled an old-style Telephony sms packet. You should update your Android app to get the latest features!"; | ||||
149 | ConversationMessage message(np.body()); | ||||
nicolasfella: Else if? | |||||
At this revision I hadn't figured out what to do with old-style packets. I have decided to support them fully (meaning old Android apps would continue to function as they currently do) and return at the end of the if block. Does this work for you? sredman: At this revision I hadn't figured out what to do with old-style packets. I have decided to… | |||||
150 | forwardToTelepathy(message); | ||||
151 | } | ||||
132 | KNotification* n = createNotification(np); | 152 | KNotification* n = createNotification(np); | ||
133 | if (n != nullptr) n->sendEvent(); | 153 | if (n != nullptr) n->sendEvent(); | ||
154 | return true; | ||||
155 | } | ||||
156 | | ||||
157 | if (np.type() == PACKET_TYPE_TELEPHONY_MESSAGE) | ||||
158 | { | ||||
159 | return handleBatchMessages(np); | ||||
160 | } | ||||
134 | 161 | | |||
135 | return true; | 162 | return true; | ||
136 | } | 163 | } | ||
137 | 164 | | |||
138 | void TelephonyPlugin::sendMutePacket() | 165 | void TelephonyPlugin::sendMutePacket() | ||
139 | { | 166 | { | ||
140 | NetworkPacket packet(PACKET_TYPE_TELEPHONY_REQUEST, {{"action", "mute"}}); | 167 | NetworkPacket packet(PACKET_TYPE_TELEPHONY_REQUEST, {{"action", "mute"}}); | ||
141 | sendPacket(packet); | 168 | sendPacket(packet); | ||
Show All 16 Lines | 183 | { | |||
158 | QString contactName = sender()->property("contactName").toString(); | 185 | QString contactName = sender()->property("contactName").toString(); | ||
159 | QString originalMessage = sender()->property("originalMessage").toString(); | 186 | QString originalMessage = sender()->property("originalMessage").toString(); | ||
160 | SendReplyDialog* dialog = new SendReplyDialog(originalMessage, phoneNumber, contactName); | 187 | SendReplyDialog* dialog = new SendReplyDialog(originalMessage, phoneNumber, contactName); | ||
161 | connect(dialog, &SendReplyDialog::sendReply, this, &TelephonyPlugin::sendSms); | 188 | connect(dialog, &SendReplyDialog::sendReply, this, &TelephonyPlugin::sendSms); | ||
162 | dialog->show(); | 189 | dialog->show(); | ||
163 | dialog->raise(); | 190 | dialog->raise(); | ||
164 | } | 191 | } | ||
165 | 192 | | |||
193 | void TelephonyPlugin::requestAllConversations() | ||||
194 | { | ||||
195 | NetworkPacket np(PACKET_TYPE_TELEPHONY_REQUEST_CONVERSATIONS); | ||||
196 | | ||||
197 | sendPacket(np); | ||||
198 | } | ||||
199 | | ||||
200 | void TelephonyPlugin::requestConversation (const QString& conversationID) const | ||||
201 | { | ||||
202 | NetworkPacket np(PACKET_TYPE_TELEPHONY_REQUEST_CONVERSATION); | ||||
203 | np.set("threadID", conversationID.toInt()); | ||||
204 | | ||||
205 | sendPacket(np); | ||||
nicolasfella: Use new syntax if possible | |||||
The messageReceived method being used as the sender of this connection is on the other side of the DBus interface (telepathy-kdeconnect/connection.h line 55). I don't know how or if the new syntax can be used in this case sredman: The messageReceived method being used as the sender of this connection is on the other side of… | |||||
206 | } | ||||
207 | | ||||
apol: Shouldn't initialize if it's empty. | |||||
208 | void TelephonyPlugin::forwardToTelepathy(const ConversationMessage& message) | ||||
209 | { | ||||
210 | // In case telepathy can handle the message, don't do anything else | ||||
return reply? apol: `return reply`?
Actually nobody seems to be reading the result of `forwardToTelepathy`, you can… | |||||
211 | if (m_telepathyInterface.isValid()) { | ||||
212 | qCDebug(KDECONNECT_PLUGIN_TELEPHONY) << "Passing a text message to the telepathy interface"; | ||||
213 | connect(&m_telepathyInterface, SIGNAL(messageReceived(QString,QString)), SLOT(sendSms(QString,QString)), Qt::UniqueConnection); | ||||
nicolasfella: returning false here is not necessary | |||||
214 | const QString messageBody = message.body(); | ||||
215 | const QString contactName; // TODO: When telepathy support is improved, look up the contact with KPeople | ||||
216 | const QString phoneNumber = message.address(); | ||||
217 | m_telepathyInterface.call(QDBus::NoBlock, QStringLiteral("sendMessage"), phoneNumber, contactName, messageBody); | ||||
218 | } | ||||
219 | } | ||||
220 | | ||||
221 | bool TelephonyPlugin::handleBatchMessages(const NetworkPacket& np) | ||||
222 | { | ||||
apol: const | |||||
223 | const auto messages = np.get<QVariantList>("messages"); | ||||
224 | | ||||
apol: const QVariant & | |||||
225 | for (const QVariant& body : messages) | ||||
226 | { | ||||
227 | ConversationMessage message(body.toMap()); | ||||
228 | forwardToTelepathy(message); | ||||
229 | m_conversationInterface->addMessage(message); | ||||
230 | } | ||||
231 | | ||||
232 | return true; | ||||
233 | } | ||||
234 | | ||||
166 | QString TelephonyPlugin::dbusPath() const | 235 | QString TelephonyPlugin::dbusPath() const | ||
167 | { | 236 | { | ||
168 | return "/modules/kdeconnect/devices/" + device()->id() + "/telephony"; | 237 | return "/modules/kdeconnect/devices/" + device()->id() + "/telephony"; | ||
169 | } | 238 | } | ||
170 | 239 | | |||
171 | #include "telephonyplugin.moc" | 240 | #include "telephonyplugin.moc" |
Instead of passing "" or QLatin1String(""), pass QString() or even {}.