Merge lp:~phablet-team/telephony-service/async_send_message into lp:telephony-service
- async_send_message
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~phablet-team/telephony-service/async_send_message |
Merge into: | lp:telephony-service |
Diff against target: |
2249 lines (+1179/-423) 31 files modified
.bzrignore (+1/-0) approver/TelephonyServiceApprover.client (+0/-1) approver/approver.cpp (+5/-3) handler/CMakeLists.txt (+3/-0) handler/Handler.xml (+3/-12) handler/TelephonyServiceHandler.client (+2/-7) handler/chatstartingjob.cpp (+149/-0) handler/chatstartingjob.h (+64/-0) handler/handlerdbus.cpp (+25/-10) handler/handlerdbus.h (+8/-4) handler/main.cpp (+1/-3) handler/messagejob.cpp (+82/-0) handler/messagejob.h (+68/-0) handler/messagesendingjob.cpp (+375/-0) handler/messagesendingjob.h (+87/-0) handler/texthandler.cpp (+53/-331) handler/texthandler.h (+7/-18) indicator/TelephonyServiceIndicator.client (+0/-5) indicator/textchannelobserver.cpp (+7/-2) libtelephonyservice/accountentry.cpp (+33/-0) libtelephonyservice/accountentry.h (+16/-0) libtelephonyservice/chatentry.cpp (+64/-1) libtelephonyservice/chatentry.h (+14/-0) libtelephonyservice/chatmanager.cpp (+58/-14) libtelephonyservice/chatmanager.h (+2/-3) libtelephonyservice/telepathyhelper.cpp (+12/-0) libtelephonyservice/telepathyhelper.h (+9/-0) tests/common/mock/connection.cpp (+7/-1) tests/handler/handlercontroller.cpp (+9/-2) tests/libtelephonyservice/ChatEntryTest.cpp (+4/-2) tests/libtelephonyservice/ChatManagerTest.cpp (+11/-4) |
To merge this branch: | bzr merge lp:~phablet-team/telephony-service/async_send_message |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu Phablet Team | Pending | ||
Review via email: mp+295528@code.launchpad.net |
This proposal has been superseded by a proposal from 2016-05-24.
Commit message
Make it possible to send messages asynchronously and still report the results.
Description of the change
Make it possible to send messages asynchronously and still report the results.
- 1204. By Gustavo Pichorim Boiko
-
Fix some problems, remove some code not needed anymore and add some debug.
- 1205. By Gustavo Pichorim Boiko
-
Remove empty spaces.
- 1206. By Gustavo Pichorim Boiko
-
Change ChatEntry to fetch channels from ChatManager and to send messages using the new asynchronous API.
- 1207. By Gustavo Pichorim Boiko
-
Merge parent branch
- 1208. By Gustavo Pichorim Boiko
-
Implement channel matching.
- 1209. By Gustavo Pichorim Boiko
-
Expose the chatentry to QML.
- 1210. By Gustavo Pichorim Boiko
-
Make it possible to set the chat type
- 1211. By Gustavo Pichorim Boiko
-
Finish implementing the message sending job and make use of it in chatentry.
- 1212. By Gustavo Pichorim Boiko
-
Watch for new channels.
- 1213. By Gustavo Pichorim Boiko
-
Do not pass the interface when registering the jobs, it is already present in
the adaptor. - 1214. By Gustavo Pichorim Boiko
-
Start chat with accounts that might have typing notifications.
- 1215. By Gustavo Pichorim Boiko
-
Ignore message sending job adaptor.
- 1216. By Gustavo Pichorim Boiko
-
Fix ChatManager tests.
- 1217. By Gustavo Pichorim Boiko
-
Fix handler tests
- 1218. By Gustavo Pichorim Boiko
-
Set also the threadId in properties so that the channel gets
created correctly. - 1219. By Gustavo Pichorim Boiko
-
If no accountId is given, match channels from all accounts.
- 1220. By Gustavo Pichorim Boiko
-
Only set the accountId in properties if we are trying to match a chatroom
- 1221. By Gustavo Pichorim Boiko
-
We don't need to verify accounts here, it is done in a later stage if needed
- 1222. By Gustavo Pichorim Boiko
-
merge parent
- 1223. By Gustavo Pichorim Boiko
-
Do not delete the interface classes. They are destroyed together with the channel itself.
- 1224. By Gustavo Pichorim Boiko
-
Update copyright headers.
- 1225. By Gustavo Pichorim Boiko
-
Merge parent
- 1226. By Gustavo Pichorim Boiko
-
Expose chatstarting to dbus
- 1227. By Gustavo Pichorim Boiko
-
Make startChat return the job's objectPath
- 1228. By Gustavo Pichorim Boiko
-
Remove wrongly committed changelog.
- 1229. By Tiago Salem Herrmann
-
merge parent branch
- 1230. By Tiago Salem Herrmann
-
merge parent branch
- 1231. By Tiago Salem Herrmann
-
merge parent branch
- 1232. By Gustavo Pichorim Boiko
-
Handle channel invalidation.
- 1233. By Tiago Salem Herrmann
-
merge parent branch
- 1234. By Tiago Salem Herrmann
-
merge parent branch
- 1235. By Tiago Salem Herrmann
-
merge parent branch
- 1236. By Tiago Salem Herrmann
-
merge parent branch
- 1237. By Tiago Salem Herrmann
-
fix handler test
- 1238. By Tiago Salem Herrmann
-
merge parent branch
- 1239. By Tiago Salem Herrmann
-
merge parent branch
- 1240. By Gustavo Pichorim Boiko
-
Add a FIXME on a disabled test
- 1241. By Gustavo Pichorim Boiko
-
Merge parent
Unmerged revisions
Preview Diff
1 | === modified file '.bzrignore' |
2 | --- .bzrignore 2015-07-02 03:35:20 +0000 |
3 | +++ .bzrignore 2016-05-24 01:13:17 +0000 |
4 | @@ -57,3 +57,4 @@ |
5 | tests/libtelephonyservice/GreeterContactsTestExe |
6 | tests/libtelephonyservice/GreeterContactsTestServerExe |
7 | tests/libtelephonyservice/*Mock |
8 | +tests/indicator/NotificationsInterface.* |
9 | |
10 | === modified file 'approver/TelephonyServiceApprover.client' |
11 | --- approver/TelephonyServiceApprover.client 2013-07-17 17:50:32 +0000 |
12 | +++ approver/TelephonyServiceApprover.client 2016-05-24 01:13:17 +0000 |
13 | @@ -8,7 +8,6 @@ |
14 | |
15 | [org.freedesktop.Telepathy.Client.Approver.ApproverChannelFilter 1] |
16 | org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Text |
17 | -org.freedesktop.Telepathy.Channel.TargetHandleType u=1 |
18 | |
19 | [org.freedesktop.Telepathy.Client.Approver.Capabilities] |
20 | org.freedesktop.Telepathy.Channel.Type.Call1/audio=true |
21 | |
22 | === modified file 'approver/approver.cpp' |
23 | --- approver/approver.cpp 2016-01-05 17:14:32 +0000 |
24 | +++ approver/approver.cpp 2016-05-24 01:13:17 +0000 |
25 | @@ -412,10 +412,12 @@ |
26 | void Approver::onRejectMessage(Tp::ChannelDispatchOperationPtr dispatchOp, const char *action) |
27 | { |
28 | if (mRejectActions.contains(action)) { |
29 | - QString targetId = dispatchOp->channels().first()->targetContact()->id(); |
30 | + QVariantMap properties; |
31 | + properties["participantIds"] = QStringList() << dispatchOp->channels().first()->targetContact()->id(); |
32 | ChatManager::instance()->sendMessage(dispatchOp->account()->uniqueIdentifier(), |
33 | - QStringList() << targetId, |
34 | - mRejectActions[action]); |
35 | + mRejectActions[action], |
36 | + QVariantMap(), // attachments |
37 | + properties); |
38 | } |
39 | |
40 | onRejected(dispatchOp); |
41 | |
42 | === modified file 'handler/CMakeLists.txt' |
43 | --- handler/CMakeLists.txt 2016-03-18 19:02:50 +0000 |
44 | +++ handler/CMakeLists.txt 2016-05-24 01:13:17 +0000 |
45 | @@ -1,8 +1,11 @@ |
46 | |
47 | set(qt_SRCS |
48 | callhandler.cpp |
49 | + chatstartingjob.cpp |
50 | handler.cpp |
51 | handlerdbus.cpp |
52 | + messagejob.cpp |
53 | + messagesendingjob.cpp |
54 | texthandler.cpp |
55 | ) |
56 | |
57 | |
58 | === modified file 'handler/Handler.xml' |
59 | --- handler/Handler.xml 2015-12-07 16:26:20 +0000 |
60 | +++ handler/Handler.xml 2016-05-24 01:13:17 +0000 |
61 | @@ -16,13 +16,12 @@ |
62 | Request to send a message to one or multiple recipients |
63 | ]]></dox:d> |
64 | <arg name="accountId" type="s" direction="in"/> |
65 | - <arg name="recipients" type="as" direction="in"/> |
66 | <arg name="message" type="s" direction="in"/> |
67 | <arg name="attachments" type="a(sss)" direction="in"/> |
68 | <arg name="accountIdOut" type="s" direction="out"/> |
69 | - <annotation name="org.qtproject.QtDBus.QtTypeName.In3" value="AttachmentList"/> |
70 | + <annotation name="org.qtproject.QtDBus.QtTypeName.In2" value="AttachmentList"/> |
71 | <arg name="properties" type="a{sv}" direction="in"/> |
72 | - <annotation name="org.qtproject.QtDBus.QtTypeName.In4" value="QVariantMap"/> |
73 | + <annotation name="org.qtproject.QtDBus.QtTypeName.In3" value="QVariantMap"/> |
74 | </method> |
75 | <method name="AcknowledgeMessages"> |
76 | <dox:d><![CDATA[ |
77 | @@ -37,16 +36,8 @@ |
78 | Start a chat with the given participants |
79 | ]]></dox:d> |
80 | <arg name="accountId" type="s" direction="in"/> |
81 | - <arg name="participants" type="as" direction="in"/> |
82 | - </method> |
83 | - <method name="StartChatRoom"> |
84 | - <dox:d><![CDATA[ |
85 | - Start a chat room with the given properties |
86 | - ]]></dox:d> |
87 | - <arg name="accountId" type="s" direction="in"/> |
88 | - <arg name="initialParticipants" type="as" direction="in"/> |
89 | <arg name="properties" type="a{sv}" direction="in"/> |
90 | - <annotation name="org.qtproject.QtDBus.QtTypeName.In2" value="QVariantMap"/> |
91 | + <annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="QVariantMap"/> |
92 | </method> |
93 | <method name="AcknowledgeAllMessages"> |
94 | <dox:d><![CDATA[ |
95 | |
96 | === modified file 'handler/TelephonyServiceHandler.client' |
97 | --- handler/TelephonyServiceHandler.client 2014-11-19 17:39:57 +0000 |
98 | +++ handler/TelephonyServiceHandler.client 2016-05-24 01:13:17 +0000 |
99 | @@ -3,11 +3,6 @@ |
100 | |
101 | [org.freedesktop.Telepathy.Client.Handler.HandlerChannelFilter 0] |
102 | org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Text |
103 | -org.freedesktop.Telepathy.Channel.TargetHandleType u=1 |
104 | - |
105 | -[org.freedesktop.Telepathy.Client.Handler.HandlerChannelFilter 1] |
106 | -org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Text |
107 | -org.freedesktop.Telepathy.Channel.TargetHandleType u=0 |
108 | - |
109 | -[org.freedesktop.Telepathy.Client.Handler.HandlerChannelFilter 2] |
110 | + |
111 | +[org.freedesktop.Telepathy.Client.Handler.HandlerChannelFilter 3] |
112 | org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Call1 |
113 | |
114 | === added file 'handler/chatstartingjob.cpp' |
115 | --- handler/chatstartingjob.cpp 1970-01-01 00:00:00 +0000 |
116 | +++ handler/chatstartingjob.cpp 2016-05-24 01:13:17 +0000 |
117 | @@ -0,0 +1,149 @@ |
118 | +/* |
119 | + * Copyright (C) 2016 Canonical, Ltd. |
120 | + * |
121 | + * Authors: |
122 | + * Tiago Salem Herrmann <tiago.herrmann@canonical.com> |
123 | + * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com> |
124 | + * |
125 | + * This file is part of telephony-service. |
126 | + * |
127 | + * telephony-service is free software; you can redistribute it and/or modify |
128 | + * it under the terms of the GNU General Public License as published by |
129 | + * the Free Software Foundation; version 3. |
130 | + * |
131 | + * telephony-service is distributed in the hope that it will be useful, |
132 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
133 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
134 | + * GNU General Public License for more details. |
135 | + * |
136 | + * You should have received a copy of the GNU General Public License |
137 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
138 | + */ |
139 | + |
140 | +#include "chatstartingjob.h" |
141 | +#include "telepathyhelper.h" |
142 | +#include "texthandler.h" |
143 | +#include <TelepathyQt/PendingChannelRequest> |
144 | + |
145 | +ChatStartingJob::ChatStartingJob(TextHandler *textHandler, const QString &accountId, const QVariantMap &properties) |
146 | +: MessageJob(textHandler), mAccountId(accountId), mProperties(properties) |
147 | +{ |
148 | +} |
149 | + |
150 | +void ChatStartingJob::startJob() |
151 | +{ |
152 | + setStatus(Running); |
153 | + |
154 | + // Request the contact to start chatting to |
155 | + // FIXME: make it possible to select which account to use, for now, pick the first one |
156 | + AccountEntry *account = TelepathyHelper::instance()->accountForId(mAccountId); |
157 | + if (!account || !account->connected()) { |
158 | + qCritical() << "The selected account does not have a connection. AccountId:" << mAccountId; |
159 | + setStatus(Failed); |
160 | + scheduleDeletion(); |
161 | + return; |
162 | + } |
163 | + |
164 | + switch(mProperties["chatType"].toUInt()) { |
165 | + case Tp::HandleTypeNone: |
166 | + case Tp::HandleTypeContact: |
167 | + startTextChat(account->account(), mProperties); |
168 | + break; |
169 | + case Tp::HandleTypeRoom: |
170 | + startTextChatRoom(account->account(), mProperties); |
171 | + break; |
172 | + default: |
173 | + qCritical() << "Chat type not supported"; |
174 | + } |
175 | +} |
176 | + |
177 | +void ChatStartingJob::startTextChat(const Tp::AccountPtr &account, const QVariantMap &properties) |
178 | +{ |
179 | + Tp::PendingChannelRequest *op = NULL; |
180 | + QStringList participants = properties["participantIds"].toStringList(); |
181 | + switch(participants.size()) { |
182 | + case 0: |
183 | + qCritical() << "Error: No participant list provided"; |
184 | + return; |
185 | + case 1: |
186 | + op = account->ensureTextChat(participants[0], QDateTime::currentDateTime(), TP_QT_IFACE_CLIENT + ".TelephonyServiceHandler"); |
187 | + break; |
188 | + default: |
189 | + op = account->createConferenceTextChat(QList<Tp::ChannelPtr>(), participants, QDateTime::currentDateTime(), TP_QT_IFACE_CLIENT + ".TelephonyServiceHandler"); |
190 | + } |
191 | + |
192 | + if (!op) { |
193 | + setStatus(Failed); |
194 | + scheduleDeletion(); |
195 | + return; |
196 | + } |
197 | + |
198 | + connect(op, &Tp::PendingOperation::finished, |
199 | + this, &ChatStartingJob::onChannelRequestFinished); |
200 | +} |
201 | + |
202 | +void ChatStartingJob::startTextChatRoom(const Tp::AccountPtr &account, const QVariantMap &properties) |
203 | +{ |
204 | + QString roomName = properties["threadId"].toString(); |
205 | + |
206 | + // these properties are still not used |
207 | + //QString server = properties["Server"].toString(); |
208 | + //QString creator = properties["Creator"].toString(); |
209 | + |
210 | + QVariantMap request; |
211 | + Tp::PendingChannelRequest *op = NULL; |
212 | + if (roomName.isEmpty()) { |
213 | + request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_TEXT); |
214 | + request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) Tp::HandleTypeNone); |
215 | + QStringList initialInviteeIDs = properties["participantIds"].toStringList(); |
216 | + if (!initialInviteeIDs.isEmpty()) { |
217 | + request.insert(TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialInviteeIDs"), initialInviteeIDs); |
218 | + } |
219 | + // the presence of RoomName indicates the returned channel must be of type Room |
220 | + request.insert(TP_QT_IFACE_CHANNEL_INTERFACE_ROOM + QLatin1String(".RoomName"), QString()); |
221 | + |
222 | + // TODO use the instance returned by createChanne() to track when the channel creation is finished |
223 | + op = account->createChannel(request, QDateTime::currentDateTime(), TP_QT_IFACE_CLIENT + ".TelephonyServiceHandler"); |
224 | + } else { |
225 | + op = account->ensureTextChatroom(roomName, QDateTime::currentDateTime(), TP_QT_IFACE_CLIENT + ".TelephonyServiceHandler", request); |
226 | + } |
227 | + |
228 | + if (!op) { |
229 | + setStatus(Failed); |
230 | + scheduleDeletion(); |
231 | + return; |
232 | + } |
233 | + connect(op, &Tp::PendingOperation::finished, |
234 | + this, &ChatStartingJob::onChannelRequestFinished); |
235 | +} |
236 | + |
237 | +Tp::TextChannelPtr ChatStartingJob::textChannel() const |
238 | +{ |
239 | + return mTextChannel; |
240 | +} |
241 | + |
242 | +void ChatStartingJob::setTextChannel(Tp::TextChannelPtr channel) |
243 | +{ |
244 | + mTextChannel = channel; |
245 | + Q_EMIT textChannelChanged(); |
246 | +} |
247 | + |
248 | +void ChatStartingJob::onChannelRequestFinished(Tp::PendingOperation *op) |
249 | +{ |
250 | + Status status; |
251 | + if (op->isError()) { |
252 | + status = Failed; |
253 | + } else { |
254 | + Tp::PendingChannelRequest *channelRequest = qobject_cast<Tp::PendingChannelRequest*>(op); |
255 | + if (!channelRequest) { |
256 | + status = Failed; |
257 | + } else { |
258 | + setTextChannel(Tp::TextChannelPtr::dynamicCast(channelRequest->channelRequest()->channel())); |
259 | + status = Finished; |
260 | + } |
261 | + } |
262 | + |
263 | + setStatus(status); |
264 | + scheduleDeletion(); |
265 | +} |
266 | + |
267 | |
268 | === added file 'handler/chatstartingjob.h' |
269 | --- handler/chatstartingjob.h 1970-01-01 00:00:00 +0000 |
270 | +++ handler/chatstartingjob.h 2016-05-24 01:13:17 +0000 |
271 | @@ -0,0 +1,64 @@ |
272 | +/* |
273 | + * Copyright (C) 2016 Canonical, Ltd. |
274 | + * |
275 | + * Authors: |
276 | + * Tiago Salem Herrmann <tiago.herrmann@canonical.com> |
277 | + * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com> |
278 | + * |
279 | + * This file is part of telephony-service. |
280 | + * |
281 | + * telephony-service is free software; you can redistribute it and/or modify |
282 | + * it under the terms of the GNU General Public License as published by |
283 | + * the Free Software Foundation; version 3. |
284 | + * |
285 | + * telephony-service is distributed in the hope that it will be useful, |
286 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
287 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
288 | + * GNU General Public License for more details. |
289 | + * |
290 | + * You should have received a copy of the GNU General Public License |
291 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
292 | + */ |
293 | + |
294 | +#ifndef CHATSTARTINGJOB_H |
295 | +#define CHATSTARTINGJOB_H |
296 | + |
297 | +#include <QObject> |
298 | +#include "messagejob.h" |
299 | +#include <TelepathyQt/Types> |
300 | +#include <TelepathyQt/PendingOperation> |
301 | + |
302 | +class TextHandler; |
303 | + |
304 | +class ChatStartingJob : public MessageJob |
305 | +{ |
306 | + Q_OBJECT |
307 | + Q_PROPERTY(Tp::TextChannelPtr textChannel READ textChannel NOTIFY textChannelChanged) |
308 | +public: |
309 | + ChatStartingJob(TextHandler *textHandler, const QString &accountId, const QVariantMap &properties); |
310 | + |
311 | + Tp::TextChannelPtr textChannel() const; |
312 | + |
313 | +public Q_SLOTS: |
314 | + virtual void startJob(); |
315 | + |
316 | +Q_SIGNALS: |
317 | + void textChannelChanged(); |
318 | + |
319 | + |
320 | +protected Q_SLOTS: |
321 | + void startTextChat(const Tp::AccountPtr &account, const QVariantMap &properties); |
322 | + void startTextChatRoom(const Tp::AccountPtr &account, const QVariantMap &properties); |
323 | + void setTextChannel(Tp::TextChannelPtr channel); |
324 | + |
325 | + void onChannelRequestFinished(Tp::PendingOperation *op); |
326 | + |
327 | +private: |
328 | + TextHandler *mTextHandler; |
329 | + QString mAccountId; |
330 | + QVariantMap mProperties; |
331 | + Tp::TextChannelPtr mTextChannel; |
332 | + |
333 | +}; |
334 | + |
335 | +#endif // CHATSTARTINGJOB_H |
336 | |
337 | === modified file 'handler/handlerdbus.cpp' |
338 | --- handler/handlerdbus.cpp 2015-12-07 16:26:20 +0000 |
339 | +++ handler/handlerdbus.cpp 2016-05-24 01:13:17 +0000 |
340 | @@ -81,6 +81,26 @@ |
341 | Q_EMIT CallIndicatorVisibleChanged(visible); |
342 | } |
343 | |
344 | +QString HandlerDBus::registerObject(QObject *object, const QString &path) |
345 | +{ |
346 | + QString fullPath = QString("%1/%2").arg(DBUS_OBJECT_PATH, path); |
347 | + if (QDBusConnection::sessionBus().registerObject(fullPath, object)) { |
348 | + return fullPath; |
349 | + } |
350 | + return QString::null; |
351 | +} |
352 | + |
353 | +void HandlerDBus::unregisterObject(const QString &path) |
354 | +{ |
355 | + QDBusConnection::sessionBus().unregisterObject(path); |
356 | +} |
357 | + |
358 | +HandlerDBus *HandlerDBus::instance() |
359 | +{ |
360 | + static HandlerDBus *self = new HandlerDBus; |
361 | + return self; |
362 | +} |
363 | + |
364 | bool HandlerDBus::connectToBus() |
365 | { |
366 | bool ok = QDBusConnection::sessionBus().registerService(DBUS_SERVICE); |
367 | @@ -93,9 +113,9 @@ |
368 | return true; |
369 | } |
370 | |
371 | -QString HandlerDBus::SendMessage(const QString &accountId, const QStringList &recipients, const QString &message, const AttachmentList &attachments, const QVariantMap &properties) |
372 | +QString HandlerDBus::SendMessage(const QString &accountId, const QString &message, const AttachmentList &attachments, const QVariantMap &properties) |
373 | { |
374 | - return TextHandler::instance()->sendMessage(accountId, recipients, message, attachments, properties); |
375 | + return TextHandler::instance()->sendMessage(accountId, message, attachments, properties); |
376 | } |
377 | |
378 | void HandlerDBus::AcknowledgeMessages(const QStringList &numbers, const QStringList &messageIds, const QString &accountId) |
379 | @@ -103,14 +123,9 @@ |
380 | TextHandler::instance()->acknowledgeMessages(numbers, messageIds, accountId); |
381 | } |
382 | |
383 | -void HandlerDBus::StartChat(const QString &accountId, const QStringList &participants) |
384 | -{ |
385 | - TextHandler::instance()->startChat(participants, accountId); |
386 | -} |
387 | - |
388 | -void HandlerDBus::StartChatRoom(const QString &accountId, const QStringList &initialParticipants, const QVariantMap &properties) |
389 | -{ |
390 | - TextHandler::instance()->startChatRoom(accountId, initialParticipants, properties); |
391 | +void HandlerDBus::StartChat(const QString &accountId, const QVariantMap &properties) |
392 | +{ |
393 | + TextHandler::instance()->startChat(accountId, properties); |
394 | } |
395 | |
396 | void HandlerDBus::AcknowledgeAllMessages(const QStringList &numbers, const QString &accountId) |
397 | |
398 | === modified file 'handler/handlerdbus.h' |
399 | --- handler/handlerdbus.h 2015-12-07 16:26:20 +0000 |
400 | +++ handler/handlerdbus.h 2016-05-24 01:13:17 +0000 |
401 | @@ -30,7 +30,7 @@ |
402 | #include "dbustypes.h" |
403 | |
404 | /** |
405 | - * DBus interface for the phone approver |
406 | + * DBus interface for the phone handler |
407 | */ |
408 | class HandlerDBus : public QObject, protected QDBusContext |
409 | { |
410 | @@ -51,14 +51,18 @@ |
411 | bool callIndicatorVisible() const; |
412 | void setCallIndicatorVisible(bool visible); |
413 | |
414 | + QString registerObject(QObject *object, const QString &path); |
415 | + void unregisterObject(const QString &path); |
416 | + |
417 | + static HandlerDBus *instance(); |
418 | + |
419 | public Q_SLOTS: |
420 | bool connectToBus(); |
421 | |
422 | // messages related |
423 | - QString SendMessage(const QString &accountId, const QStringList &recipients, const QString &message, const AttachmentList &attachments, const QVariantMap &properties); |
424 | + QString SendMessage(const QString &accountId, const QString &message, const AttachmentList &attachments, const QVariantMap &properties); |
425 | Q_NOREPLY void AcknowledgeMessages(const QStringList &numbers, const QStringList &messageIds, const QString &accountId); |
426 | - Q_NOREPLY void StartChat(const QString &accountId, const QStringList &participants); |
427 | - Q_NOREPLY void StartChatRoom(const QString &accountId, const QStringList &initialParticipants, const QVariantMap &properties); |
428 | + Q_NOREPLY void StartChat(const QString &accountId, const QVariantMap &properties); |
429 | Q_NOREPLY void AcknowledgeAllMessages(const QStringList &numbers, const QString &accountId); |
430 | |
431 | // call related |
432 | |
433 | === modified file 'handler/main.cpp' |
434 | --- handler/main.cpp 2016-03-18 19:02:50 +0000 |
435 | +++ handler/main.cpp 2016-05-24 01:13:17 +0000 |
436 | @@ -54,10 +54,8 @@ |
437 | QObject::connect(handler, SIGNAL(textChannelAvailable(Tp::TextChannelPtr)), |
438 | TextHandler::instance(), SLOT(onTextChannelAvailable(Tp::TextChannelPtr))); |
439 | |
440 | - HandlerDBus dbus; |
441 | - |
442 | QObject::connect(TelepathyHelper::instance(), SIGNAL(setupReady()), |
443 | - &dbus, SLOT(connectToBus())); |
444 | + HandlerDBus::instance(), SLOT(connectToBus())); |
445 | |
446 | return app.exec(); |
447 | } |
448 | |
449 | === added file 'handler/messagejob.cpp' |
450 | --- handler/messagejob.cpp 1970-01-01 00:00:00 +0000 |
451 | +++ handler/messagejob.cpp 2016-05-24 01:13:17 +0000 |
452 | @@ -0,0 +1,82 @@ |
453 | +/* |
454 | + * Copyright (C) 2016 Canonical, Ltd. |
455 | + * |
456 | + * Authors: |
457 | + * Tiago Salem Herrmann <tiago.herrmann@canonical.com> |
458 | + * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com> |
459 | + * |
460 | + * This file is part of telephony-service. |
461 | + * |
462 | + * telephony-service is free software; you can redistribute it and/or modify |
463 | + * it under the terms of the GNU General Public License as published by |
464 | + * the Free Software Foundation; version 3. |
465 | + * |
466 | + * telephony-service is distributed in the hope that it will be useful, |
467 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
468 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
469 | + * GNU General Public License for more details. |
470 | + * |
471 | + * You should have received a copy of the GNU General Public License |
472 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
473 | + */ |
474 | + |
475 | +#include "messagejob.h" |
476 | +#include <QCoreApplication> |
477 | +#include <QTime> |
478 | +#include <QTimer> |
479 | + |
480 | +MessageJob::MessageJob(QObject *parent) |
481 | +: QObject(parent), mStatus(Pending), mFinished(false) |
482 | +{ |
483 | +} |
484 | + |
485 | +MessageJob::~MessageJob() |
486 | +{ |
487 | +} |
488 | + |
489 | +MessageJob::Status MessageJob::status() const |
490 | +{ |
491 | + return mStatus; |
492 | +} |
493 | + |
494 | +bool MessageJob::isFinished() const |
495 | +{ |
496 | + return mFinished; |
497 | +} |
498 | + |
499 | +void MessageJob::waitForFinished(int timeout) |
500 | +{ |
501 | + QTime time; |
502 | + time.start(); |
503 | + while (!mFinished && time.elapsed() < timeout) { |
504 | + QCoreApplication::processEvents(); |
505 | + } |
506 | +} |
507 | + |
508 | +void MessageJob::startJob() |
509 | +{ |
510 | + // the default implementation just sets the status to Finished |
511 | + setStatus(Finished); |
512 | +} |
513 | + |
514 | +void MessageJob::setStatus(MessageJob::Status status) |
515 | +{ |
516 | + mStatus = status; |
517 | + Q_EMIT statusChanged(); |
518 | + |
519 | + // update the isFinished property too |
520 | + bool wasFinished = mFinished; |
521 | + mFinished = mStatus == Finished || mStatus == Failed; |
522 | + if (wasFinished != mFinished) { |
523 | + Q_EMIT isFinishedChanged(); |
524 | + } |
525 | + if (mFinished) { |
526 | + Q_EMIT finished(); |
527 | + } |
528 | +} |
529 | + |
530 | +void MessageJob::scheduleDeletion(int timeout) |
531 | +{ |
532 | + QTimer::singleShot(timeout, this, &QObject::deleteLater); |
533 | +} |
534 | + |
535 | |
536 | === added file 'handler/messagejob.h' |
537 | --- handler/messagejob.h 1970-01-01 00:00:00 +0000 |
538 | +++ handler/messagejob.h 2016-05-24 01:13:17 +0000 |
539 | @@ -0,0 +1,68 @@ |
540 | +/* |
541 | + * Copyright (C) 2016 Canonical, Ltd. |
542 | + * |
543 | + * Authors: |
544 | + * Tiago Salem Herrmann <tiago.herrmann@canonical.com> |
545 | + * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com> |
546 | + * |
547 | + * This file is part of telephony-service. |
548 | + * |
549 | + * telephony-service is free software; you can redistribute it and/or modify |
550 | + * it under the terms of the GNU General Public License as published by |
551 | + * the Free Software Foundation; version 3. |
552 | + * |
553 | + * telephony-service is distributed in the hope that it will be useful, |
554 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
555 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
556 | + * GNU General Public License for more details. |
557 | + * |
558 | + * You should have received a copy of the GNU General Public License |
559 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
560 | + */ |
561 | + |
562 | +#ifndef MESSAGEJOB_H |
563 | +#define MESSAGEJOB_H |
564 | + |
565 | +#include <QObject> |
566 | + |
567 | +class MessageJob : public QObject |
568 | +{ |
569 | + Q_OBJECT |
570 | + Q_PROPERTY(Status status READ status NOTIFY statusChanged) |
571 | + Q_PROPERTY(bool isFinished READ isFinished NOTIFY isFinishedChanged) |
572 | + Q_ENUMS(Status) |
573 | +public: |
574 | + enum Status { |
575 | + Pending, |
576 | + Initialising, |
577 | + Running, |
578 | + Finished, |
579 | + Failed |
580 | + }; |
581 | + |
582 | + explicit MessageJob(QObject *parent = 0); |
583 | + virtual ~MessageJob(); |
584 | + |
585 | + Status status() const; |
586 | + bool isFinished() const; |
587 | + |
588 | + void waitForFinished(int timeout = 10000); |
589 | + |
590 | +Q_SIGNALS: |
591 | + void statusChanged(); |
592 | + void isFinishedChanged(); |
593 | + void finished(); |
594 | + |
595 | +public Q_SLOTS: |
596 | + virtual void startJob(); |
597 | + |
598 | +protected: |
599 | + void setStatus(Status status); |
600 | + void scheduleDeletion(int timeout = 60000); |
601 | + |
602 | +private: |
603 | + Status mStatus; |
604 | + bool mFinished; |
605 | +}; |
606 | + |
607 | +#endif // MESSAGEJOB_H |
608 | |
609 | === added file 'handler/messagesendingjob.cpp' |
610 | --- handler/messagesendingjob.cpp 1970-01-01 00:00:00 +0000 |
611 | +++ handler/messagesendingjob.cpp 2016-05-24 01:13:17 +0000 |
612 | @@ -0,0 +1,375 @@ |
613 | +/* |
614 | + * Copyright (C) 2016 Canonical, Ltd. |
615 | + * |
616 | + * Authors: |
617 | + * Tiago Salem Herrmann <tiago.herrmann@canonical.com> |
618 | + * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com> |
619 | + * |
620 | + * This file is part of telephony-service. |
621 | + * |
622 | + * telephony-service is free software; you can redistribute it and/or modify |
623 | + * it under the terms of the GNU General Public License as published by |
624 | + * the Free Software Foundation; version 3. |
625 | + * |
626 | + * telephony-service is distributed in the hope that it will be useful, |
627 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
628 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
629 | + * GNU General Public License for more details. |
630 | + * |
631 | + * You should have received a copy of the GNU General Public License |
632 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
633 | + */ |
634 | + |
635 | +#include "accountentry.h" |
636 | +#include "chatstartingjob.h" |
637 | +#include "handlerdbus.h" |
638 | +#include "messagesendingjob.h" |
639 | +#include "telepathyhelper.h" |
640 | +#include "texthandler.h" |
641 | +#include <TelepathyQt/ContactManager> |
642 | +#include <TelepathyQt/PendingContacts> |
643 | +#include <QImage> |
644 | + |
645 | +#define SMIL_TEXT_REGION "<region id=\"Text\" width=\"100%\" height=\"100%\" fit=\"scroll\" />" |
646 | +#define SMIL_IMAGE_REGION "<region id=\"Image\" width=\"100%\" height=\"100%\" fit=\"meet\" />" |
647 | +#define SMIL_VIDEO_REGION "<region id=\"Video\" width=\"100%\" height=\"100%\" fit=\"meet\" />" |
648 | +#define SMIL_AUDIO_REGION "<region id=\"Audio\" width=\"100%\" height=\"100%\" fit=\"meet\" />" |
649 | +#define SMIL_TEXT_PART "<par dur=\"3s\">\ |
650 | + <text src=\"cid:%1\" region=\"Text\" />\ |
651 | + </par>" |
652 | +#define SMIL_IMAGE_PART "<par dur=\"5000ms\">\ |
653 | + <img src=\"cid:%1\" region=\"Image\" />\ |
654 | + </par>" |
655 | +#define SMIL_VIDEO_PART "<par>\ |
656 | + <video src=\"cid:%1\" region=\"Video\" />\ |
657 | + </par>" |
658 | +#define SMIL_AUDIO_PART "<par>\ |
659 | + <audio src=\"cid:%1\" region=\"Audio\" />\ |
660 | + </par>" |
661 | + |
662 | +#define SMIL_FILE "<smil>\ |
663 | + <head>\ |
664 | + <layout>\ |
665 | + %1\ |
666 | + </layout>\ |
667 | + </head>\ |
668 | + <body>\ |
669 | + %2\ |
670 | + </body>\ |
671 | + </smil>" |
672 | + |
673 | +MessageSendingJob::MessageSendingJob(TextHandler *textHandler, PendingMessage message) |
674 | +: MessageJob(textHandler), mMessage(message), mFinished(false) |
675 | +{ |
676 | + static ulong count = 0; |
677 | + // just to avoid overflowing |
678 | + if (count == ULONG_MAX) { |
679 | + count = 0; |
680 | + } |
681 | + mObjectPath = HandlerDBus::instance()->registerObject(this, QString("messagesendingjob%1").arg(count++)); |
682 | +} |
683 | + |
684 | +MessageSendingJob::~MessageSendingJob() |
685 | +{ |
686 | + HandlerDBus::instance()->unregisterObject(mObjectPath); |
687 | +} |
688 | + |
689 | +QString MessageSendingJob::accountId() const |
690 | +{ |
691 | + return mAccountId; |
692 | +} |
693 | + |
694 | +QString MessageSendingJob::channelObjectPath() const |
695 | +{ |
696 | + return mChannelObjectPath; |
697 | +} |
698 | + |
699 | +QString MessageSendingJob::objectPath() const |
700 | +{ |
701 | + return mObjectPath; |
702 | +} |
703 | + |
704 | +void MessageSendingJob::startJob() |
705 | +{ |
706 | + qDebug() << "Getting account for id:" << mMessage.accountId; |
707 | + AccountEntry *account = TelepathyHelper::instance()->accountForId(mMessage.accountId); |
708 | + if (!account) { |
709 | + setStatus(Failed); |
710 | + scheduleDeletion(); |
711 | + } |
712 | + |
713 | + setStatus(Running); |
714 | + |
715 | + // check if the message should be sent via multimedia account |
716 | + // we just use fallback to 1-1 chats |
717 | + if (account->type() == AccountEntry::PhoneAccount) { |
718 | + Q_FOREACH(AccountEntry *newAccount, TelepathyHelper::instance()->accounts()) { |
719 | + // TODO: we have to find the multimedia account that matches the same phone number, |
720 | + // but for now we just pick any multimedia connected account |
721 | + if (newAccount->type() != AccountEntry::MultimediaAccount) { |
722 | + continue; |
723 | + } |
724 | + // FIXME: the fallback implementation needs to be changed to use protocol info and create a map of |
725 | + // accounts. Also, it needs to check connection capabilities to determine if we can send message |
726 | + // to offline contacts. |
727 | + bool shouldFallback = true; |
728 | + // if the account is offline, dont fallback to this account |
729 | + if (!newAccount->connected()) { |
730 | + continue; |
731 | + } |
732 | + QList<Tp::TextChannelPtr> channels = mTextHandler->existingChannels(newAccount->accountId(), mMessage.properties); |
733 | + // check if we have a channel for this contact already and get the contact pointer from there, |
734 | + // this way we avoid doing the while(op->isFinished()) all the time |
735 | + if (!channels.isEmpty()) { |
736 | + // FIXME: we need to re-evaluate the rules to fallback |
737 | + // if the contact is known, force fallback to this account |
738 | + Q_FOREACH(const Tp::ContactPtr &contact, channels.first()->groupContacts(false)) { |
739 | + Tp::Presence presence = contact->presence(); |
740 | + shouldFallback = (presence.type() == Tp::ConnectionPresenceTypeAvailable || |
741 | + presence.type() == Tp::ConnectionPresenceTypeOffline); |
742 | + if (!shouldFallback) { |
743 | + break; |
744 | + } |
745 | + } |
746 | + } else { |
747 | + QStringList participantIds = mMessage.properties["participantIds"].toStringList(); |
748 | + Tp::PendingContacts *op = newAccount->account()->connection()->contactManager()->contactsForIdentifiers(participantIds); |
749 | + while (!op->isFinished()) { |
750 | + qApp->processEvents(); |
751 | + } |
752 | + Q_FOREACH(const Tp::ContactPtr &contact, op->contacts()) { |
753 | + Tp::Presence presence = contact->presence(); |
754 | + shouldFallback = (presence.type() == Tp::ConnectionPresenceTypeAvailable || |
755 | + presence.type() == Tp::ConnectionPresenceTypeOffline); |
756 | + if (!shouldFallback) { |
757 | + break; |
758 | + } |
759 | + } |
760 | + } |
761 | + if (shouldFallback) { |
762 | + account = newAccount; |
763 | + break; |
764 | + } |
765 | + } |
766 | + } |
767 | + |
768 | + // save the account |
769 | + mAccount = account; |
770 | + setAccountId(mAccount->accountId()); |
771 | + |
772 | + if (!account->connected()) { |
773 | + connect(account, &AccountEntry::connectedChanged, [this, account]() { |
774 | + if (account->connected()) { |
775 | + findOrCreateChannel(); |
776 | + } |
777 | + }); |
778 | + return; |
779 | + } |
780 | + |
781 | + findOrCreateChannel(); |
782 | +} |
783 | + |
784 | +void MessageSendingJob::findOrCreateChannel() |
785 | +{ |
786 | + // now that we know what account to use, find existing channels or request a new one |
787 | + QList<Tp::TextChannelPtr> channels = mTextHandler->existingChannels(mAccount->accountId(), mMessage.properties); |
788 | + if (channels.isEmpty()) { |
789 | + ChatStartingJob *job = new ChatStartingJob(mTextHandler, mAccount->accountId(), mMessage.properties); |
790 | + connect(job, &MessageJob::finished, [this, job]() { |
791 | + if (job->status() == MessageJob::Failed) { |
792 | + setStatus(Failed); |
793 | + scheduleDeletion(); |
794 | + return; |
795 | + } |
796 | + |
797 | + mTextChannel = job->textChannel(); |
798 | + sendMessage(); |
799 | + }); |
800 | + job->startJob(); |
801 | + } |
802 | + |
803 | + mTextChannel = channels.last(); |
804 | + sendMessage(); |
805 | +} |
806 | + |
807 | +void MessageSendingJob::sendMessage() |
808 | +{ |
809 | + Tp::PendingSendMessage *op = mTextChannel->send(buildMessage(mMessage)); |
810 | + connect(op, &Tp::PendingOperation::finished, [this, op]() { |
811 | + if (op->isError()) { |
812 | + setStatus(Failed); |
813 | + scheduleDeletion(); |
814 | + return; |
815 | + } |
816 | + |
817 | + setChannelObjectPath(mTextChannel->objectPath()); |
818 | + setStatus(Finished); |
819 | + scheduleDeletion(); |
820 | + }); |
821 | +} |
822 | + |
823 | +void MessageSendingJob::setAccountId(const QString &accountId) |
824 | +{ |
825 | + mAccountId = accountId; |
826 | + Q_EMIT accountIdChanged(); |
827 | +} |
828 | + |
829 | +void MessageSendingJob::setChannelObjectPath(const QString &objectPath) |
830 | +{ |
831 | + mChannelObjectPath = objectPath; |
832 | + Q_EMIT channelObjectPathChanged(); |
833 | +} |
834 | + |
835 | +Tp::MessagePartList MessageSendingJob::buildMessage(const PendingMessage &pendingMessage) |
836 | +{ |
837 | + Tp::MessagePartList message; |
838 | + Tp::MessagePart header; |
839 | + QString smil, regions, parts; |
840 | + bool hasImage = false, hasText = false, hasVideo = false, hasAudio = false, isMMS = false; |
841 | + |
842 | + AccountEntry *account = TelepathyHelper::instance()->accountForId(pendingMessage.accountId); |
843 | + if (!account) { |
844 | + // account does not exist |
845 | + return Tp::MessagePartList(); |
846 | + } |
847 | + |
848 | + bool temporaryFiles = (pendingMessage.properties.contains("x-canonical-tmp-files") && |
849 | + pendingMessage.properties["x-canonical-tmp-files"].toBool()); |
850 | + |
851 | + // add the remaining properties to the message header |
852 | + QVariantMap::const_iterator it = pendingMessage.properties.begin(); |
853 | + for (; it != pendingMessage.properties.end(); ++it) { |
854 | + header[it.key()] = QDBusVariant(it.value()); |
855 | + } |
856 | + |
857 | + // check if this message should be sent as an MMS |
858 | + if (account->type() == AccountEntry::PhoneAccount) { |
859 | + isMMS = (pendingMessage.attachments.size() > 0 || |
860 | + (header.contains("x-canonical-mms") && header["x-canonical-mms"].variant().toBool()) || |
861 | + (pendingMessage.properties["participantIds"].toStringList().size() > 1 && TelepathyHelper::instance()->mmsGroupChat())); |
862 | + if (isMMS) { |
863 | + header["x-canonical-mms"] = QDBusVariant(true); |
864 | + } |
865 | + } |
866 | + |
867 | + // this flag should not be in the message header, it's only useful for the handler |
868 | + header.remove("x-canonical-tmp-files"); |
869 | + header.remove("chatType"); |
870 | + header.remove("threadId"); |
871 | + header.remove("participantIds"); |
872 | + |
873 | + header["message-type"] = QDBusVariant(0); |
874 | + message << header; |
875 | + |
876 | + // convert AttachmentList struct into telepathy Message parts |
877 | + Q_FOREACH(const AttachmentStruct &attachment, pendingMessage.attachments) { |
878 | + QByteArray fileData; |
879 | + QString newFilePath = QString(attachment.filePath).replace("file://", ""); |
880 | + QFile attachmentFile(newFilePath); |
881 | + if (!attachmentFile.open(QIODevice::ReadOnly)) { |
882 | + qWarning() << "fail to load attachment" << attachmentFile.errorString() << attachment.filePath; |
883 | + continue; |
884 | + } |
885 | + if (attachment.contentType.startsWith("image/")) { |
886 | + if (isMMS) { |
887 | + hasImage = true; |
888 | + parts += QString(SMIL_IMAGE_PART).arg(attachment.id); |
889 | + // check if we need to reduce de image size in case it's bigger than 300k |
890 | + // this check is only valid for MMS |
891 | + if (attachmentFile.size() > 307200) { |
892 | + QImage scaledImage(newFilePath); |
893 | + if (!scaledImage.isNull()) { |
894 | + QBuffer buffer(&fileData); |
895 | + buffer.open(QIODevice::WriteOnly); |
896 | + scaledImage.scaled(640, 640, Qt::KeepAspectRatio, Qt::SmoothTransformation).save(&buffer, "jpg"); |
897 | + } |
898 | + } else { |
899 | + fileData = attachmentFile.readAll(); |
900 | + } |
901 | + } |
902 | + } else if (attachment.contentType.startsWith("video/")) { |
903 | + if (isMMS) { |
904 | + hasVideo = true; |
905 | + parts += QString(SMIL_VIDEO_PART).arg(attachment.id); |
906 | + } |
907 | + } else if (attachment.contentType.startsWith("audio/")) { |
908 | + if (isMMS) { |
909 | + hasAudio = true; |
910 | + parts += QString(SMIL_AUDIO_PART).arg(attachment.id); |
911 | + } |
912 | + } else if (attachment.contentType.startsWith("text/plain")) { |
913 | + if (isMMS) { |
914 | + hasText = true; |
915 | + parts += QString(SMIL_TEXT_PART).arg(attachment.id); |
916 | + } |
917 | + } else if (attachment.contentType.startsWith("text/vcard") || |
918 | + attachment.contentType.startsWith("text/x-vcard")) { |
919 | + } else if (isMMS) { |
920 | + // for MMS we just support the contentTypes above |
921 | + if (temporaryFiles) { |
922 | + attachmentFile.remove(); |
923 | + } |
924 | + continue; |
925 | + } |
926 | + |
927 | + if (fileData.isEmpty()) { |
928 | + fileData = attachmentFile.readAll(); |
929 | + } |
930 | + |
931 | + if (temporaryFiles) { |
932 | + attachmentFile.remove(); |
933 | + } |
934 | + |
935 | + if (hasVideo) { |
936 | + regions += QString(SMIL_VIDEO_REGION); |
937 | + } |
938 | + |
939 | + if (hasAudio) { |
940 | + regions += QString(SMIL_AUDIO_REGION); |
941 | + } |
942 | + |
943 | + if (hasText) { |
944 | + regions += QString(SMIL_TEXT_REGION); |
945 | + } |
946 | + if (hasImage) { |
947 | + regions += QString(SMIL_IMAGE_REGION); |
948 | + } |
949 | + |
950 | + Tp::MessagePart part; |
951 | + part["content-type"] = QDBusVariant(attachment.contentType); |
952 | + part["identifier"] = QDBusVariant(attachment.id); |
953 | + part["content"] = QDBusVariant(fileData); |
954 | + part["size"] = QDBusVariant(fileData.size()); |
955 | + |
956 | + message << part; |
957 | + } |
958 | + |
959 | + if (!pendingMessage.message.isEmpty()) { |
960 | + Tp::MessagePart part; |
961 | + QString tmpTextId("text_0.txt"); |
962 | + part["content-type"] = QDBusVariant(QString("text/plain")); |
963 | + part["identifier"] = QDBusVariant(tmpTextId); |
964 | + part["content"] = QDBusVariant(pendingMessage.message); |
965 | + part["size"] = QDBusVariant(pendingMessage.message.size()); |
966 | + if (isMMS) { |
967 | + parts += QString(SMIL_TEXT_PART).arg(tmpTextId); |
968 | + regions += QString(SMIL_TEXT_REGION); |
969 | + } |
970 | + message << part; |
971 | + } |
972 | + |
973 | + if (isMMS) { |
974 | + Tp::MessagePart smilPart; |
975 | + smil = QString(SMIL_FILE).arg(regions).arg(parts); |
976 | + smilPart["content-type"] = QDBusVariant(QString("application/smil")); |
977 | + smilPart["identifier"] = QDBusVariant(QString("smil.xml")); |
978 | + smilPart["content"] = QDBusVariant(smil); |
979 | + smilPart["size"] = QDBusVariant(smil.size()); |
980 | + |
981 | + message << smilPart; |
982 | + } |
983 | + |
984 | + return message; |
985 | +} |
986 | + |
987 | + |
988 | |
989 | === added file 'handler/messagesendingjob.h' |
990 | --- handler/messagesendingjob.h 1970-01-01 00:00:00 +0000 |
991 | +++ handler/messagesendingjob.h 2016-05-24 01:13:17 +0000 |
992 | @@ -0,0 +1,87 @@ |
993 | +/* |
994 | + * Copyright (C) 2016 Canonical, Ltd. |
995 | + * |
996 | + * Authors: |
997 | + * Tiago Salem Herrmann <tiago.herrmann@canonical.com> |
998 | + * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com> |
999 | + * |
1000 | + * This file is part of telephony-service. |
1001 | + * |
1002 | + * telephony-service is free software; you can redistribute it and/or modify |
1003 | + * it under the terms of the GNU General Public License as published by |
1004 | + * the Free Software Foundation; version 3. |
1005 | + * |
1006 | + * telephony-service is distributed in the hope that it will be useful, |
1007 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1008 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1009 | + * GNU General Public License for more details. |
1010 | + * |
1011 | + * You should have received a copy of the GNU General Public License |
1012 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1013 | + */ |
1014 | + |
1015 | +#ifndef MESSAGESENDINGJOB_H |
1016 | +#define MESSAGESENDINGJOB_H |
1017 | + |
1018 | +#include <QObject> |
1019 | +#include <QDBusContext> |
1020 | +#include <TelepathyQt/Types> |
1021 | +#include "dbustypes.h" |
1022 | +#include "messagejob.h" |
1023 | + |
1024 | +class AccountEntry; |
1025 | +class TextHandler; |
1026 | + |
1027 | +struct PendingMessage { |
1028 | + QString accountId; |
1029 | + QString message; |
1030 | + AttachmentList attachments; |
1031 | + QVariantMap properties; |
1032 | +}; |
1033 | +Q_DECLARE_METATYPE(PendingMessage) |
1034 | + |
1035 | +class MessageSendingJob : public MessageJob, protected QDBusContext |
1036 | +{ |
1037 | + Q_OBJECT |
1038 | + Q_PROPERTY(QString accountId READ accountId NOTIFY accountIdChanged) |
1039 | + Q_PROPERTY(QString channelObjectPath READ channelObjectPath NOTIFY channelObjectPathChanged) |
1040 | + Q_PROPERTY(QString objectPath READ objectPath CONSTANT) |
1041 | + |
1042 | +public: |
1043 | + explicit MessageSendingJob(TextHandler *textHandler, PendingMessage message); |
1044 | + ~MessageSendingJob(); |
1045 | + |
1046 | + QString accountId() const; |
1047 | + QString channelObjectPath() const; |
1048 | + QString objectPath() const; |
1049 | + |
1050 | +Q_SIGNALS: |
1051 | + void accountIdChanged(); |
1052 | + void channelObjectPathChanged(); |
1053 | + void messageStatusChanged(); |
1054 | + |
1055 | +public Q_SLOTS: |
1056 | + void startJob(); |
1057 | + |
1058 | +protected Q_SLOTS: |
1059 | + void findOrCreateChannel(); |
1060 | + void sendMessage(); |
1061 | + |
1062 | + void setAccountId(const QString &accountId); |
1063 | + void setChannelObjectPath(const QString &objectPath); |
1064 | + |
1065 | +private: |
1066 | + TextHandler *mTextHandler; |
1067 | + PendingMessage mMessage; |
1068 | + QString mAccountId; |
1069 | + AccountEntry *mAccount; |
1070 | + QString mChannelObjectPath; |
1071 | + Tp::TextChannelPtr mTextChannel; |
1072 | + QString mObjectPath; |
1073 | + bool mFinished; |
1074 | + |
1075 | + Tp::MessagePartList buildMessage(const PendingMessage &pendingMessage); |
1076 | + |
1077 | +}; |
1078 | + |
1079 | +#endif // MESSAGESENDINGJOB_H |
1080 | |
1081 | === modified file 'handler/texthandler.cpp' |
1082 | --- handler/texthandler.cpp 2016-03-01 18:17:57 +0000 |
1083 | +++ handler/texthandler.cpp 2016-05-24 01:13:17 +0000 |
1084 | @@ -26,38 +26,12 @@ |
1085 | #include "config.h" |
1086 | #include "dbustypes.h" |
1087 | #include "accountentry.h" |
1088 | +#include "chatstartingjob.h" |
1089 | |
1090 | #include <QImage> |
1091 | #include <TelepathyQt/ContactManager> |
1092 | #include <TelepathyQt/PendingContacts> |
1093 | - |
1094 | -#define SMIL_TEXT_REGION "<region id=\"Text\" width=\"100%\" height=\"100%\" fit=\"scroll\" />" |
1095 | -#define SMIL_IMAGE_REGION "<region id=\"Image\" width=\"100%\" height=\"100%\" fit=\"meet\" />" |
1096 | -#define SMIL_VIDEO_REGION "<region id=\"Video\" width=\"100%\" height=\"100%\" fit=\"meet\" />" |
1097 | -#define SMIL_AUDIO_REGION "<region id=\"Audio\" width=\"100%\" height=\"100%\" fit=\"meet\" />" |
1098 | -#define SMIL_TEXT_PART "<par dur=\"3s\">\ |
1099 | - <text src=\"cid:%1\" region=\"Text\" />\ |
1100 | - </par>" |
1101 | -#define SMIL_IMAGE_PART "<par dur=\"5000ms\">\ |
1102 | - <img src=\"cid:%1\" region=\"Image\" />\ |
1103 | - </par>" |
1104 | -#define SMIL_VIDEO_PART "<par>\ |
1105 | - <video src=\"cid:%1\" region=\"Video\" />\ |
1106 | - </par>" |
1107 | -#define SMIL_AUDIO_PART "<par>\ |
1108 | - <audio src=\"cid:%1\" region=\"Audio\" />\ |
1109 | - </par>" |
1110 | - |
1111 | -#define SMIL_FILE "<smil>\ |
1112 | - <head>\ |
1113 | - <layout>\ |
1114 | - %1\ |
1115 | - </layout>\ |
1116 | - </head>\ |
1117 | - <body>\ |
1118 | - %2\ |
1119 | - </body>\ |
1120 | - </smil>" |
1121 | +#include <TelepathyQt/PendingChannelRequest> |
1122 | |
1123 | TextHandler::TextHandler(QObject *parent) |
1124 | : QObject(parent) |
1125 | @@ -93,7 +67,7 @@ |
1126 | } |
1127 | bool found = false; |
1128 | // avoid adding twice the same list of participants |
1129 | - Q_FOREACH(const QStringList &recipients, recipientsList) { |
1130 | +/* Q_FOREACH(const QStringList &recipients, recipientsList) { |
1131 | if (recipients == pendingMessage.recipients) { |
1132 | found = true; |
1133 | break; |
1134 | @@ -101,10 +75,9 @@ |
1135 | } |
1136 | if (!found) { |
1137 | recipientsList << pendingMessage.recipients; |
1138 | - } |
1139 | - } |
1140 | - Q_FOREACH(const QStringList& recipients, recipientsList) { |
1141 | - startChat(recipients, accountId); |
1142 | + }*/ |
1143 | + // TODO AVOID CALLING TWICE FOR SAME CHANNEL |
1144 | + startChat(accountId, pendingMessage.properties); |
1145 | } |
1146 | } |
1147 | } |
1148 | @@ -115,271 +88,33 @@ |
1149 | return handler; |
1150 | } |
1151 | |
1152 | -void TextHandler::startChat(const QStringList &recipients, const QString &accountId) |
1153 | -{ |
1154 | - // Request the contact to start chatting to |
1155 | - // FIXME: make it possible to select which account to use, for now, pick the first one |
1156 | - AccountEntry *account = TelepathyHelper::instance()->accountForId(accountId); |
1157 | - if (!account->connected()) { |
1158 | - qCritical() << "The selected account does not have a connection. AccountId:" << accountId; |
1159 | - return; |
1160 | - } |
1161 | - |
1162 | - connect(account->account()->connection()->contactManager()->contactsForIdentifiers(recipients), |
1163 | - SIGNAL(finished(Tp::PendingOperation*)), |
1164 | - SLOT(onContactsAvailable(Tp::PendingOperation*))); |
1165 | -} |
1166 | - |
1167 | -void TextHandler::startChatRoom(const QString &accountId, const QStringList &initialParticipants, const QVariantMap &properties) |
1168 | -{ |
1169 | - Q_UNUSED(accountId) |
1170 | - Q_UNUSED(initialParticipants) |
1171 | - Q_UNUSED(properties) |
1172 | - // FIXME: implement |
1173 | -} |
1174 | - |
1175 | -void TextHandler::startChat(const Tp::AccountPtr &account, const Tp::Contacts &contacts) |
1176 | -{ |
1177 | - if (contacts.size() == 1) { |
1178 | - account->ensureTextChat(contacts.values()[0], QDateTime::currentDateTime(), TP_QT_IFACE_CLIENT + ".TelephonyServiceHandler"); |
1179 | - } else { |
1180 | - account->createConferenceTextChat(QList<Tp::ChannelPtr>(), contacts.toList(), QDateTime::currentDateTime(), TP_QT_IFACE_CLIENT + ".TelephonyServiceHandler"); |
1181 | - } |
1182 | - // start chatting to the contacts |
1183 | - Q_FOREACH(Tp::ContactPtr contact, contacts) { |
1184 | - // hold the ContactPtr to make sure its refcounting stays bigger than 0 |
1185 | - mContacts[account->uniqueIdentifier()][contact->id()] = contact; |
1186 | - } |
1187 | -} |
1188 | - |
1189 | -Tp::MessagePartList TextHandler::buildMessage(const PendingMessage &pendingMessage) |
1190 | -{ |
1191 | - Tp::MessagePartList message; |
1192 | - Tp::MessagePart header; |
1193 | - QString smil, regions, parts; |
1194 | - bool hasImage = false, hasText = false, hasVideo = false, hasAudio = false, isMMS = false; |
1195 | - |
1196 | - AccountEntry *account = TelepathyHelper::instance()->accountForId(pendingMessage.accountId); |
1197 | - if (!account) { |
1198 | - // account does not exist |
1199 | - return Tp::MessagePartList(); |
1200 | - } |
1201 | - |
1202 | - bool temporaryFiles = (pendingMessage.properties.contains("x-canonical-tmp-files") && |
1203 | - pendingMessage.properties["x-canonical-tmp-files"].toBool()); |
1204 | - |
1205 | - // add the remaining properties to the message header |
1206 | - QVariantMap::const_iterator it = pendingMessage.properties.begin(); |
1207 | - for (; it != pendingMessage.properties.end(); ++it) { |
1208 | - header[it.key()] = QDBusVariant(it.value()); |
1209 | - } |
1210 | - |
1211 | - // check if this message should be sent as an MMS |
1212 | - if (account->type() == AccountEntry::PhoneAccount) { |
1213 | - isMMS = (pendingMessage.attachments.size() > 0 || |
1214 | - (header.contains("x-canonical-mms") && header["x-canonical-mms"].variant().toBool()) || |
1215 | - (pendingMessage.recipients.size() > 1 && TelepathyHelper::instance()->mmsGroupChat())); |
1216 | - if (isMMS) { |
1217 | - header["x-canonical-mms"] = QDBusVariant(true); |
1218 | - } |
1219 | - } |
1220 | - |
1221 | - // this flag should not be in the message header, it's only useful for the handler |
1222 | - header.remove("x-canonical-tmp-files"); |
1223 | - |
1224 | - header["message-type"] = QDBusVariant(0); |
1225 | - message << header; |
1226 | - |
1227 | - // convert AttachmentList struct into telepathy Message parts |
1228 | - Q_FOREACH(const AttachmentStruct &attachment, pendingMessage.attachments) { |
1229 | - QByteArray fileData; |
1230 | - QString newFilePath = QString(attachment.filePath).replace("file://", ""); |
1231 | - QFile attachmentFile(newFilePath); |
1232 | - if (!attachmentFile.open(QIODevice::ReadOnly)) { |
1233 | - qWarning() << "fail to load attachment" << attachmentFile.errorString() << attachment.filePath; |
1234 | - continue; |
1235 | - } |
1236 | - if (attachment.contentType.startsWith("image/")) { |
1237 | - if (isMMS) { |
1238 | - hasImage = true; |
1239 | - parts += QString(SMIL_IMAGE_PART).arg(attachment.id); |
1240 | - // check if we need to reduce de image size in case it's bigger than 300k |
1241 | - // this check is only valid for MMS |
1242 | - if (attachmentFile.size() > 307200) { |
1243 | - QImage scaledImage(newFilePath); |
1244 | - if (!scaledImage.isNull()) { |
1245 | - QBuffer buffer(&fileData); |
1246 | - buffer.open(QIODevice::WriteOnly); |
1247 | - scaledImage.scaled(640, 640, Qt::KeepAspectRatio, Qt::SmoothTransformation).save(&buffer, "jpg"); |
1248 | - } |
1249 | - } else { |
1250 | - fileData = attachmentFile.readAll(); |
1251 | - } |
1252 | - } |
1253 | - } else if (attachment.contentType.startsWith("video/")) { |
1254 | - if (isMMS) { |
1255 | - hasVideo = true; |
1256 | - parts += QString(SMIL_VIDEO_PART).arg(attachment.id); |
1257 | - } |
1258 | - } else if (attachment.contentType.startsWith("audio/")) { |
1259 | - if (isMMS) { |
1260 | - hasAudio = true; |
1261 | - parts += QString(SMIL_AUDIO_PART).arg(attachment.id); |
1262 | - } |
1263 | - } else if (attachment.contentType.startsWith("text/plain")) { |
1264 | - if (isMMS) { |
1265 | - hasText = true; |
1266 | - parts += QString(SMIL_TEXT_PART).arg(attachment.id); |
1267 | - } |
1268 | - } else if (attachment.contentType.startsWith("text/vcard") || |
1269 | - attachment.contentType.startsWith("text/x-vcard")) { |
1270 | - } else if (isMMS) { |
1271 | - // for MMS we just support the contentTypes above |
1272 | - if (temporaryFiles) { |
1273 | - attachmentFile.remove(); |
1274 | - } |
1275 | - continue; |
1276 | - } |
1277 | - |
1278 | - if (fileData.isEmpty()) { |
1279 | - fileData = attachmentFile.readAll(); |
1280 | - } |
1281 | - |
1282 | - if (temporaryFiles) { |
1283 | - attachmentFile.remove(); |
1284 | - } |
1285 | - |
1286 | - if (hasVideo) { |
1287 | - regions += QString(SMIL_VIDEO_REGION); |
1288 | - } |
1289 | - |
1290 | - if (hasAudio) { |
1291 | - regions += QString(SMIL_AUDIO_REGION); |
1292 | - } |
1293 | - |
1294 | - if (hasText) { |
1295 | - regions += QString(SMIL_TEXT_REGION); |
1296 | - } |
1297 | - if (hasImage) { |
1298 | - regions += QString(SMIL_IMAGE_REGION); |
1299 | - } |
1300 | - |
1301 | - Tp::MessagePart part; |
1302 | - part["content-type"] = QDBusVariant(attachment.contentType); |
1303 | - part["identifier"] = QDBusVariant(attachment.id); |
1304 | - part["content"] = QDBusVariant(fileData); |
1305 | - part["size"] = QDBusVariant(fileData.size()); |
1306 | - |
1307 | - message << part; |
1308 | - } |
1309 | - |
1310 | - if (!pendingMessage.message.isEmpty()) { |
1311 | - Tp::MessagePart part; |
1312 | - QString tmpTextId("text_0.txt"); |
1313 | - part["content-type"] = QDBusVariant(QString("text/plain")); |
1314 | - part["identifier"] = QDBusVariant(tmpTextId); |
1315 | - part["content"] = QDBusVariant(pendingMessage.message); |
1316 | - part["size"] = QDBusVariant(pendingMessage.message.size()); |
1317 | - if (isMMS) { |
1318 | - parts += QString(SMIL_TEXT_PART).arg(tmpTextId); |
1319 | - regions += QString(SMIL_TEXT_REGION); |
1320 | - } |
1321 | - message << part; |
1322 | - } |
1323 | - |
1324 | - if (isMMS) { |
1325 | - Tp::MessagePart smilPart; |
1326 | - smil = QString(SMIL_FILE).arg(regions).arg(parts); |
1327 | - smilPart["content-type"] = QDBusVariant(QString("application/smil")); |
1328 | - smilPart["identifier"] = QDBusVariant(QString("smil.xml")); |
1329 | - smilPart["content"] = QDBusVariant(smil); |
1330 | - smilPart["size"] = QDBusVariant(smil.size()); |
1331 | - |
1332 | - message << smilPart; |
1333 | - } |
1334 | - |
1335 | - return message; |
1336 | -} |
1337 | - |
1338 | -QString TextHandler::sendMessage(const QString &accountId, const QStringList &recipients, const QString &message, const AttachmentList &attachments, const QVariantMap &properties) |
1339 | -{ |
1340 | - AccountEntry *account = TelepathyHelper::instance()->accountForId(accountId); |
1341 | - if (!account) { |
1342 | - // account does not exist |
1343 | - return QString(); |
1344 | - } |
1345 | - |
1346 | - // check if the message should be sent via multimedia account |
1347 | - // we just use fallback to 1-1 chats |
1348 | - if (account->type() == AccountEntry::PhoneAccount && recipients.size() == 1) { |
1349 | - Q_FOREACH(AccountEntry *newAccount, TelepathyHelper::instance()->accounts()) { |
1350 | - // TODO: we have to find the multimedia account that matches the same phone number, |
1351 | - // but for now we just pick any multimedia connected account |
1352 | - if (newAccount->type() != AccountEntry::MultimediaAccount) { |
1353 | - continue; |
1354 | - } |
1355 | - // FIXME: the fallback implementation needs to be changed to use protocol info and create a map of |
1356 | - // accounts. Also, it needs to check connection capabilities to determine if we can send message |
1357 | - // to offline contacts. |
1358 | - bool shouldFallback = false; |
1359 | - // if the account is offline, dont fallback to this account |
1360 | - if (!newAccount->connected()) { |
1361 | - continue; |
1362 | - } |
1363 | - QList<Tp::TextChannelPtr> channels = existingChannels(recipients, newAccount->accountId()); |
1364 | - // check if we have a channel for this contact already and get the contact pointer from there, |
1365 | - // this way we avoid doing the while(op->isFinished()) all the time |
1366 | - if (!channels.isEmpty()) { |
1367 | - // if the contact is known, force fallback to this account |
1368 | - Tp::Presence presence = channels.first()->targetContact()->presence(); |
1369 | - shouldFallback = (presence.type() == Tp::ConnectionPresenceTypeAvailable || |
1370 | - presence.type() == Tp::ConnectionPresenceTypeOffline); |
1371 | - } else { |
1372 | - Tp::PendingOperation *op = newAccount->account()->connection()->contactManager()->contactsForIdentifiers(recipients); |
1373 | - while (!op->isFinished()) { |
1374 | - qApp->processEvents(); |
1375 | - } |
1376 | - Tp::PendingContacts *pc = qobject_cast<Tp::PendingContacts*>(op); |
1377 | - if (pc) { |
1378 | - Tp::Presence presence = pc->contacts().first()->presence(); |
1379 | - shouldFallback = (presence.type() == Tp::ConnectionPresenceTypeAvailable || |
1380 | - presence.type() == Tp::ConnectionPresenceTypeOffline); |
1381 | - } |
1382 | - } |
1383 | - if (shouldFallback) { |
1384 | - account = newAccount; |
1385 | - break; |
1386 | - } |
1387 | - } |
1388 | - } |
1389 | - |
1390 | - // keep recipient list always sorted to be able to compare |
1391 | - QStringList sortedRecipients = recipients; |
1392 | - sortedRecipients.sort(); |
1393 | - PendingMessage pendingMessage = {account->accountId(), sortedRecipients, message, attachments, properties}; |
1394 | - |
1395 | - if (!account->connected()) { |
1396 | - mPendingMessages.append(pendingMessage); |
1397 | - return account->accountId(); |
1398 | - } |
1399 | - |
1400 | - QList<Tp::TextChannelPtr> channels = existingChannels(recipients, account->accountId()); |
1401 | - if (channels.isEmpty()) { |
1402 | - mPendingMessages.append(pendingMessage); |
1403 | - startChat(sortedRecipients, account->accountId()); |
1404 | - return account->accountId(); |
1405 | - } |
1406 | - |
1407 | - connect(channels.last()->send(buildMessage(pendingMessage)), |
1408 | - SIGNAL(finished(Tp::PendingOperation*)), |
1409 | - SLOT(onMessageSent(Tp::PendingOperation*))); |
1410 | - |
1411 | - return account->accountId(); |
1412 | +void TextHandler::startChat(const QString &accountId, const QVariantMap &properties) |
1413 | +{ |
1414 | + ChatStartingJob *job = new ChatStartingJob(this, accountId, properties); |
1415 | + QTimer::singleShot(0, job, &ChatStartingJob::startJob); |
1416 | + // FIXME: do we care about the result? |
1417 | +} |
1418 | + |
1419 | +QString TextHandler::sendMessage(const QString &accountId, const QString &message, const AttachmentList &attachments, const QVariantMap &properties) |
1420 | +{ |
1421 | + PendingMessage pendingMessage = {accountId, message, attachments, properties}; |
1422 | + MessageSendingJob *job = new MessageSendingJob(this, pendingMessage); |
1423 | + QTimer::singleShot(0, job, &MessageSendingJob::startJob); |
1424 | + |
1425 | + // FIXME: just for a first stage, we synchronously wait for the job to finish and return the accountId as usual |
1426 | + while (!job->isFinished()) { |
1427 | + QCoreApplication::processEvents(); |
1428 | + } |
1429 | + |
1430 | + return job->accountId(); |
1431 | } |
1432 | |
1433 | void TextHandler::acknowledgeMessages(const QStringList &recipients, const QStringList &messageIds, const QString &accountId) |
1434 | { |
1435 | - QList<Tp::TextChannelPtr> channels = existingChannels(recipients, accountId); |
1436 | + QVariantMap properties; |
1437 | + properties["participantIds"] = recipients; |
1438 | + |
1439 | + QList<Tp::TextChannelPtr> channels = existingChannels(accountId, properties); |
1440 | if (channels.isEmpty()) { |
1441 | return; |
1442 | } |
1443 | @@ -397,7 +132,9 @@ |
1444 | |
1445 | void TextHandler::acknowledgeAllMessages(const QStringList &recipients, const QString &accountId) |
1446 | { |
1447 | - QList<Tp::TextChannelPtr> channels = existingChannels(recipients, accountId); |
1448 | + QVariantMap properties; |
1449 | + properties["participantIds"] = recipients; |
1450 | + QList<Tp::TextChannelPtr> channels = existingChannels(accountId, properties); |
1451 | if (channels.isEmpty()) { |
1452 | return; |
1453 | } |
1454 | @@ -411,14 +148,11 @@ |
1455 | { |
1456 | Tp::TextChannelPtr textChannel(qobject_cast<Tp::TextChannel*>(sender())); |
1457 | mChannels.removeAll(textChannel); |
1458 | - AccountEntry *account = TelepathyHelper::instance()->accountForConnection(textChannel->connection()); |
1459 | - if (account) { |
1460 | - mContacts.remove(account->accountId()); |
1461 | - } |
1462 | } |
1463 | |
1464 | void TextHandler::onTextChannelAvailable(Tp::TextChannelPtr channel) |
1465 | { |
1466 | + qDebug() << "TextHandler::onTextChannelAvailable" << channel; |
1467 | AccountEntry *account = TelepathyHelper::instance()->accountForConnection(channel->connection()); |
1468 | if (!account) { |
1469 | return; |
1470 | @@ -438,10 +172,9 @@ |
1471 | QList<PendingMessage>::iterator it = mPendingMessages.begin(); |
1472 | while (it != mPendingMessages.end()) { |
1473 | bool found = false; |
1474 | - Q_FOREACH(const Tp::TextChannelPtr &existingChannel, existingChannels(it->recipients, it->accountId)) { |
1475 | + Q_FOREACH(const Tp::TextChannelPtr &existingChannel, existingChannels(it->accountId, it->properties)) { |
1476 | if (existingChannel == channel) { |
1477 | - // FIXME: we can't trust recipients for group chats in regular IM accounts |
1478 | - sendMessage(it->accountId, it->recipients, it->message, it->attachments, it->properties); |
1479 | + sendMessage(it->accountId, it->message, it->attachments, it->properties); |
1480 | it = mPendingMessages.erase(it); |
1481 | found = true; |
1482 | break; |
1483 | @@ -453,23 +186,15 @@ |
1484 | } |
1485 | } |
1486 | |
1487 | -void TextHandler::onMessageSent(Tp::PendingOperation *op) |
1488 | -{ |
1489 | - Tp::PendingSendMessage *psm = qobject_cast<Tp::PendingSendMessage*>(op); |
1490 | - if(!psm) { |
1491 | - qWarning() << "The pending object was not a pending operation:" << op; |
1492 | - return; |
1493 | - } |
1494 | - |
1495 | - if (psm->isError()) { |
1496 | - qWarning() << "Error sending message:" << psm->errorName() << psm->errorMessage(); |
1497 | - return; |
1498 | - } |
1499 | -} |
1500 | - |
1501 | -QList<Tp::TextChannelPtr> TextHandler::existingChannels(const QStringList &targetIds, const QString &accountId) |
1502 | +QList<Tp::TextChannelPtr> TextHandler::existingChannels(const QString &accountId, const QVariantMap &properties) |
1503 | { |
1504 | QList<Tp::TextChannelPtr> channels; |
1505 | + QStringList targetIds = properties["participantIds"].toStringList(); |
1506 | + int chatType = properties["chatType"].toUInt(); |
1507 | + if (chatType == 0 && targetIds.size() == 1) { |
1508 | + chatType = 1; |
1509 | + } |
1510 | + QString roomId = properties["threadId"].toString(); |
1511 | |
1512 | Q_FOREACH(const Tp::TextChannelPtr &channel, mChannels) { |
1513 | int count = 0; |
1514 | @@ -479,6 +204,17 @@ |
1515 | continue; |
1516 | } |
1517 | |
1518 | + if (chatType != channel->targetHandleType()) { |
1519 | + continue; |
1520 | + } |
1521 | + |
1522 | + if (chatType == 2) { |
1523 | + if (!roomId.isEmpty() && channel->targetHandleType() == chatType && roomId == channel->targetId()) { |
1524 | + channels.append(channel); |
1525 | + } |
1526 | + continue; |
1527 | + } |
1528 | + |
1529 | // this is a special case. We have to check if we are looking for a channel open with our self contact. |
1530 | bool channelToSelfContact = channel->groupContacts(true).size() == 1 && targetIds.size() == 1 && |
1531 | channel->targetHandleType() == Tp::HandleTypeContact && |
1532 | @@ -507,17 +243,3 @@ |
1533 | } |
1534 | return channels; |
1535 | } |
1536 | - |
1537 | -void TextHandler::onContactsAvailable(Tp::PendingOperation *op) |
1538 | -{ |
1539 | - Tp::PendingContacts *pc = qobject_cast<Tp::PendingContacts*>(op); |
1540 | - |
1541 | - if (!pc) { |
1542 | - qCritical() << "The pending object is not a Tp::PendingContacts"; |
1543 | - return; |
1544 | - } |
1545 | - AccountEntry *account = TelepathyHelper::instance()->accountForConnection(pc->manager()->connection()); |
1546 | - startChat(account->account(), pc->contacts().toSet()); |
1547 | -} |
1548 | - |
1549 | - |
1550 | |
1551 | === modified file 'handler/texthandler.h' |
1552 | --- handler/texthandler.h 2015-12-07 16:26:20 +0000 |
1553 | +++ handler/texthandler.h 2016-05-24 01:13:17 +0000 |
1554 | @@ -27,46 +27,35 @@ |
1555 | #include <TelepathyQt/TextChannel> |
1556 | #include <TelepathyQt/ReceivedMessage> |
1557 | #include "dbustypes.h" |
1558 | - |
1559 | -struct PendingMessage { |
1560 | - QString accountId; |
1561 | - QStringList recipients; |
1562 | - QString message; |
1563 | - AttachmentList attachments; |
1564 | - QVariantMap properties; |
1565 | -}; |
1566 | -Q_DECLARE_METATYPE(PendingMessage) |
1567 | +#include "messagesendingjob.h" |
1568 | |
1569 | class TextHandler : public QObject |
1570 | { |
1571 | Q_OBJECT |
1572 | public: |
1573 | static TextHandler *instance(); |
1574 | - void startChat(const QStringList &recipients, const QString &accountId); |
1575 | - void startChatRoom(const QString &accountId, const QStringList &initialParticipants, const QVariantMap &properties); |
1576 | - void startChat(const Tp::AccountPtr &account, const Tp::Contacts &contacts); |
1577 | + void startChat(const QString &accountId, const QVariantMap &properties); |
1578 | + |
1579 | + friend class MessageSendingJob; |
1580 | |
1581 | public Q_SLOTS: |
1582 | - QString sendMessage(const QString &accountId, const QStringList &recipients, const QString &message, const AttachmentList &attachments, const QVariantMap &properties); |
1583 | + QString sendMessage(const QString &accountId, const QString &message, const AttachmentList &attachments, const QVariantMap &properties); |
1584 | void acknowledgeMessages(const QStringList &recipients, const QStringList &messageIds, const QString &accountId); |
1585 | void acknowledgeAllMessages(const QStringList &recipients, const QString &accountId); |
1586 | |
1587 | protected Q_SLOTS: |
1588 | void onTextChannelAvailable(Tp::TextChannelPtr channel); |
1589 | void onTextChannelInvalidated(); |
1590 | - void onContactsAvailable(Tp::PendingOperation *op); |
1591 | - void onMessageSent(Tp::PendingOperation *op); |
1592 | void onConnectedChanged(); |
1593 | |
1594 | protected: |
1595 | - QList<Tp::TextChannelPtr> existingChannels(const QStringList &targetIds, const QString &accountId); |
1596 | + QList<Tp::TextChannelPtr> existingChannels(const QString &accountId, const QVariantMap &properties); |
1597 | |
1598 | private: |
1599 | explicit TextHandler(QObject *parent = 0); |
1600 | - Tp::MessagePartList buildMessage(const PendingMessage &pendingMessage); |
1601 | + |
1602 | |
1603 | QList<Tp::TextChannelPtr> mChannels; |
1604 | - QMap<QString, QMap<QString, Tp::ContactPtr> > mContacts; |
1605 | QList<PendingMessage> mPendingMessages; |
1606 | }; |
1607 | |
1608 | |
1609 | === modified file 'indicator/TelephonyServiceIndicator.client' |
1610 | --- indicator/TelephonyServiceIndicator.client 2014-11-21 13:58:47 +0000 |
1611 | +++ indicator/TelephonyServiceIndicator.client 2016-05-24 01:13:17 +0000 |
1612 | @@ -8,11 +8,6 @@ |
1613 | |
1614 | [org.freedesktop.Telepathy.Client.Observer.ObserverChannelFilter 1] |
1615 | org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Text |
1616 | -org.freedesktop.Telepathy.Channel.TargetHandleType u=1 |
1617 | - |
1618 | -[org.freedesktop.Telepathy.Client.Observer.ObserverChannelFilter 2] |
1619 | -org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Text |
1620 | -org.freedesktop.Telepathy.Channel.TargetHandleType u=0 |
1621 | |
1622 | [org.freedesktop.Telepathy.Client.Observer.Capabilities] |
1623 | org.freedesktop.Telepathy.Channel.Type.Call1/audio=true |
1624 | |
1625 | === modified file 'indicator/textchannelobserver.cpp' |
1626 | --- indicator/textchannelobserver.cpp 2016-03-30 13:34:38 +0000 |
1627 | +++ indicator/textchannelobserver.cpp 2016-05-24 01:13:17 +0000 |
1628 | @@ -277,7 +277,9 @@ |
1629 | return; |
1630 | } |
1631 | |
1632 | - ChatManager::instance()->sendMessage(account->accountId(), recipients, text); |
1633 | + QVariantMap properties; |
1634 | + properties["participantIds"] = recipients; |
1635 | + ChatManager::instance()->sendMessage(account->accountId(), text, QVariantMap(), properties); |
1636 | } |
1637 | |
1638 | void TextChannelObserver::clearNotifications() |
1639 | @@ -341,6 +343,9 @@ |
1640 | void TextChannelObserver::triggerNotificationForMessage(const Tp::ReceivedMessage &message, const QString &accountId, const QStringList &participantIds) |
1641 | { |
1642 | Tp::ContactPtr contact = message.sender(); |
1643 | + if (!contact) { |
1644 | + return; |
1645 | + } |
1646 | |
1647 | QByteArray token(message.messageToken().toUtf8()); |
1648 | if (!mUnreadMessages.contains(token)) { |
1649 | @@ -624,7 +629,7 @@ |
1650 | // we do not notify messages sent by ourselves on other devices, unless we |
1651 | // are dealing with phone accounts: #1547462 |
1652 | if (!account->account()->connection().isNull() && |
1653 | - message.sender()->handle().at(0) == account->account()->connection()->selfHandle() && |
1654 | + message.sender() && message.sender()->handle().at(0) == account->account()->connection()->selfHandle() && |
1655 | account->type() != AccountEntry::PhoneAccount) { |
1656 | return; |
1657 | } |
1658 | |
1659 | === modified file 'libtelephonyservice/accountentry.cpp' |
1660 | --- libtelephonyservice/accountentry.cpp 2015-11-23 20:01:58 +0000 |
1661 | +++ libtelephonyservice/accountentry.cpp 2016-05-24 01:13:17 +0000 |
1662 | @@ -106,6 +106,38 @@ |
1663 | mAccount->connection()->status() == Tp::ConnectionStatusConnected; |
1664 | } |
1665 | |
1666 | +AccountEntry::Capabilities AccountEntry::capabilities() const |
1667 | +{ |
1668 | + AccountEntry::Capabilities capabilities = CapabilityNone; |
1669 | + |
1670 | + if (!connected()) { |
1671 | + return capabilities; |
1672 | + } |
1673 | + |
1674 | + Tp::ConnectionCapabilities tpCapabilities = mAccount->capabilities(); |
1675 | + |
1676 | + if (tpCapabilities.textChatrooms()) { |
1677 | + capabilities |= (AccountEntry::Capabilities)AccountEntry::CapabilityTextChatrooms; |
1678 | + } |
1679 | + if (tpCapabilities.conferenceTextChats()) { |
1680 | + capabilities |= (AccountEntry::Capabilities)AccountEntry::CapabilityConferenceTextChats; |
1681 | + } |
1682 | + if (tpCapabilities.conferenceTextChatsWithInvitees()) { |
1683 | + capabilities |= (AccountEntry::Capabilities)AccountEntry::CapabilityConferenceTextChatsWithInvitees; |
1684 | + } |
1685 | + if (tpCapabilities.conferenceTextChatrooms()) { |
1686 | + capabilities |= (AccountEntry::Capabilities)AccountEntry::CapabilityConferenceTextChatrooms; |
1687 | + } |
1688 | + if (tpCapabilities.conferenceTextChatroomsWithInvitees()) { |
1689 | + capabilities |= (AccountEntry::Capabilities)AccountEntry::CapabilityConferenceTextChatroomsWithInvitees; |
1690 | + } |
1691 | + if (tpCapabilities.contactSearches()) { |
1692 | + capabilities |= (AccountEntry::Capabilities)AccountEntry::CapabilityContactSearches; |
1693 | + } |
1694 | + |
1695 | + return capabilities; |
1696 | +} |
1697 | + |
1698 | Tp::AccountPtr AccountEntry::account() const |
1699 | { |
1700 | return mAccount; |
1701 | @@ -219,6 +251,7 @@ |
1702 | |
1703 | Q_EMIT connectedChanged(); |
1704 | Q_EMIT selfContactIdChanged(); |
1705 | + Q_EMIT capabilitiesChanged(); |
1706 | } |
1707 | |
1708 | void AccountEntry::addAccountLabel(const QString &accountId, QString &text) |
1709 | |
1710 | === modified file 'libtelephonyservice/accountentry.h' |
1711 | --- libtelephonyservice/accountentry.h 2015-11-23 20:01:58 +0000 |
1712 | +++ libtelephonyservice/accountentry.h 2016-05-24 01:13:17 +0000 |
1713 | @@ -45,6 +45,7 @@ |
1714 | Q_PROPERTY(bool connected READ connected NOTIFY connectedChanged) |
1715 | Q_PROPERTY(QStringList addressableVCardFields READ addressableVCardFields NOTIFY addressableVCardFieldsChanged) |
1716 | Q_PROPERTY(Protocol* protocolInfo READ protocolInfo CONSTANT) |
1717 | + Q_PROPERTY(Capabilities capabilities READ capabilities NOTIFY capabilitiesChanged) |
1718 | Q_ENUMS(AccountType) |
1719 | friend class AccountEntryFactory; |
1720 | |
1721 | @@ -55,6 +56,17 @@ |
1722 | GenericAccount |
1723 | }; |
1724 | |
1725 | + enum Capability { |
1726 | + CapabilityNone = 0, |
1727 | + CapabilityTextChatrooms = 1, |
1728 | + CapabilityConferenceTextChats = 2, |
1729 | + CapabilityConferenceTextChatsWithInvitees = 4, |
1730 | + CapabilityConferenceTextChatrooms = 8, |
1731 | + CapabilityConferenceTextChatroomsWithInvitees = 16, |
1732 | + CapabilityContactSearches = 32 |
1733 | + }; |
1734 | + Q_DECLARE_FLAGS(Capabilities, Capability); |
1735 | + |
1736 | bool ready() const; |
1737 | QString accountId() const; |
1738 | QString displayName() const; |
1739 | @@ -68,6 +80,7 @@ |
1740 | virtual bool compareIds(const QString &first, const QString &second) const; |
1741 | virtual bool active() const; |
1742 | virtual bool connected() const; |
1743 | + Capabilities capabilities() const; |
1744 | |
1745 | Protocol *protocolInfo() const; |
1746 | |
1747 | @@ -85,6 +98,7 @@ |
1748 | void addressableVCardFieldsChanged(); |
1749 | void removed(); |
1750 | void connectionStatusChanged(Tp::ConnectionStatus status); |
1751 | + void capabilitiesChanged(); |
1752 | |
1753 | protected Q_SLOTS: |
1754 | virtual void initialize(); |
1755 | @@ -101,4 +115,6 @@ |
1756 | Protocol *mProtocol; |
1757 | }; |
1758 | |
1759 | +Q_DECLARE_OPERATORS_FOR_FLAGS(AccountEntry::Capabilities); |
1760 | + |
1761 | #endif // ACCOUNTENTRY_H |
1762 | |
1763 | === modified file 'libtelephonyservice/chatentry.cpp' |
1764 | --- libtelephonyservice/chatentry.cpp 2015-08-04 19:50:53 +0000 |
1765 | +++ libtelephonyservice/chatentry.cpp 2016-05-24 01:13:17 +0000 |
1766 | @@ -31,7 +31,10 @@ |
1767 | |
1768 | ChatEntry::ChatEntry(const Tp::TextChannelPtr &channel, QObject *parent) : |
1769 | QObject(parent), |
1770 | - mChannel(channel) |
1771 | + mChannel(channel), |
1772 | + roomInterface(NULL), |
1773 | + roomConfigInterface(NULL), |
1774 | + subjectInterface(NULL) |
1775 | { |
1776 | qRegisterMetaType<ContactChatStates>(); |
1777 | mAccount = TelepathyHelper::instance()->accountForConnection(mChannel->connection()); |
1778 | @@ -40,12 +43,54 @@ |
1779 | mChatStates[contact->id()] = state; |
1780 | } |
1781 | |
1782 | + roomInterface = channel->optionalInterface<Tp::Client::ChannelInterfaceRoomInterface>(); |
1783 | + roomConfigInterface = channel->optionalInterface<Tp::Client::ChannelInterfaceRoomConfigInterface>(); |
1784 | + subjectInterface = channel->optionalInterface<Tp::Client::ChannelInterfaceSubjectInterface>(); |
1785 | + |
1786 | + if (roomInterface) { |
1787 | + roomInterface->setMonitorProperties(true); |
1788 | + connect(roomInterface, SIGNAL(propertiesChanged(const QVariantMap &,const QStringList &)), |
1789 | + SLOT(onRoomPropertiesChanged(const QVariantMap &,const QStringList &))); |
1790 | + } |
1791 | + if (roomConfigInterface) { |
1792 | + roomConfigInterface->setMonitorProperties(true); |
1793 | + connect(roomConfigInterface, SIGNAL(propertiesChanged(const QVariantMap &,const QStringList &)), |
1794 | + SLOT(onRoomPropertiesChanged(const QVariantMap &,const QStringList &))); |
1795 | + } |
1796 | + if (subjectInterface) { |
1797 | + subjectInterface->setMonitorProperties(true); |
1798 | + connect(subjectInterface, SIGNAL(propertiesChanged(const QVariantMap &,const QStringList &)), |
1799 | + SLOT(onRoomPropertiesChanged(const QVariantMap &,const QStringList &))); |
1800 | + } |
1801 | + |
1802 | connect(channel.data(), SIGNAL(chatStateChanged(const Tp::ContactPtr &, Tp::ChannelChatState)), |
1803 | this, SLOT(onChatStateChanged(const Tp::ContactPtr &,Tp::ChannelChatState))); |
1804 | connect(channel.data(), SIGNAL(groupMembersChanged(const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, |
1805 | const Tp::Contacts &, const Tp::Channel::GroupMemberChangeDetails &)), this, SIGNAL(participantsChanged())); |
1806 | } |
1807 | |
1808 | +void ChatEntry::onRoomPropertiesChanged(const QVariantMap &changed,const QStringList &invalidated) |
1809 | +{ |
1810 | + if (changed.contains("RoomName")) { |
1811 | + mRoomName = changed["RoomName"].toString(); |
1812 | + Q_EMIT roomNameChanged(); |
1813 | + } |
1814 | + if (changed.contains("Title")) { |
1815 | + mTitle = changed["Title"].toString(); |
1816 | + Q_EMIT titleChanged(); |
1817 | + } |
1818 | +} |
1819 | + |
1820 | +QString ChatEntry::roomName() |
1821 | +{ |
1822 | + return mRoomName; |
1823 | +} |
1824 | + |
1825 | +QString ChatEntry::title() |
1826 | +{ |
1827 | + return mTitle; |
1828 | +} |
1829 | + |
1830 | ChatEntry::~ChatEntry() |
1831 | { |
1832 | QMap<QString, ContactChatState*> tmp = mChatStates; |
1833 | @@ -56,6 +101,24 @@ |
1834 | it.next(); |
1835 | delete it.value(); |
1836 | } |
1837 | + |
1838 | + if (roomInterface) { |
1839 | + roomInterface->deleteLater(); |
1840 | + } |
1841 | + if (roomConfigInterface) { |
1842 | + roomConfigInterface->deleteLater(); |
1843 | + } |
1844 | + if (subjectInterface) { |
1845 | + subjectInterface->deleteLater(); |
1846 | + } |
1847 | +} |
1848 | + |
1849 | +QString ChatEntry::chatId() |
1850 | +{ |
1851 | + if (mChannel) { |
1852 | + return mChannel->targetId(); |
1853 | + } |
1854 | + return QString(); |
1855 | } |
1856 | |
1857 | void ChatEntry::onChatStateChanged(const Tp::ContactPtr &contact, Tp::ChannelChatState state) |
1858 | |
1859 | === modified file 'libtelephonyservice/chatentry.h' |
1860 | --- libtelephonyservice/chatentry.h 2015-03-20 19:00:21 +0000 |
1861 | +++ libtelephonyservice/chatentry.h 2016-05-24 01:13:17 +0000 |
1862 | @@ -55,6 +55,9 @@ |
1863 | Q_PROPERTY(AccountEntry* account READ account CONSTANT) |
1864 | Q_PROPERTY(ChatType chatType READ chatType CONSTANT) |
1865 | Q_PROPERTY(QStringList participants READ participants NOTIFY participantsChanged) |
1866 | + Q_PROPERTY(QString roomName READ roomName NOTIFY roomNameChanged) |
1867 | + Q_PROPERTY(QString chatId READ chatId CONSTANT) |
1868 | + Q_PROPERTY(QString title READ title NOTIFY titleChanged) |
1869 | Q_PROPERTY(QQmlListProperty<ContactChatState> chatStates |
1870 | READ chatStates |
1871 | NOTIFY chatStatesChanged) |
1872 | @@ -83,20 +86,31 @@ |
1873 | QQmlListProperty<ContactChatState> chatStates(); |
1874 | QStringList participants(); |
1875 | ChatType chatType(); |
1876 | + QString chatId(); |
1877 | + QString roomName(); |
1878 | + QString title(); |
1879 | static int chatStatesCount(QQmlListProperty<ContactChatState> *p); |
1880 | static ContactChatState *chatStatesAt(QQmlListProperty<ContactChatState> *p, int index); |
1881 | |
1882 | private Q_SLOTS: |
1883 | void onChatStateChanged(const Tp::ContactPtr &contact, Tp::ChannelChatState state); |
1884 | + void onRoomPropertiesChanged(const QVariantMap &changed,const QStringList &invalidated); |
1885 | |
1886 | Q_SIGNALS: |
1887 | void chatStatesChanged(); |
1888 | void participantsChanged(); |
1889 | + void roomNameChanged(); |
1890 | + void titleChanged(); |
1891 | |
1892 | private: |
1893 | AccountEntry *mAccount; |
1894 | Tp::TextChannelPtr mChannel; |
1895 | QMap<QString, ContactChatState*> mChatStates; |
1896 | + QString mRoomName; |
1897 | + QString mTitle; |
1898 | + Tp::Client::ChannelInterfaceRoomInterface *roomInterface; |
1899 | + Tp::Client::ChannelInterfaceRoomConfigInterface *roomConfigInterface; |
1900 | + Tp::Client::ChannelInterfaceSubjectInterface *subjectInterface; |
1901 | }; |
1902 | |
1903 | #endif // CHATENTRY_H |
1904 | |
1905 | === modified file 'libtelephonyservice/chatmanager.cpp' |
1906 | --- libtelephonyservice/chatmanager.cpp 2016-03-07 19:27:55 +0000 |
1907 | +++ libtelephonyservice/chatmanager.cpp 2016-05-24 01:13:17 +0000 |
1908 | @@ -95,7 +95,7 @@ |
1909 | return manager; |
1910 | } |
1911 | |
1912 | -QString ChatManager::sendMessage(const QString &accountId, const QStringList &recipients, const QString &message, const QVariant &attachments, const QVariantMap &properties) |
1913 | +QString ChatManager::sendMessage(const QString &accountId, const QString &message, const QVariant &attachments, const QVariantMap &properties) |
1914 | { |
1915 | AccountEntry *account = TelepathyHelper::instance()->accountForId(accountId); |
1916 | |
1917 | @@ -103,9 +103,16 @@ |
1918 | return QString(); |
1919 | } |
1920 | |
1921 | + QVariantMap propMap = properties; |
1922 | + |
1923 | // check if files should be copied to a temporary location before passing them to handler |
1924 | bool tmpFiles = (properties.contains("x-canonical-tmp-files") && properties["x-canonical-tmp-files"].toBool()); |
1925 | |
1926 | + // participants coming from qml are variants |
1927 | + if (properties.contains("participantIds")) { |
1928 | + propMap["participantIds"] = properties["participantIds"].toStringList(); |
1929 | + } |
1930 | + |
1931 | AttachmentList newAttachments; |
1932 | Q_FOREACH (const QVariant &attachment, attachments.toList()) { |
1933 | AttachmentStruct newAttachment; |
1934 | @@ -142,7 +149,7 @@ |
1935 | } |
1936 | |
1937 | QDBusInterface *phoneAppHandler = TelepathyHelper::instance()->handlerInterface(); |
1938 | - QDBusReply<QString> reply = phoneAppHandler->call("SendMessage", account->accountId(), recipients, message, QVariant::fromValue(newAttachments), properties); |
1939 | + QDBusReply<QString> reply = phoneAppHandler->call("SendMessage", account->accountId(), message, QVariant::fromValue(newAttachments), propMap); |
1940 | if (reply.isValid()) { |
1941 | return reply.value(); |
1942 | } |
1943 | @@ -164,7 +171,7 @@ |
1944 | connect(channel.data(), |
1945 | SIGNAL(messageSent(Tp::Message,Tp::MessageSendingFlags,QString)), |
1946 | SLOT(onMessageSent(Tp::Message,Tp::MessageSendingFlags,QString))); |
1947 | - connect(channel.data(), |
1948 | + connect(channel.data(), |
1949 | SIGNAL(invalidated(Tp::DBusProxy*,const QString&, const QString&)), |
1950 | SLOT(onChannelInvalidated())); |
1951 | |
1952 | @@ -206,6 +213,10 @@ |
1953 | return; |
1954 | } |
1955 | |
1956 | + if (!message.sender()) { |
1957 | + return; |
1958 | + } |
1959 | + |
1960 | Q_EMIT messageReceived(message.sender()->id(), message.text(), message.received(), message.messageToken(), true); |
1961 | } |
1962 | |
1963 | @@ -278,9 +289,41 @@ |
1964 | return mChatEntries; |
1965 | } |
1966 | |
1967 | -ChatEntry *ChatManager::chatEntryForParticipants(const QString &accountId, const QStringList &participants, bool create) |
1968 | +ChatEntry *ChatManager::chatEntryForProperties(const QString &accountId, const QVariantMap &properties, bool create) |
1969 | { |
1970 | - if (participants.count() == 0 || accountId.isEmpty()) { |
1971 | + QVariantMap propMap = properties; |
1972 | + int chatType = 0; |
1973 | + |
1974 | + QStringList participants; |
1975 | + // participants coming from qml are variants |
1976 | + if (properties.contains("participantIds")) { |
1977 | + participants = properties["participantIds"].toStringList(); |
1978 | + if (!participants.isEmpty()) { |
1979 | + propMap["participantIds"] = participants; |
1980 | + } |
1981 | + } |
1982 | + |
1983 | + if (participants.isEmpty() && propMap.contains("participants")) { |
1984 | + // try to generate list of participants from "participants" |
1985 | + Q_FOREACH(const QVariant &participantMap, propMap["participants"].toList()) { |
1986 | + if (participantMap.toMap().contains("identifier")) { |
1987 | + participants << participantMap.toMap()["identifier"].toString(); |
1988 | + } |
1989 | + } |
1990 | + if (!participants.isEmpty()) { |
1991 | + propMap["participantIds"] = participants; |
1992 | + } |
1993 | + } |
1994 | + |
1995 | + if (properties.contains("chatType")) { |
1996 | + chatType = properties["chatType"].toInt(); |
1997 | + } else { |
1998 | + if (participants.length() == 1) { |
1999 | + chatType = 1; |
2000 | + } |
2001 | + } |
2002 | + |
2003 | + if ((participants.count() == 0 && chatType == 1) || accountId.isEmpty()) { |
2004 | return NULL; |
2005 | } |
2006 | |
2007 | @@ -292,6 +335,15 @@ |
2008 | |
2009 | Q_FOREACH (ChatEntry *chatEntry, mChatEntries) { |
2010 | int participantCount = 0; |
2011 | + |
2012 | + if (chatType == 2) { |
2013 | + QString roomId = propMap["threadId"].toString(); |
2014 | + if (!roomId.isEmpty() && chatEntry->chatType() == 2 && roomId == chatEntry->chatId()) { |
2015 | + return chatEntry; |
2016 | + } |
2017 | + continue; |
2018 | + } |
2019 | + |
2020 | Tp::Contacts contacts = chatEntry->channel()->groupContacts(false); |
2021 | if (participants.count() != contacts.count()) { |
2022 | continue; |
2023 | @@ -320,19 +372,11 @@ |
2024 | |
2025 | if (create) { |
2026 | QDBusInterface *phoneAppHandler = TelepathyHelper::instance()->handlerInterface(); |
2027 | - phoneAppHandler->call("StartChat", accountId, participants); |
2028 | + phoneAppHandler->call("StartChat", accountId, propMap); |
2029 | } |
2030 | return NULL; |
2031 | } |
2032 | |
2033 | -ChatEntry *ChatManager::chatEntryForChatRoom(const QString &accountId, const QVariantMap &properties, bool create) |
2034 | -{ |
2035 | - Q_UNUSED(accountId) |
2036 | - Q_UNUSED(properties) |
2037 | - Q_UNUSED(create) |
2038 | - // FIXME: implement |
2039 | -} |
2040 | - |
2041 | QQmlListProperty<ChatEntry> ChatManager::chats() |
2042 | { |
2043 | return QQmlListProperty<ChatEntry>(this, 0, chatCount, chatAt); |
2044 | |
2045 | === modified file 'libtelephonyservice/chatmanager.h' |
2046 | --- libtelephonyservice/chatmanager.h 2015-12-07 16:26:20 +0000 |
2047 | +++ libtelephonyservice/chatmanager.h 2016-05-24 01:13:17 +0000 |
2048 | @@ -39,9 +39,8 @@ |
2049 | public: |
2050 | static ChatManager *instance(); |
2051 | |
2052 | - Q_INVOKABLE QString sendMessage(const QString &accountId, const QStringList &recipients, const QString &message, const QVariant &attachments = QVariant(), const QVariantMap &properties = QVariantMap()); |
2053 | - Q_INVOKABLE ChatEntry *chatEntryForParticipants(const QString &accountId, const QStringList &participants, bool create = false); |
2054 | - Q_INVOKABLE ChatEntry *chatEntryForChatRoom(const QString &accountId, const QVariantMap &properties, bool create); |
2055 | + Q_INVOKABLE QString sendMessage(const QString &accountId, const QString &message, const QVariant &attachments = QVariant(), const QVariantMap &properties = QVariantMap()); |
2056 | + Q_INVOKABLE ChatEntry *chatEntryForProperties(const QString &accountId, const QVariantMap &properties, bool create = false); |
2057 | |
2058 | QQmlListProperty<ChatEntry> chats(); |
2059 | static int chatCount(QQmlListProperty<ChatEntry> *p); |
2060 | |
2061 | === modified file 'libtelephonyservice/telepathyhelper.cpp' |
2062 | --- libtelephonyservice/telepathyhelper.cpp 2016-03-10 21:10:11 +0000 |
2063 | +++ libtelephonyservice/telepathyhelper.cpp 2016-05-24 01:13:17 +0000 |
2064 | @@ -56,6 +56,7 @@ |
2065 | "org.freedesktop.URfkill", |
2066 | QDBusConnection::systemBus()) |
2067 | { |
2068 | + qRegisterMetaType<QList<AccountEntry*> >(); |
2069 | mAccountFeatures << Tp::Account::FeatureCore |
2070 | << Tp::Account::FeatureProtocolInfo; |
2071 | mContactFeatures << Tp::Contact::FeatureAlias |
2072 | @@ -585,3 +586,14 @@ |
2073 | connectivityIface.asyncCall("UnlockAllModems"); |
2074 | } |
2075 | |
2076 | + |
2077 | +QList<AccountEntry*> TelepathyHelper::accountsForType(int type) |
2078 | +{ |
2079 | + QList<AccountEntry*> accounts; |
2080 | + Q_FOREACH(AccountEntry *account, mAccounts) { |
2081 | + if (account->type() == (AccountEntry::AccountType)type) { |
2082 | + accounts << account; |
2083 | + } |
2084 | + } |
2085 | + return accounts; |
2086 | +} |
2087 | |
2088 | === modified file 'libtelephonyservice/telepathyhelper.h' |
2089 | --- libtelephonyservice/telepathyhelper.h 2016-03-09 20:10:48 +0000 |
2090 | +++ libtelephonyservice/telepathyhelper.h 2016-05-24 01:13:17 +0000 |
2091 | @@ -31,6 +31,7 @@ |
2092 | #include <TelepathyQt/ConnectionManager> |
2093 | #include <TelepathyQt/Types> |
2094 | #include "channelobserver.h" |
2095 | +#include "accountentry.h" |
2096 | |
2097 | #define CANONICAL_TELEPHONY_VOICEMAIL_IFACE "com.canonical.Telephony.Voicemail" |
2098 | #define CANONICAL_TELEPHONY_AUDIOOUTPUTS_IFACE "com.canonical.Telephony.AudioOutputs" |
2099 | @@ -56,12 +57,19 @@ |
2100 | Q_PROPERTY(bool emergencyCallsAvailable READ emergencyCallsAvailable NOTIFY emergencyCallsAvailableChanged) |
2101 | Q_PROPERTY(QVariantMap simNames READ simNames NOTIFY simNamesChanged) |
2102 | Q_ENUMS(AccountType) |
2103 | + Q_ENUMS(ChatType) |
2104 | public: |
2105 | enum AccountType { |
2106 | Call, |
2107 | Messaging |
2108 | }; |
2109 | |
2110 | + enum ChatType { |
2111 | + ChatTypeNone = Tp::HandleTypeNone, |
2112 | + ChatTypeContact = Tp::HandleTypeContact, |
2113 | + ChatTypeRoom = Tp::HandleTypeRoom |
2114 | + }; |
2115 | + |
2116 | ~TelepathyHelper(); |
2117 | |
2118 | static TelepathyHelper *instance(); |
2119 | @@ -87,6 +95,7 @@ |
2120 | AccountEntry *accountForConnection(const Tp::ConnectionPtr &connection) const; |
2121 | Q_INVOKABLE AccountEntry *accountForId(const QString &accountId) const; |
2122 | Q_INVOKABLE void setDefaultAccount(AccountType type, AccountEntry* account); |
2123 | + Q_INVOKABLE QList<AccountEntry*> accountsForType(int type); |
2124 | bool emergencyCallsAvailable() const; |
2125 | Q_INVOKABLE void unlockSimCards() const; |
2126 | bool multiplePhoneAccounts() const; |
2127 | |
2128 | === modified file 'tests/common/mock/connection.cpp' |
2129 | --- tests/common/mock/connection.cpp 2016-03-31 19:29:44 +0000 |
2130 | +++ tests/common/mock/connection.cpp 2016-05-24 01:13:17 +0000 |
2131 | @@ -362,7 +362,9 @@ |
2132 | |
2133 | QStringList recipients; |
2134 | bool flash; |
2135 | - if (hints.contains(TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialInviteeHandles"))) { |
2136 | + if (hints.contains(TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialInviteeIDs"))) { |
2137 | + recipients = qdbus_cast<QStringList>(hints[TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialInviteeIDs")]); |
2138 | + } else if (hints.contains(TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialInviteeHandles"))) { |
2139 | recipients << inspectHandles(Tp::HandleTypeContact, qdbus_cast<Tp::UIntList>(hints[TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialInviteeHandles")]), error); |
2140 | } else { |
2141 | recipients << mHandles.value(targetHandle); |
2142 | @@ -465,11 +467,15 @@ |
2143 | const QString channelType = request.value(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType")).toString(); |
2144 | uint targetHandleType = request.value(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType")).toUInt(); |
2145 | uint targetHandle = request.value(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle")).toUInt(); |
2146 | + QString targetId = request.value(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID")).toString(); |
2147 | qDebug() << "MockConnection::createChannel" << targetHandle; |
2148 | if (mSelfPresence.type != Tp::ConnectionPresenceTypeAvailable) { |
2149 | error->set(TP_QT_ERROR_NETWORK_ERROR, "No network available"); |
2150 | return Tp::BaseChannelPtr(); |
2151 | } |
2152 | + if (!targetId.isEmpty()) { |
2153 | + targetHandle = ensureHandle(targetId); |
2154 | + } |
2155 | |
2156 | if (channelType == TP_QT_IFACE_CHANNEL_TYPE_TEXT) { |
2157 | return createTextChannel(targetHandleType, targetHandle, request, error); |
2158 | |
2159 | === modified file 'tests/handler/handlercontroller.cpp' |
2160 | --- tests/handler/handlercontroller.cpp 2015-12-07 16:26:20 +0000 |
2161 | +++ tests/handler/handlercontroller.cpp 2016-05-24 01:13:17 +0000 |
2162 | @@ -75,7 +75,11 @@ |
2163 | |
2164 | void HandlerController::startChat(const QString &accountId, const QStringList &recipients) |
2165 | { |
2166 | - mHandlerInterface.call("StartChat", accountId, recipients); |
2167 | + // TODO CHANGE SIGNATURE of this method |
2168 | + QVariantMap properties; |
2169 | + properties["participantIds"] = recipients; |
2170 | + |
2171 | + mHandlerInterface.call("StartChat", accountId, properties); |
2172 | } |
2173 | |
2174 | void HandlerController::startCall(const QString &number, const QString &accountId) |
2175 | @@ -131,7 +135,10 @@ |
2176 | |
2177 | QString HandlerController::sendMessage(const QString &accountId, const QStringList &recipients, const QString &message, const AttachmentList &attachments, const QVariantMap &properties) |
2178 | { |
2179 | - QDBusReply<QString> reply = mHandlerInterface.call("SendMessage", accountId, recipients, message, QVariant::fromValue(attachments), properties); |
2180 | + // TODO CHANGE SIGNATURE of this method |
2181 | + QVariantMap props = properties; |
2182 | + props["participantIds"] = recipients; |
2183 | + QDBusReply<QString> reply = mHandlerInterface.call("SendMessage", accountId, message, QVariant::fromValue(attachments), props); |
2184 | if (reply.isValid()) { |
2185 | return reply.value(); |
2186 | } |
2187 | |
2188 | === modified file 'tests/libtelephonyservice/ChatEntryTest.cpp' |
2189 | --- tests/libtelephonyservice/ChatEntryTest.cpp 2015-11-17 12:41:23 +0000 |
2190 | +++ tests/libtelephonyservice/ChatEntryTest.cpp 2016-05-24 01:13:17 +0000 |
2191 | @@ -96,11 +96,13 @@ |
2192 | MockController *mockController = accountId.startsWith("mock/mock") ? mGenericMockController : mMultimediaMockController; |
2193 | |
2194 | QSignalSpy chatEntryCreatedSpy(ChatManager::instance(), SIGNAL(chatEntryCreated(QString, QStringList,ChatEntry *))); |
2195 | - ChatEntry *entry = ChatManager::instance()->chatEntryForParticipants(accountId, participants, true); |
2196 | + QVariantMap properties; |
2197 | + properties["participantIds"] = participants; |
2198 | + ChatEntry *entry = ChatManager::instance()->chatEntryForProperties(accountId, properties, true); |
2199 | QVERIFY(entry == NULL); |
2200 | QTRY_COMPARE(chatEntryCreatedSpy.count(), 1); |
2201 | |
2202 | - entry = ChatManager::instance()->chatEntryForParticipants(accountId, participants, false); |
2203 | + entry = ChatManager::instance()->chatEntryForProperties(accountId, properties, false); |
2204 | QVERIFY(entry != NULL); |
2205 | QList<QVariant> arguments = chatEntryCreatedSpy.takeFirst(); |
2206 | QCOMPARE(accountId, arguments.at(0).toString()); |
2207 | |
2208 | === modified file 'tests/libtelephonyservice/ChatManagerTest.cpp' |
2209 | --- tests/libtelephonyservice/ChatManagerTest.cpp 2016-03-10 21:10:11 +0000 |
2210 | +++ tests/libtelephonyservice/ChatManagerTest.cpp 2016-05-24 01:13:17 +0000 |
2211 | @@ -104,7 +104,9 @@ |
2212 | QSignalSpy controllerMessageSentSpy(controller, SIGNAL(MessageSent(QString,QVariantList,QVariantMap))); |
2213 | QSignalSpy messageSentSpy(ChatManager::instance(), SIGNAL(messageSent(QStringList,QString))); |
2214 | |
2215 | - ChatManager::instance()->sendMessage(accountId, recipients, message); |
2216 | + QVariantMap properties; |
2217 | + properties["participantIds"] = recipients; |
2218 | + ChatManager::instance()->sendMessage(accountId, message, QVariantMap(), properties); |
2219 | |
2220 | TRY_COMPARE(controllerMessageSentSpy.count(), 1); |
2221 | QString messageText = controllerMessageSentSpy.first()[0].toString(); |
2222 | @@ -182,11 +184,14 @@ |
2223 | QStringList recipients; |
2224 | recipients << "user@domain.com" << "user2@domain.com"; |
2225 | QSignalSpy chatEntryCreatedSpy(ChatManager::instance(), SIGNAL(chatEntryCreated(QString, QStringList,ChatEntry *))); |
2226 | - ChatEntry *entry = ChatManager::instance()->chatEntryForParticipants("mock/mock/account0", recipients, true); |
2227 | + QVariantMap properties; |
2228 | + properties["participantIds"] = recipients; |
2229 | + |
2230 | + ChatEntry *entry = ChatManager::instance()->chatEntryForProperties("mock/mock/account0", properties, true); |
2231 | QVERIFY(entry == NULL); |
2232 | QTRY_COMPARE(chatEntryCreatedSpy.count(), 1); |
2233 | |
2234 | - entry = ChatManager::instance()->chatEntryForParticipants("mock/mock/account0", recipients, false); |
2235 | + entry = ChatManager::instance()->chatEntryForProperties("mock/mock/account0", properties, false); |
2236 | QVERIFY(entry != NULL); |
2237 | QList<QVariant> arguments = chatEntryCreatedSpy.takeFirst(); |
2238 | QCOMPARE(QString("mock/mock/account0"), arguments.at(0).toString()); |
2239 | @@ -226,7 +231,9 @@ |
2240 | attachmentList << QVariant::fromValue(attachment); |
2241 | QVariant attachments = QVariant::fromValue(attachmentList); |
2242 | |
2243 | - ChatManager::instance()->sendMessage(accountId, recipients, message, attachments); |
2244 | + QVariantMap properties; |
2245 | + properties["participantIds"] = recipients; |
2246 | + ChatManager::instance()->sendMessage(accountId, message, attachments, properties); |
2247 | |
2248 | TRY_COMPARE(controllerMessageSentSpy.count(), 1); |
2249 | QString messageText = controllerMessageSentSpy.first()[0].toString(); |