Changeset View
Changeset View
Standalone View
Standalone View
plugins/telephony/telephonyplugin.cpp
Show All 15 Lines | |||||
16 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. | ||
17 | * | 17 | * | ||
18 | * 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 | ||
19 | * 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/>. | ||
20 | */ | 20 | */ | ||
21 | 21 | | |||
22 | #include "telephonyplugin.h" | 22 | #include "telephonyplugin.h" | ||
23 | 23 | | |||
24 | #include "sendreplydialog.h" | | |||
25 | #include "conversationsdbusinterface.h" | | |||
26 | #include "interfaces/conversationmessage.h" | | |||
27 | | ||||
28 | #include <KLocalizedString> | 24 | #include <KLocalizedString> | ||
29 | #include <QDebug> | 25 | #include <QDebug> | ||
30 | #include <QDBusReply> | 26 | #include <QDBusReply> | ||
31 | 27 | | |||
32 | #include <KPluginFactory> | 28 | #include <KPluginFactory> | ||
33 | #include <KNotification> | 29 | #include <KNotification> | ||
34 | 30 | | |||
35 | K_PLUGIN_FACTORY_WITH_JSON( KdeConnectPluginFactory, "kdeconnect_telephony.json", registerPlugin< TelephonyPlugin >(); ) | 31 | K_PLUGIN_FACTORY_WITH_JSON( KdeConnectPluginFactory, "kdeconnect_telephony.json", registerPlugin< TelephonyPlugin >(); ) | ||
36 | 32 | | |||
37 | Q_LOGGING_CATEGORY(KDECONNECT_PLUGIN_TELEPHONY, "kdeconnect.plugin.telephony") | 33 | Q_LOGGING_CATEGORY(KDECONNECT_PLUGIN_TELEPHONY, "kdeconnect.plugin.telephony") | ||
38 | 34 | | |||
39 | TelephonyPlugin::TelephonyPlugin(QObject* parent, const QVariantList& args) | 35 | TelephonyPlugin::TelephonyPlugin(QObject* parent, const QVariantList& args) | ||
40 | : KdeConnectPlugin(parent, args) | 36 | : KdeConnectPlugin(parent, args) | ||
41 | , m_telepathyInterface(QStringLiteral("org.freedesktop.Telepathy.ConnectionManager.kdeconnect"), QStringLiteral("/kdeconnect")) | | |||
42 | , m_conversationInterface(new ConversationsDbusInterface(this)) | | |||
43 | { | 37 | { | ||
44 | } | 38 | } | ||
45 | 39 | | |||
46 | TelephonyPlugin::~TelephonyPlugin() | 40 | TelephonyPlugin::~TelephonyPlugin() | ||
47 | { | 41 | { | ||
48 | // FIXME: Same problem as discussed in the BatteryPlugin destructor and for the same reason: | 42 | // 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 | 43 | // 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 | 44 | // next DBus access to the parent | ||
51 | 45 | | |||
52 | //m_conversationInterface->deleteLater(); | 46 | //m_conversationInterface->deleteLater(); | ||
sredman: Needless to say, all of this can be removed since the telephony plugin no longer has a… | |||||
53 | } | 47 | } | ||
54 | 48 | | |||
55 | KNotification* TelephonyPlugin::createNotification(const NetworkPacket& np) | 49 | KNotification* TelephonyPlugin::createNotification(const NetworkPacket& np) | ||
56 | { | 50 | { | ||
57 | const QString event = np.get<QString>(QStringLiteral("event")); | 51 | const QString event = np.get<QString>(QStringLiteral("event")); | ||
58 | const QString phoneNumber = np.get<QString>(QStringLiteral("phoneNumber"), i18n("unknown number")); | 52 | const QString phoneNumber = np.get<QString>(QStringLiteral("phoneNumber"), i18n("unknown number")); | ||
59 | const QString contactName = np.get<QString>(QStringLiteral("contactName"), phoneNumber); | 53 | const QString contactName = np.get<QString>(QStringLiteral("contactName"), phoneNumber); | ||
60 | const QByteArray phoneThumbnail = QByteArray::fromBase64(np.get<QByteArray>(QStringLiteral("phoneThumbnail"), "")); | 54 | const QByteArray phoneThumbnail = QByteArray::fromBase64(np.get<QByteArray>(QStringLiteral("phoneThumbnail"), "")); | ||
61 | const QString messageBody = np.get<QString>(QStringLiteral("messageBody"),{}); | 55 | const QString messageBody = np.get<QString>(QStringLiteral("messageBody"),{}); | ||
62 | 56 | | |||
63 | // In case telepathy can handle the message, don't do anything else | | |||
64 | if (event == QLatin1String("sms") && m_telepathyInterface.isValid()) { | | |||
65 | // Telepathy has already been tried (in receivePacket) | | |||
66 | // There is a chance that it somehow failed, but since nobody uses Telepathy anyway... | | |||
67 | // TODO: When upgrading telepathy, handle failure case (in case m_telepathyInterface.call returns false) | | |||
68 | return nullptr; | | |||
69 | } | | |||
70 | | ||||
71 | QString content, type, icon; | 57 | QString content, type, icon; | ||
72 | KNotification::NotificationFlags flags = KNotification::CloseOnTimeout; | 58 | KNotification::NotificationFlags flags = KNotification::CloseOnTimeout; | ||
73 | 59 | | |||
74 | const QString title = device()->name(); | 60 | const QString title = device()->name(); | ||
75 | 61 | | |||
76 | if (event == QLatin1String("ringing")) { | 62 | if (event == QLatin1String("ringing")) { | ||
77 | type = QStringLiteral("callReceived"); | 63 | type = QStringLiteral("callReceived"); | ||
78 | icon = QStringLiteral("call-start"); | 64 | icon = QStringLiteral("call-start"); | ||
79 | content = i18n("Incoming call from %1", contactName); | 65 | content = i18n("Incoming call from %1", contactName); | ||
80 | } else if (event == QLatin1String("missedCall")) { | 66 | } else if (event == QLatin1String("missedCall")) { | ||
81 | type = QStringLiteral("missedCall"); | 67 | type = QStringLiteral("missedCall"); | ||
82 | icon = QStringLiteral("call-start"); | 68 | icon = QStringLiteral("call-start"); | ||
83 | content = i18n("Missed call from %1", contactName); | 69 | content = i18n("Missed call from %1", contactName); | ||
84 | flags |= KNotification::Persistent; //Note that in Unity this generates a message box! | 70 | flags |= KNotification::Persistent; //Note that in Unity this generates a message box! | ||
85 | } else if (event == QLatin1String("sms")) { | | |||
86 | type = QStringLiteral("smsReceived"); | | |||
87 | icon = QStringLiteral("mail-receive"); | | |||
88 | QString messageBody = np.get<QString>(QStringLiteral("messageBody"), QLatin1String("")); | | |||
89 | content = i18n("SMS from %1<br>%2", contactName, messageBody); | | |||
90 | flags |= KNotification::Persistent; //Note that in Unity this generates a message box! | | |||
91 | } else if (event == QLatin1String("talking")) { | 71 | } else if (event == QLatin1String("talking")) { | ||
92 | return nullptr; | 72 | return nullptr; | ||
93 | } else { | 73 | } else { | ||
94 | #ifndef NDEBUG | 74 | #ifndef NDEBUG | ||
95 | return nullptr; | 75 | return nullptr; | ||
96 | #else | 76 | #else | ||
97 | type = QStringLiteral("callReceived"); | 77 | type = QStringLiteral("callReceived"); | ||
98 | icon = QStringLiteral("phone"); | 78 | icon = QStringLiteral("phone"); | ||
Show All 13 Lines | 80 | #endif | |||
112 | } | 92 | } | ||
113 | notification->setComponentName(QStringLiteral("kdeconnect")); | 93 | notification->setComponentName(QStringLiteral("kdeconnect")); | ||
114 | notification->setTitle(title); | 94 | notification->setTitle(title); | ||
115 | notification->setText(content); | 95 | notification->setText(content); | ||
116 | 96 | | |||
117 | if (event == QLatin1String("ringing")) { | 97 | if (event == QLatin1String("ringing")) { | ||
118 | notification->setActions( QStringList(i18n("Mute Call")) ); | 98 | notification->setActions( QStringList(i18n("Mute Call")) ); | ||
119 | connect(notification, &KNotification::action1Activated, this, &TelephonyPlugin::sendMutePacket); | 99 | connect(notification, &KNotification::action1Activated, this, &TelephonyPlugin::sendMutePacket); | ||
120 | } else if (event == QLatin1String("sms")) { | | |||
121 | notification->setActions( QStringList(i18n("Reply")) ); | | |||
122 | notification->setProperty("phoneNumber", phoneNumber); | | |||
123 | notification->setProperty("contactName", contactName); | | |||
124 | notification->setProperty("originalMessage", messageBody); | | |||
125 | connect(notification, &KNotification::action1Activated, this, &TelephonyPlugin::showSendSmsDialog); | | |||
126 | } | 100 | } | ||
127 | | ||||
128 | return notification; | 101 | return notification; | ||
129 | | ||||
130 | } | 102 | } | ||
131 | 103 | | |||
132 | bool TelephonyPlugin::receivePacket(const NetworkPacket& np) | 104 | bool TelephonyPlugin::receivePacket(const NetworkPacket& np) | ||
133 | { | 105 | { | ||
134 | if (np.get<bool>(QStringLiteral("isCancel"))) { | 106 | if (np.get<bool>(QStringLiteral("isCancel"))) { | ||
135 | 107 | | |||
136 | //TODO: Clear the old notification | 108 | //TODO: Clear the old notification | ||
137 | return true; | 109 | return true; | ||
138 | } | 110 | } | ||
139 | 111 | | |||
140 | const QString& event = np.get<QString>(QStringLiteral("event"), QStringLiteral("unknown")); | 112 | const QString& event = np.get<QString>(QStringLiteral("event"), QStringLiteral("unknown")); | ||
141 | 113 | | |||
142 | // Handle old-style packets | 114 | // Handle old-style packets | ||
143 | if (np.type() == PACKET_TYPE_TELEPHONY) | 115 | if (np.type() == PACKET_TYPE_TELEPHONY) | ||
144 | { | 116 | { | ||
145 | if (event == QLatin1String("sms")) | 117 | if (event == QLatin1String("sms")) | ||
146 | { | 118 | { | ||
147 | // New-style packets should be a PACKET_TYPE_TELEPHONY_MESSAGE (15 May 2018) | 119 | return false; | ||
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()); | | |||
150 | forwardToTelepathy(message); | | |||
151 | } | 120 | } | ||
152 | KNotification* n = createNotification(np); | 121 | KNotification* n = createNotification(np); | ||
153 | if (n != nullptr) n->sendEvent(); | 122 | if (n != nullptr) n->sendEvent(); | ||
154 | return true; | 123 | return true; | ||
155 | } | 124 | } | ||
156 | 125 | | |||
157 | if (np.type() == PACKET_TYPE_TELEPHONY_MESSAGE) | | |||
158 | { | | |||
159 | return handleBatchMessages(np); | | |||
160 | } | | |||
161 | | ||||
162 | return true; | 126 | return true; | ||
163 | } | 127 | } | ||
164 | 128 | | |||
165 | void TelephonyPlugin::sendMutePacket() | 129 | void TelephonyPlugin::sendMutePacket() | ||
166 | { | 130 | { | ||
167 | NetworkPacket packet(PACKET_TYPE_TELEPHONY_REQUEST, {{"action", "mute"}}); | 131 | NetworkPacket packet(PACKET_TYPE_TELEPHONY_REQUEST, {{"action", "mute"}}); | ||
168 | sendPacket(packet); | 132 | sendPacket(packet); | ||
169 | } | 133 | } | ||
170 | 134 | | |||
171 | void TelephonyPlugin::sendSms(const QString& phoneNumber, const QString& messageBody) | | |||
172 | { | | |||
173 | NetworkPacket np(PACKET_TYPE_SMS_REQUEST, { | | |||
174 | {"sendSms", true}, | | |||
175 | {"phoneNumber", phoneNumber}, | | |||
176 | {"messageBody", messageBody} | | |||
177 | }); | | |||
178 | qDebug() << "sending sms!"; | | |||
179 | sendPacket(np); | | |||
180 | } | | |||
181 | | ||||
182 | void TelephonyPlugin::showSendSmsDialog() | | |||
183 | { | | |||
184 | QString phoneNumber = sender()->property("phoneNumber").toString(); | | |||
185 | QString contactName = sender()->property("contactName").toString(); | | |||
186 | QString originalMessage = sender()->property("originalMessage").toString(); | | |||
187 | SendReplyDialog* dialog = new SendReplyDialog(originalMessage, phoneNumber, contactName); | | |||
188 | connect(dialog, &SendReplyDialog::sendReply, this, &TelephonyPlugin::sendSms); | | |||
189 | dialog->show(); | | |||
190 | dialog->raise(); | | |||
191 | } | | |||
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); | | |||
206 | } | | |||
207 | | ||||
208 | void TelephonyPlugin::forwardToTelepathy(const ConversationMessage& message) | | |||
209 | { | | |||
210 | // In case telepathy can handle the message, don't do anything else | | |||
211 | if (m_telepathyInterface.isValid()) { | | |||
This check should either be brought back within this method or bumped outside in all uses sredman: This check should either be brought back within this method or bumped outside in all uses | |||||
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); | | |||
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 | { | | |||
223 | const auto messages = np.get<QVariantList>("messages"); | | |||
224 | | ||||
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 | | ||||
235 | QString TelephonyPlugin::dbusPath() const | 135 | QString TelephonyPlugin::dbusPath() const | ||
236 | { | 136 | { | ||
237 | return "/modules/kdeconnect/devices/" + device()->id() + "/telephony"; | 137 | return "/modules/kdeconnect/devices/" + device()->id() + "/telephony"; | ||
238 | } | 138 | } | ||
239 | 139 | | |||
240 | #include "telephonyplugin.moc" | 140 | #include "telephonyplugin.moc" |
Needless to say, all of this can be removed since the telephony plugin no longer has a conversation interface