Merge lp:~phablet-team/telephony-service/async_send_message into lp:telephony-service

Proposed by Gustavo Pichorim Boiko
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
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.

To post a comment you must log in.
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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file '.bzrignore'
--- .bzrignore 2015-07-02 03:35:20 +0000
+++ .bzrignore 2016-05-24 01:13:17 +0000
@@ -57,3 +57,4 @@
57tests/libtelephonyservice/GreeterContactsTestExe57tests/libtelephonyservice/GreeterContactsTestExe
58tests/libtelephonyservice/GreeterContactsTestServerExe58tests/libtelephonyservice/GreeterContactsTestServerExe
59tests/libtelephonyservice/*Mock59tests/libtelephonyservice/*Mock
60tests/indicator/NotificationsInterface.*
6061
=== modified file 'approver/TelephonyServiceApprover.client'
--- approver/TelephonyServiceApprover.client 2013-07-17 17:50:32 +0000
+++ approver/TelephonyServiceApprover.client 2016-05-24 01:13:17 +0000
@@ -8,7 +8,6 @@
88
9[org.freedesktop.Telepathy.Client.Approver.ApproverChannelFilter 1]9[org.freedesktop.Telepathy.Client.Approver.ApproverChannelFilter 1]
10org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Text10org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Text
11org.freedesktop.Telepathy.Channel.TargetHandleType u=1
1211
13[org.freedesktop.Telepathy.Client.Approver.Capabilities]12[org.freedesktop.Telepathy.Client.Approver.Capabilities]
14org.freedesktop.Telepathy.Channel.Type.Call1/audio=true13org.freedesktop.Telepathy.Channel.Type.Call1/audio=true
1514
=== modified file 'approver/approver.cpp'
--- approver/approver.cpp 2016-01-05 17:14:32 +0000
+++ approver/approver.cpp 2016-05-24 01:13:17 +0000
@@ -412,10 +412,12 @@
412void Approver::onRejectMessage(Tp::ChannelDispatchOperationPtr dispatchOp, const char *action)412void Approver::onRejectMessage(Tp::ChannelDispatchOperationPtr dispatchOp, const char *action)
413{413{
414 if (mRejectActions.contains(action)) {414 if (mRejectActions.contains(action)) {
415 QString targetId = dispatchOp->channels().first()->targetContact()->id();415 QVariantMap properties;
416 properties["participantIds"] = QStringList() << dispatchOp->channels().first()->targetContact()->id();
416 ChatManager::instance()->sendMessage(dispatchOp->account()->uniqueIdentifier(),417 ChatManager::instance()->sendMessage(dispatchOp->account()->uniqueIdentifier(),
417 QStringList() << targetId,418 mRejectActions[action],
418 mRejectActions[action]);419 QVariantMap(), // attachments
420 properties);
419 }421 }
420422
421 onRejected(dispatchOp);423 onRejected(dispatchOp);
422424
=== modified file 'handler/CMakeLists.txt'
--- handler/CMakeLists.txt 2016-03-18 19:02:50 +0000
+++ handler/CMakeLists.txt 2016-05-24 01:13:17 +0000
@@ -1,8 +1,11 @@
11
2set(qt_SRCS2set(qt_SRCS
3 callhandler.cpp3 callhandler.cpp
4 chatstartingjob.cpp
4 handler.cpp5 handler.cpp
5 handlerdbus.cpp6 handlerdbus.cpp
7 messagejob.cpp
8 messagesendingjob.cpp
6 texthandler.cpp9 texthandler.cpp
7 )10 )
811
912
=== modified file 'handler/Handler.xml'
--- handler/Handler.xml 2015-12-07 16:26:20 +0000
+++ handler/Handler.xml 2016-05-24 01:13:17 +0000
@@ -16,13 +16,12 @@
16 Request to send a message to one or multiple recipients16 Request to send a message to one or multiple recipients
17 ]]></dox:d>17 ]]></dox:d>
18 <arg name="accountId" type="s" direction="in"/>18 <arg name="accountId" type="s" direction="in"/>
19 <arg name="recipients" type="as" direction="in"/>
20 <arg name="message" type="s" direction="in"/>19 <arg name="message" type="s" direction="in"/>
21 <arg name="attachments" type="a(sss)" direction="in"/>20 <arg name="attachments" type="a(sss)" direction="in"/>
22 <arg name="accountIdOut" type="s" direction="out"/>21 <arg name="accountIdOut" type="s" direction="out"/>
23 <annotation name="org.qtproject.QtDBus.QtTypeName.In3" value="AttachmentList"/>22 <annotation name="org.qtproject.QtDBus.QtTypeName.In2" value="AttachmentList"/>
24 <arg name="properties" type="a{sv}" direction="in"/>23 <arg name="properties" type="a{sv}" direction="in"/>
25 <annotation name="org.qtproject.QtDBus.QtTypeName.In4" value="QVariantMap"/>24 <annotation name="org.qtproject.QtDBus.QtTypeName.In3" value="QVariantMap"/>
26 </method>25 </method>
27 <method name="AcknowledgeMessages">26 <method name="AcknowledgeMessages">
28 <dox:d><![CDATA[27 <dox:d><![CDATA[
@@ -37,16 +36,8 @@
37 Start a chat with the given participants36 Start a chat with the given participants
38 ]]></dox:d>37 ]]></dox:d>
39 <arg name="accountId" type="s" direction="in"/>38 <arg name="accountId" type="s" direction="in"/>
40 <arg name="participants" type="as" direction="in"/>
41 </method>
42 <method name="StartChatRoom">
43 <dox:d><![CDATA[
44 Start a chat room with the given properties
45 ]]></dox:d>
46 <arg name="accountId" type="s" direction="in"/>
47 <arg name="initialParticipants" type="as" direction="in"/>
48 <arg name="properties" type="a{sv}" direction="in"/>39 <arg name="properties" type="a{sv}" direction="in"/>
49 <annotation name="org.qtproject.QtDBus.QtTypeName.In2" value="QVariantMap"/>40 <annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="QVariantMap"/>
50 </method>41 </method>
51 <method name="AcknowledgeAllMessages">42 <method name="AcknowledgeAllMessages">
52 <dox:d><![CDATA[43 <dox:d><![CDATA[
5344
=== modified file 'handler/TelephonyServiceHandler.client'
--- handler/TelephonyServiceHandler.client 2014-11-19 17:39:57 +0000
+++ handler/TelephonyServiceHandler.client 2016-05-24 01:13:17 +0000
@@ -3,11 +3,6 @@
33
4[org.freedesktop.Telepathy.Client.Handler.HandlerChannelFilter 0]4[org.freedesktop.Telepathy.Client.Handler.HandlerChannelFilter 0]
5org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Text5org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Text
6org.freedesktop.Telepathy.Channel.TargetHandleType u=16
77[org.freedesktop.Telepathy.Client.Handler.HandlerChannelFilter 3]
8[org.freedesktop.Telepathy.Client.Handler.HandlerChannelFilter 1]
9org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Text
10org.freedesktop.Telepathy.Channel.TargetHandleType u=0
11
12[org.freedesktop.Telepathy.Client.Handler.HandlerChannelFilter 2]
13org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Call18org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Call1
149
=== added file 'handler/chatstartingjob.cpp'
--- handler/chatstartingjob.cpp 1970-01-01 00:00:00 +0000
+++ handler/chatstartingjob.cpp 2016-05-24 01:13:17 +0000
@@ -0,0 +1,149 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * Authors:
5 * Tiago Salem Herrmann <tiago.herrmann@canonical.com>
6 * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com>
7 *
8 * This file is part of telephony-service.
9 *
10 * telephony-service is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 3.
13 *
14 * telephony-service is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#include "chatstartingjob.h"
24#include "telepathyhelper.h"
25#include "texthandler.h"
26#include <TelepathyQt/PendingChannelRequest>
27
28ChatStartingJob::ChatStartingJob(TextHandler *textHandler, const QString &accountId, const QVariantMap &properties)
29: MessageJob(textHandler), mAccountId(accountId), mProperties(properties)
30{
31}
32
33void ChatStartingJob::startJob()
34{
35 setStatus(Running);
36
37 // Request the contact to start chatting to
38 // FIXME: make it possible to select which account to use, for now, pick the first one
39 AccountEntry *account = TelepathyHelper::instance()->accountForId(mAccountId);
40 if (!account || !account->connected()) {
41 qCritical() << "The selected account does not have a connection. AccountId:" << mAccountId;
42 setStatus(Failed);
43 scheduleDeletion();
44 return;
45 }
46
47 switch(mProperties["chatType"].toUInt()) {
48 case Tp::HandleTypeNone:
49 case Tp::HandleTypeContact:
50 startTextChat(account->account(), mProperties);
51 break;
52 case Tp::HandleTypeRoom:
53 startTextChatRoom(account->account(), mProperties);
54 break;
55 default:
56 qCritical() << "Chat type not supported";
57 }
58}
59
60void ChatStartingJob::startTextChat(const Tp::AccountPtr &account, const QVariantMap &properties)
61{
62 Tp::PendingChannelRequest *op = NULL;
63 QStringList participants = properties["participantIds"].toStringList();
64 switch(participants.size()) {
65 case 0:
66 qCritical() << "Error: No participant list provided";
67 return;
68 case 1:
69 op = account->ensureTextChat(participants[0], QDateTime::currentDateTime(), TP_QT_IFACE_CLIENT + ".TelephonyServiceHandler");
70 break;
71 default:
72 op = account->createConferenceTextChat(QList<Tp::ChannelPtr>(), participants, QDateTime::currentDateTime(), TP_QT_IFACE_CLIENT + ".TelephonyServiceHandler");
73 }
74
75 if (!op) {
76 setStatus(Failed);
77 scheduleDeletion();
78 return;
79 }
80
81 connect(op, &Tp::PendingOperation::finished,
82 this, &ChatStartingJob::onChannelRequestFinished);
83}
84
85void ChatStartingJob::startTextChatRoom(const Tp::AccountPtr &account, const QVariantMap &properties)
86{
87 QString roomName = properties["threadId"].toString();
88
89 // these properties are still not used
90 //QString server = properties["Server"].toString();
91 //QString creator = properties["Creator"].toString();
92
93 QVariantMap request;
94 Tp::PendingChannelRequest *op = NULL;
95 if (roomName.isEmpty()) {
96 request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_TEXT);
97 request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) Tp::HandleTypeNone);
98 QStringList initialInviteeIDs = properties["participantIds"].toStringList();
99 if (!initialInviteeIDs.isEmpty()) {
100 request.insert(TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialInviteeIDs"), initialInviteeIDs);
101 }
102 // the presence of RoomName indicates the returned channel must be of type Room
103 request.insert(TP_QT_IFACE_CHANNEL_INTERFACE_ROOM + QLatin1String(".RoomName"), QString());
104
105 // TODO use the instance returned by createChanne() to track when the channel creation is finished
106 op = account->createChannel(request, QDateTime::currentDateTime(), TP_QT_IFACE_CLIENT + ".TelephonyServiceHandler");
107 } else {
108 op = account->ensureTextChatroom(roomName, QDateTime::currentDateTime(), TP_QT_IFACE_CLIENT + ".TelephonyServiceHandler", request);
109 }
110
111 if (!op) {
112 setStatus(Failed);
113 scheduleDeletion();
114 return;
115 }
116 connect(op, &Tp::PendingOperation::finished,
117 this, &ChatStartingJob::onChannelRequestFinished);
118}
119
120Tp::TextChannelPtr ChatStartingJob::textChannel() const
121{
122 return mTextChannel;
123}
124
125void ChatStartingJob::setTextChannel(Tp::TextChannelPtr channel)
126{
127 mTextChannel = channel;
128 Q_EMIT textChannelChanged();
129}
130
131void ChatStartingJob::onChannelRequestFinished(Tp::PendingOperation *op)
132{
133 Status status;
134 if (op->isError()) {
135 status = Failed;
136 } else {
137 Tp::PendingChannelRequest *channelRequest = qobject_cast<Tp::PendingChannelRequest*>(op);
138 if (!channelRequest) {
139 status = Failed;
140 } else {
141 setTextChannel(Tp::TextChannelPtr::dynamicCast(channelRequest->channelRequest()->channel()));
142 status = Finished;
143 }
144 }
145
146 setStatus(status);
147 scheduleDeletion();
148}
149
0150
=== added file 'handler/chatstartingjob.h'
--- handler/chatstartingjob.h 1970-01-01 00:00:00 +0000
+++ handler/chatstartingjob.h 2016-05-24 01:13:17 +0000
@@ -0,0 +1,64 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * Authors:
5 * Tiago Salem Herrmann <tiago.herrmann@canonical.com>
6 * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com>
7 *
8 * This file is part of telephony-service.
9 *
10 * telephony-service is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 3.
13 *
14 * telephony-service is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#ifndef CHATSTARTINGJOB_H
24#define CHATSTARTINGJOB_H
25
26#include <QObject>
27#include "messagejob.h"
28#include <TelepathyQt/Types>
29#include <TelepathyQt/PendingOperation>
30
31class TextHandler;
32
33class ChatStartingJob : public MessageJob
34{
35 Q_OBJECT
36 Q_PROPERTY(Tp::TextChannelPtr textChannel READ textChannel NOTIFY textChannelChanged)
37public:
38 ChatStartingJob(TextHandler *textHandler, const QString &accountId, const QVariantMap &properties);
39
40 Tp::TextChannelPtr textChannel() const;
41
42public Q_SLOTS:
43 virtual void startJob();
44
45Q_SIGNALS:
46 void textChannelChanged();
47
48
49protected Q_SLOTS:
50 void startTextChat(const Tp::AccountPtr &account, const QVariantMap &properties);
51 void startTextChatRoom(const Tp::AccountPtr &account, const QVariantMap &properties);
52 void setTextChannel(Tp::TextChannelPtr channel);
53
54 void onChannelRequestFinished(Tp::PendingOperation *op);
55
56private:
57 TextHandler *mTextHandler;
58 QString mAccountId;
59 QVariantMap mProperties;
60 Tp::TextChannelPtr mTextChannel;
61
62};
63
64#endif // CHATSTARTINGJOB_H
065
=== modified file 'handler/handlerdbus.cpp'
--- handler/handlerdbus.cpp 2015-12-07 16:26:20 +0000
+++ handler/handlerdbus.cpp 2016-05-24 01:13:17 +0000
@@ -81,6 +81,26 @@
81 Q_EMIT CallIndicatorVisibleChanged(visible);81 Q_EMIT CallIndicatorVisibleChanged(visible);
82}82}
8383
84QString HandlerDBus::registerObject(QObject *object, const QString &path)
85{
86 QString fullPath = QString("%1/%2").arg(DBUS_OBJECT_PATH, path);
87 if (QDBusConnection::sessionBus().registerObject(fullPath, object)) {
88 return fullPath;
89 }
90 return QString::null;
91}
92
93void HandlerDBus::unregisterObject(const QString &path)
94{
95 QDBusConnection::sessionBus().unregisterObject(path);
96}
97
98HandlerDBus *HandlerDBus::instance()
99{
100 static HandlerDBus *self = new HandlerDBus;
101 return self;
102}
103
84bool HandlerDBus::connectToBus()104bool HandlerDBus::connectToBus()
85{105{
86 bool ok = QDBusConnection::sessionBus().registerService(DBUS_SERVICE);106 bool ok = QDBusConnection::sessionBus().registerService(DBUS_SERVICE);
@@ -93,9 +113,9 @@
93 return true;113 return true;
94}114}
95115
96QString HandlerDBus::SendMessage(const QString &accountId, const QStringList &recipients, const QString &message, const AttachmentList &attachments, const QVariantMap &properties)116QString HandlerDBus::SendMessage(const QString &accountId, const QString &message, const AttachmentList &attachments, const QVariantMap &properties)
97{117{
98 return TextHandler::instance()->sendMessage(accountId, recipients, message, attachments, properties);118 return TextHandler::instance()->sendMessage(accountId, message, attachments, properties);
99}119}
100120
101void HandlerDBus::AcknowledgeMessages(const QStringList &numbers, const QStringList &messageIds, const QString &accountId)121void HandlerDBus::AcknowledgeMessages(const QStringList &numbers, const QStringList &messageIds, const QString &accountId)
@@ -103,14 +123,9 @@
103 TextHandler::instance()->acknowledgeMessages(numbers, messageIds, accountId);123 TextHandler::instance()->acknowledgeMessages(numbers, messageIds, accountId);
104}124}
105125
106void HandlerDBus::StartChat(const QString &accountId, const QStringList &participants)126void HandlerDBus::StartChat(const QString &accountId, const QVariantMap &properties)
107{127{
108 TextHandler::instance()->startChat(participants, accountId);128 TextHandler::instance()->startChat(accountId, properties);
109}
110
111void HandlerDBus::StartChatRoom(const QString &accountId, const QStringList &initialParticipants, const QVariantMap &properties)
112{
113 TextHandler::instance()->startChatRoom(accountId, initialParticipants, properties);
114}129}
115130
116void HandlerDBus::AcknowledgeAllMessages(const QStringList &numbers, const QString &accountId)131void HandlerDBus::AcknowledgeAllMessages(const QStringList &numbers, const QString &accountId)
117132
=== modified file 'handler/handlerdbus.h'
--- handler/handlerdbus.h 2015-12-07 16:26:20 +0000
+++ handler/handlerdbus.h 2016-05-24 01:13:17 +0000
@@ -30,7 +30,7 @@
30#include "dbustypes.h"30#include "dbustypes.h"
3131
32/**32/**
33 * DBus interface for the phone approver33 * DBus interface for the phone handler
34 */34 */
35class HandlerDBus : public QObject, protected QDBusContext35class HandlerDBus : public QObject, protected QDBusContext
36{36{
@@ -51,14 +51,18 @@
51 bool callIndicatorVisible() const;51 bool callIndicatorVisible() const;
52 void setCallIndicatorVisible(bool visible);52 void setCallIndicatorVisible(bool visible);
5353
54 QString registerObject(QObject *object, const QString &path);
55 void unregisterObject(const QString &path);
56
57 static HandlerDBus *instance();
58
54public Q_SLOTS:59public Q_SLOTS:
55 bool connectToBus();60 bool connectToBus();
5661
57 // messages related62 // messages related
58 QString SendMessage(const QString &accountId, const QStringList &recipients, const QString &message, const AttachmentList &attachments, const QVariantMap &properties);63 QString SendMessage(const QString &accountId, const QString &message, const AttachmentList &attachments, const QVariantMap &properties);
59 Q_NOREPLY void AcknowledgeMessages(const QStringList &numbers, const QStringList &messageIds, const QString &accountId);64 Q_NOREPLY void AcknowledgeMessages(const QStringList &numbers, const QStringList &messageIds, const QString &accountId);
60 Q_NOREPLY void StartChat(const QString &accountId, const QStringList &participants);65 Q_NOREPLY void StartChat(const QString &accountId, const QVariantMap &properties);
61 Q_NOREPLY void StartChatRoom(const QString &accountId, const QStringList &initialParticipants, const QVariantMap &properties);
62 Q_NOREPLY void AcknowledgeAllMessages(const QStringList &numbers, const QString &accountId);66 Q_NOREPLY void AcknowledgeAllMessages(const QStringList &numbers, const QString &accountId);
6367
64 // call related68 // call related
6569
=== modified file 'handler/main.cpp'
--- handler/main.cpp 2016-03-18 19:02:50 +0000
+++ handler/main.cpp 2016-05-24 01:13:17 +0000
@@ -54,10 +54,8 @@
54 QObject::connect(handler, SIGNAL(textChannelAvailable(Tp::TextChannelPtr)),54 QObject::connect(handler, SIGNAL(textChannelAvailable(Tp::TextChannelPtr)),
55 TextHandler::instance(), SLOT(onTextChannelAvailable(Tp::TextChannelPtr)));55 TextHandler::instance(), SLOT(onTextChannelAvailable(Tp::TextChannelPtr)));
5656
57 HandlerDBus dbus;
58
59 QObject::connect(TelepathyHelper::instance(), SIGNAL(setupReady()),57 QObject::connect(TelepathyHelper::instance(), SIGNAL(setupReady()),
60 &dbus, SLOT(connectToBus()));58 HandlerDBus::instance(), SLOT(connectToBus()));
6159
62 return app.exec();60 return app.exec();
63}61}
6462
=== added file 'handler/messagejob.cpp'
--- handler/messagejob.cpp 1970-01-01 00:00:00 +0000
+++ handler/messagejob.cpp 2016-05-24 01:13:17 +0000
@@ -0,0 +1,82 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * Authors:
5 * Tiago Salem Herrmann <tiago.herrmann@canonical.com>
6 * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com>
7 *
8 * This file is part of telephony-service.
9 *
10 * telephony-service is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 3.
13 *
14 * telephony-service is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#include "messagejob.h"
24#include <QCoreApplication>
25#include <QTime>
26#include <QTimer>
27
28MessageJob::MessageJob(QObject *parent)
29: QObject(parent), mStatus(Pending), mFinished(false)
30{
31}
32
33MessageJob::~MessageJob()
34{
35}
36
37MessageJob::Status MessageJob::status() const
38{
39 return mStatus;
40}
41
42bool MessageJob::isFinished() const
43{
44 return mFinished;
45}
46
47void MessageJob::waitForFinished(int timeout)
48{
49 QTime time;
50 time.start();
51 while (!mFinished && time.elapsed() < timeout) {
52 QCoreApplication::processEvents();
53 }
54}
55
56void MessageJob::startJob()
57{
58 // the default implementation just sets the status to Finished
59 setStatus(Finished);
60}
61
62void MessageJob::setStatus(MessageJob::Status status)
63{
64 mStatus = status;
65 Q_EMIT statusChanged();
66
67 // update the isFinished property too
68 bool wasFinished = mFinished;
69 mFinished = mStatus == Finished || mStatus == Failed;
70 if (wasFinished != mFinished) {
71 Q_EMIT isFinishedChanged();
72 }
73 if (mFinished) {
74 Q_EMIT finished();
75 }
76}
77
78void MessageJob::scheduleDeletion(int timeout)
79{
80 QTimer::singleShot(timeout, this, &QObject::deleteLater);
81}
82
083
=== added file 'handler/messagejob.h'
--- handler/messagejob.h 1970-01-01 00:00:00 +0000
+++ handler/messagejob.h 2016-05-24 01:13:17 +0000
@@ -0,0 +1,68 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * Authors:
5 * Tiago Salem Herrmann <tiago.herrmann@canonical.com>
6 * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com>
7 *
8 * This file is part of telephony-service.
9 *
10 * telephony-service is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 3.
13 *
14 * telephony-service is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#ifndef MESSAGEJOB_H
24#define MESSAGEJOB_H
25
26#include <QObject>
27
28class MessageJob : public QObject
29{
30 Q_OBJECT
31 Q_PROPERTY(Status status READ status NOTIFY statusChanged)
32 Q_PROPERTY(bool isFinished READ isFinished NOTIFY isFinishedChanged)
33 Q_ENUMS(Status)
34public:
35 enum Status {
36 Pending,
37 Initialising,
38 Running,
39 Finished,
40 Failed
41 };
42
43 explicit MessageJob(QObject *parent = 0);
44 virtual ~MessageJob();
45
46 Status status() const;
47 bool isFinished() const;
48
49 void waitForFinished(int timeout = 10000);
50
51Q_SIGNALS:
52 void statusChanged();
53 void isFinishedChanged();
54 void finished();
55
56public Q_SLOTS:
57 virtual void startJob();
58
59protected:
60 void setStatus(Status status);
61 void scheduleDeletion(int timeout = 60000);
62
63private:
64 Status mStatus;
65 bool mFinished;
66};
67
68#endif // MESSAGEJOB_H
069
=== added file 'handler/messagesendingjob.cpp'
--- handler/messagesendingjob.cpp 1970-01-01 00:00:00 +0000
+++ handler/messagesendingjob.cpp 2016-05-24 01:13:17 +0000
@@ -0,0 +1,375 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * Authors:
5 * Tiago Salem Herrmann <tiago.herrmann@canonical.com>
6 * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com>
7 *
8 * This file is part of telephony-service.
9 *
10 * telephony-service is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 3.
13 *
14 * telephony-service is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#include "accountentry.h"
24#include "chatstartingjob.h"
25#include "handlerdbus.h"
26#include "messagesendingjob.h"
27#include "telepathyhelper.h"
28#include "texthandler.h"
29#include <TelepathyQt/ContactManager>
30#include <TelepathyQt/PendingContacts>
31#include <QImage>
32
33#define SMIL_TEXT_REGION "<region id=\"Text\" width=\"100%\" height=\"100%\" fit=\"scroll\" />"
34#define SMIL_IMAGE_REGION "<region id=\"Image\" width=\"100%\" height=\"100%\" fit=\"meet\" />"
35#define SMIL_VIDEO_REGION "<region id=\"Video\" width=\"100%\" height=\"100%\" fit=\"meet\" />"
36#define SMIL_AUDIO_REGION "<region id=\"Audio\" width=\"100%\" height=\"100%\" fit=\"meet\" />"
37#define SMIL_TEXT_PART "<par dur=\"3s\">\
38 <text src=\"cid:%1\" region=\"Text\" />\
39 </par>"
40#define SMIL_IMAGE_PART "<par dur=\"5000ms\">\
41 <img src=\"cid:%1\" region=\"Image\" />\
42 </par>"
43#define SMIL_VIDEO_PART "<par>\
44 <video src=\"cid:%1\" region=\"Video\" />\
45 </par>"
46#define SMIL_AUDIO_PART "<par>\
47 <audio src=\"cid:%1\" region=\"Audio\" />\
48 </par>"
49
50#define SMIL_FILE "<smil>\
51 <head>\
52 <layout>\
53 %1\
54 </layout>\
55 </head>\
56 <body>\
57 %2\
58 </body>\
59 </smil>"
60
61MessageSendingJob::MessageSendingJob(TextHandler *textHandler, PendingMessage message)
62: MessageJob(textHandler), mMessage(message), mFinished(false)
63{
64 static ulong count = 0;
65 // just to avoid overflowing
66 if (count == ULONG_MAX) {
67 count = 0;
68 }
69 mObjectPath = HandlerDBus::instance()->registerObject(this, QString("messagesendingjob%1").arg(count++));
70}
71
72MessageSendingJob::~MessageSendingJob()
73{
74 HandlerDBus::instance()->unregisterObject(mObjectPath);
75}
76
77QString MessageSendingJob::accountId() const
78{
79 return mAccountId;
80}
81
82QString MessageSendingJob::channelObjectPath() const
83{
84 return mChannelObjectPath;
85}
86
87QString MessageSendingJob::objectPath() const
88{
89 return mObjectPath;
90}
91
92void MessageSendingJob::startJob()
93{
94 qDebug() << "Getting account for id:" << mMessage.accountId;
95 AccountEntry *account = TelepathyHelper::instance()->accountForId(mMessage.accountId);
96 if (!account) {
97 setStatus(Failed);
98 scheduleDeletion();
99 }
100
101 setStatus(Running);
102
103 // check if the message should be sent via multimedia account
104 // we just use fallback to 1-1 chats
105 if (account->type() == AccountEntry::PhoneAccount) {
106 Q_FOREACH(AccountEntry *newAccount, TelepathyHelper::instance()->accounts()) {
107 // TODO: we have to find the multimedia account that matches the same phone number,
108 // but for now we just pick any multimedia connected account
109 if (newAccount->type() != AccountEntry::MultimediaAccount) {
110 continue;
111 }
112 // FIXME: the fallback implementation needs to be changed to use protocol info and create a map of
113 // accounts. Also, it needs to check connection capabilities to determine if we can send message
114 // to offline contacts.
115 bool shouldFallback = true;
116 // if the account is offline, dont fallback to this account
117 if (!newAccount->connected()) {
118 continue;
119 }
120 QList<Tp::TextChannelPtr> channels = mTextHandler->existingChannels(newAccount->accountId(), mMessage.properties);
121 // check if we have a channel for this contact already and get the contact pointer from there,
122 // this way we avoid doing the while(op->isFinished()) all the time
123 if (!channels.isEmpty()) {
124 // FIXME: we need to re-evaluate the rules to fallback
125 // if the contact is known, force fallback to this account
126 Q_FOREACH(const Tp::ContactPtr &contact, channels.first()->groupContacts(false)) {
127 Tp::Presence presence = contact->presence();
128 shouldFallback = (presence.type() == Tp::ConnectionPresenceTypeAvailable ||
129 presence.type() == Tp::ConnectionPresenceTypeOffline);
130 if (!shouldFallback) {
131 break;
132 }
133 }
134 } else {
135 QStringList participantIds = mMessage.properties["participantIds"].toStringList();
136 Tp::PendingContacts *op = newAccount->account()->connection()->contactManager()->contactsForIdentifiers(participantIds);
137 while (!op->isFinished()) {
138 qApp->processEvents();
139 }
140 Q_FOREACH(const Tp::ContactPtr &contact, op->contacts()) {
141 Tp::Presence presence = contact->presence();
142 shouldFallback = (presence.type() == Tp::ConnectionPresenceTypeAvailable ||
143 presence.type() == Tp::ConnectionPresenceTypeOffline);
144 if (!shouldFallback) {
145 break;
146 }
147 }
148 }
149 if (shouldFallback) {
150 account = newAccount;
151 break;
152 }
153 }
154 }
155
156 // save the account
157 mAccount = account;
158 setAccountId(mAccount->accountId());
159
160 if (!account->connected()) {
161 connect(account, &AccountEntry::connectedChanged, [this, account]() {
162 if (account->connected()) {
163 findOrCreateChannel();
164 }
165 });
166 return;
167 }
168
169 findOrCreateChannel();
170}
171
172void MessageSendingJob::findOrCreateChannel()
173{
174 // now that we know what account to use, find existing channels or request a new one
175 QList<Tp::TextChannelPtr> channels = mTextHandler->existingChannels(mAccount->accountId(), mMessage.properties);
176 if (channels.isEmpty()) {
177 ChatStartingJob *job = new ChatStartingJob(mTextHandler, mAccount->accountId(), mMessage.properties);
178 connect(job, &MessageJob::finished, [this, job]() {
179 if (job->status() == MessageJob::Failed) {
180 setStatus(Failed);
181 scheduleDeletion();
182 return;
183 }
184
185 mTextChannel = job->textChannel();
186 sendMessage();
187 });
188 job->startJob();
189 }
190
191 mTextChannel = channels.last();
192 sendMessage();
193}
194
195void MessageSendingJob::sendMessage()
196{
197 Tp::PendingSendMessage *op = mTextChannel->send(buildMessage(mMessage));
198 connect(op, &Tp::PendingOperation::finished, [this, op]() {
199 if (op->isError()) {
200 setStatus(Failed);
201 scheduleDeletion();
202 return;
203 }
204
205 setChannelObjectPath(mTextChannel->objectPath());
206 setStatus(Finished);
207 scheduleDeletion();
208 });
209}
210
211void MessageSendingJob::setAccountId(const QString &accountId)
212{
213 mAccountId = accountId;
214 Q_EMIT accountIdChanged();
215}
216
217void MessageSendingJob::setChannelObjectPath(const QString &objectPath)
218{
219 mChannelObjectPath = objectPath;
220 Q_EMIT channelObjectPathChanged();
221}
222
223Tp::MessagePartList MessageSendingJob::buildMessage(const PendingMessage &pendingMessage)
224{
225 Tp::MessagePartList message;
226 Tp::MessagePart header;
227 QString smil, regions, parts;
228 bool hasImage = false, hasText = false, hasVideo = false, hasAudio = false, isMMS = false;
229
230 AccountEntry *account = TelepathyHelper::instance()->accountForId(pendingMessage.accountId);
231 if (!account) {
232 // account does not exist
233 return Tp::MessagePartList();
234 }
235
236 bool temporaryFiles = (pendingMessage.properties.contains("x-canonical-tmp-files") &&
237 pendingMessage.properties["x-canonical-tmp-files"].toBool());
238
239 // add the remaining properties to the message header
240 QVariantMap::const_iterator it = pendingMessage.properties.begin();
241 for (; it != pendingMessage.properties.end(); ++it) {
242 header[it.key()] = QDBusVariant(it.value());
243 }
244
245 // check if this message should be sent as an MMS
246 if (account->type() == AccountEntry::PhoneAccount) {
247 isMMS = (pendingMessage.attachments.size() > 0 ||
248 (header.contains("x-canonical-mms") && header["x-canonical-mms"].variant().toBool()) ||
249 (pendingMessage.properties["participantIds"].toStringList().size() > 1 && TelepathyHelper::instance()->mmsGroupChat()));
250 if (isMMS) {
251 header["x-canonical-mms"] = QDBusVariant(true);
252 }
253 }
254
255 // this flag should not be in the message header, it's only useful for the handler
256 header.remove("x-canonical-tmp-files");
257 header.remove("chatType");
258 header.remove("threadId");
259 header.remove("participantIds");
260
261 header["message-type"] = QDBusVariant(0);
262 message << header;
263
264 // convert AttachmentList struct into telepathy Message parts
265 Q_FOREACH(const AttachmentStruct &attachment, pendingMessage.attachments) {
266 QByteArray fileData;
267 QString newFilePath = QString(attachment.filePath).replace("file://", "");
268 QFile attachmentFile(newFilePath);
269 if (!attachmentFile.open(QIODevice::ReadOnly)) {
270 qWarning() << "fail to load attachment" << attachmentFile.errorString() << attachment.filePath;
271 continue;
272 }
273 if (attachment.contentType.startsWith("image/")) {
274 if (isMMS) {
275 hasImage = true;
276 parts += QString(SMIL_IMAGE_PART).arg(attachment.id);
277 // check if we need to reduce de image size in case it's bigger than 300k
278 // this check is only valid for MMS
279 if (attachmentFile.size() > 307200) {
280 QImage scaledImage(newFilePath);
281 if (!scaledImage.isNull()) {
282 QBuffer buffer(&fileData);
283 buffer.open(QIODevice::WriteOnly);
284 scaledImage.scaled(640, 640, Qt::KeepAspectRatio, Qt::SmoothTransformation).save(&buffer, "jpg");
285 }
286 } else {
287 fileData = attachmentFile.readAll();
288 }
289 }
290 } else if (attachment.contentType.startsWith("video/")) {
291 if (isMMS) {
292 hasVideo = true;
293 parts += QString(SMIL_VIDEO_PART).arg(attachment.id);
294 }
295 } else if (attachment.contentType.startsWith("audio/")) {
296 if (isMMS) {
297 hasAudio = true;
298 parts += QString(SMIL_AUDIO_PART).arg(attachment.id);
299 }
300 } else if (attachment.contentType.startsWith("text/plain")) {
301 if (isMMS) {
302 hasText = true;
303 parts += QString(SMIL_TEXT_PART).arg(attachment.id);
304 }
305 } else if (attachment.contentType.startsWith("text/vcard") ||
306 attachment.contentType.startsWith("text/x-vcard")) {
307 } else if (isMMS) {
308 // for MMS we just support the contentTypes above
309 if (temporaryFiles) {
310 attachmentFile.remove();
311 }
312 continue;
313 }
314
315 if (fileData.isEmpty()) {
316 fileData = attachmentFile.readAll();
317 }
318
319 if (temporaryFiles) {
320 attachmentFile.remove();
321 }
322
323 if (hasVideo) {
324 regions += QString(SMIL_VIDEO_REGION);
325 }
326
327 if (hasAudio) {
328 regions += QString(SMIL_AUDIO_REGION);
329 }
330
331 if (hasText) {
332 regions += QString(SMIL_TEXT_REGION);
333 }
334 if (hasImage) {
335 regions += QString(SMIL_IMAGE_REGION);
336 }
337
338 Tp::MessagePart part;
339 part["content-type"] = QDBusVariant(attachment.contentType);
340 part["identifier"] = QDBusVariant(attachment.id);
341 part["content"] = QDBusVariant(fileData);
342 part["size"] = QDBusVariant(fileData.size());
343
344 message << part;
345 }
346
347 if (!pendingMessage.message.isEmpty()) {
348 Tp::MessagePart part;
349 QString tmpTextId("text_0.txt");
350 part["content-type"] = QDBusVariant(QString("text/plain"));
351 part["identifier"] = QDBusVariant(tmpTextId);
352 part["content"] = QDBusVariant(pendingMessage.message);
353 part["size"] = QDBusVariant(pendingMessage.message.size());
354 if (isMMS) {
355 parts += QString(SMIL_TEXT_PART).arg(tmpTextId);
356 regions += QString(SMIL_TEXT_REGION);
357 }
358 message << part;
359 }
360
361 if (isMMS) {
362 Tp::MessagePart smilPart;
363 smil = QString(SMIL_FILE).arg(regions).arg(parts);
364 smilPart["content-type"] = QDBusVariant(QString("application/smil"));
365 smilPart["identifier"] = QDBusVariant(QString("smil.xml"));
366 smilPart["content"] = QDBusVariant(smil);
367 smilPart["size"] = QDBusVariant(smil.size());
368
369 message << smilPart;
370 }
371
372 return message;
373}
374
375
0376
=== added file 'handler/messagesendingjob.h'
--- handler/messagesendingjob.h 1970-01-01 00:00:00 +0000
+++ handler/messagesendingjob.h 2016-05-24 01:13:17 +0000
@@ -0,0 +1,87 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * Authors:
5 * Tiago Salem Herrmann <tiago.herrmann@canonical.com>
6 * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com>
7 *
8 * This file is part of telephony-service.
9 *
10 * telephony-service is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 3.
13 *
14 * telephony-service is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#ifndef MESSAGESENDINGJOB_H
24#define MESSAGESENDINGJOB_H
25
26#include <QObject>
27#include <QDBusContext>
28#include <TelepathyQt/Types>
29#include "dbustypes.h"
30#include "messagejob.h"
31
32class AccountEntry;
33class TextHandler;
34
35struct PendingMessage {
36 QString accountId;
37 QString message;
38 AttachmentList attachments;
39 QVariantMap properties;
40};
41Q_DECLARE_METATYPE(PendingMessage)
42
43class MessageSendingJob : public MessageJob, protected QDBusContext
44{
45 Q_OBJECT
46 Q_PROPERTY(QString accountId READ accountId NOTIFY accountIdChanged)
47 Q_PROPERTY(QString channelObjectPath READ channelObjectPath NOTIFY channelObjectPathChanged)
48 Q_PROPERTY(QString objectPath READ objectPath CONSTANT)
49
50public:
51 explicit MessageSendingJob(TextHandler *textHandler, PendingMessage message);
52 ~MessageSendingJob();
53
54 QString accountId() const;
55 QString channelObjectPath() const;
56 QString objectPath() const;
57
58Q_SIGNALS:
59 void accountIdChanged();
60 void channelObjectPathChanged();
61 void messageStatusChanged();
62
63public Q_SLOTS:
64 void startJob();
65
66protected Q_SLOTS:
67 void findOrCreateChannel();
68 void sendMessage();
69
70 void setAccountId(const QString &accountId);
71 void setChannelObjectPath(const QString &objectPath);
72
73private:
74 TextHandler *mTextHandler;
75 PendingMessage mMessage;
76 QString mAccountId;
77 AccountEntry *mAccount;
78 QString mChannelObjectPath;
79 Tp::TextChannelPtr mTextChannel;
80 QString mObjectPath;
81 bool mFinished;
82
83 Tp::MessagePartList buildMessage(const PendingMessage &pendingMessage);
84
85};
86
87#endif // MESSAGESENDINGJOB_H
088
=== modified file 'handler/texthandler.cpp'
--- handler/texthandler.cpp 2016-03-01 18:17:57 +0000
+++ handler/texthandler.cpp 2016-05-24 01:13:17 +0000
@@ -26,38 +26,12 @@
26#include "config.h"26#include "config.h"
27#include "dbustypes.h"27#include "dbustypes.h"
28#include "accountentry.h"28#include "accountentry.h"
29#include "chatstartingjob.h"
2930
30#include <QImage>31#include <QImage>
31#include <TelepathyQt/ContactManager>32#include <TelepathyQt/ContactManager>
32#include <TelepathyQt/PendingContacts>33#include <TelepathyQt/PendingContacts>
3334#include <TelepathyQt/PendingChannelRequest>
34#define SMIL_TEXT_REGION "<region id=\"Text\" width=\"100%\" height=\"100%\" fit=\"scroll\" />"
35#define SMIL_IMAGE_REGION "<region id=\"Image\" width=\"100%\" height=\"100%\" fit=\"meet\" />"
36#define SMIL_VIDEO_REGION "<region id=\"Video\" width=\"100%\" height=\"100%\" fit=\"meet\" />"
37#define SMIL_AUDIO_REGION "<region id=\"Audio\" width=\"100%\" height=\"100%\" fit=\"meet\" />"
38#define SMIL_TEXT_PART "<par dur=\"3s\">\
39 <text src=\"cid:%1\" region=\"Text\" />\
40 </par>"
41#define SMIL_IMAGE_PART "<par dur=\"5000ms\">\
42 <img src=\"cid:%1\" region=\"Image\" />\
43 </par>"
44#define SMIL_VIDEO_PART "<par>\
45 <video src=\"cid:%1\" region=\"Video\" />\
46 </par>"
47#define SMIL_AUDIO_PART "<par>\
48 <audio src=\"cid:%1\" region=\"Audio\" />\
49 </par>"
50
51#define SMIL_FILE "<smil>\
52 <head>\
53 <layout>\
54 %1\
55 </layout>\
56 </head>\
57 <body>\
58 %2\
59 </body>\
60 </smil>"
6135
62TextHandler::TextHandler(QObject *parent)36TextHandler::TextHandler(QObject *parent)
63: QObject(parent)37: QObject(parent)
@@ -93,7 +67,7 @@
93 }67 }
94 bool found = false;68 bool found = false;
95 // avoid adding twice the same list of participants69 // avoid adding twice the same list of participants
96 Q_FOREACH(const QStringList &recipients, recipientsList) {70/* Q_FOREACH(const QStringList &recipients, recipientsList) {
97 if (recipients == pendingMessage.recipients) {71 if (recipients == pendingMessage.recipients) {
98 found = true;72 found = true;
99 break;73 break;
@@ -101,10 +75,9 @@
101 }75 }
102 if (!found) {76 if (!found) {
103 recipientsList << pendingMessage.recipients;77 recipientsList << pendingMessage.recipients;
104 }78 }*/
105 }79 // TODO AVOID CALLING TWICE FOR SAME CHANNEL
106 Q_FOREACH(const QStringList& recipients, recipientsList) {80 startChat(accountId, pendingMessage.properties);
107 startChat(recipients, accountId);
108 }81 }
109 }82 }
110}83}
@@ -115,271 +88,33 @@
115 return handler;88 return handler;
116}89}
11790
118void TextHandler::startChat(const QStringList &recipients, const QString &accountId)91void TextHandler::startChat(const QString &accountId, const QVariantMap &properties)
119{92{
120 // Request the contact to start chatting to93 ChatStartingJob *job = new ChatStartingJob(this, accountId, properties);
121 // FIXME: make it possible to select which account to use, for now, pick the first one94 QTimer::singleShot(0, job, &ChatStartingJob::startJob);
122 AccountEntry *account = TelepathyHelper::instance()->accountForId(accountId);95 // FIXME: do we care about the result?
123 if (!account->connected()) {96}
124 qCritical() << "The selected account does not have a connection. AccountId:" << accountId;97
125 return;98QString TextHandler::sendMessage(const QString &accountId, const QString &message, const AttachmentList &attachments, const QVariantMap &properties)
126 }99{
127100 PendingMessage pendingMessage = {accountId, message, attachments, properties};
128 connect(account->account()->connection()->contactManager()->contactsForIdentifiers(recipients),101 MessageSendingJob *job = new MessageSendingJob(this, pendingMessage);
129 SIGNAL(finished(Tp::PendingOperation*)),102 QTimer::singleShot(0, job, &MessageSendingJob::startJob);
130 SLOT(onContactsAvailable(Tp::PendingOperation*)));103
131}104 // FIXME: just for a first stage, we synchronously wait for the job to finish and return the accountId as usual
132105 while (!job->isFinished()) {
133void TextHandler::startChatRoom(const QString &accountId, const QStringList &initialParticipants, const QVariantMap &properties)106 QCoreApplication::processEvents();
134{107 }
135 Q_UNUSED(accountId)108
136 Q_UNUSED(initialParticipants)109 return job->accountId();
137 Q_UNUSED(properties)
138 // FIXME: implement
139}
140
141void TextHandler::startChat(const Tp::AccountPtr &account, const Tp::Contacts &contacts)
142{
143 if (contacts.size() == 1) {
144 account->ensureTextChat(contacts.values()[0], QDateTime::currentDateTime(), TP_QT_IFACE_CLIENT + ".TelephonyServiceHandler");
145 } else {
146 account->createConferenceTextChat(QList<Tp::ChannelPtr>(), contacts.toList(), QDateTime::currentDateTime(), TP_QT_IFACE_CLIENT + ".TelephonyServiceHandler");
147 }
148 // start chatting to the contacts
149 Q_FOREACH(Tp::ContactPtr contact, contacts) {
150 // hold the ContactPtr to make sure its refcounting stays bigger than 0
151 mContacts[account->uniqueIdentifier()][contact->id()] = contact;
152 }
153}
154
155Tp::MessagePartList TextHandler::buildMessage(const PendingMessage &pendingMessage)
156{
157 Tp::MessagePartList message;
158 Tp::MessagePart header;
159 QString smil, regions, parts;
160 bool hasImage = false, hasText = false, hasVideo = false, hasAudio = false, isMMS = false;
161
162 AccountEntry *account = TelepathyHelper::instance()->accountForId(pendingMessage.accountId);
163 if (!account) {
164 // account does not exist
165 return Tp::MessagePartList();
166 }
167
168 bool temporaryFiles = (pendingMessage.properties.contains("x-canonical-tmp-files") &&
169 pendingMessage.properties["x-canonical-tmp-files"].toBool());
170
171 // add the remaining properties to the message header
172 QVariantMap::const_iterator it = pendingMessage.properties.begin();
173 for (; it != pendingMessage.properties.end(); ++it) {
174 header[it.key()] = QDBusVariant(it.value());
175 }
176
177 // check if this message should be sent as an MMS
178 if (account->type() == AccountEntry::PhoneAccount) {
179 isMMS = (pendingMessage.attachments.size() > 0 ||
180 (header.contains("x-canonical-mms") && header["x-canonical-mms"].variant().toBool()) ||
181 (pendingMessage.recipients.size() > 1 && TelepathyHelper::instance()->mmsGroupChat()));
182 if (isMMS) {
183 header["x-canonical-mms"] = QDBusVariant(true);
184 }
185 }
186
187 // this flag should not be in the message header, it's only useful for the handler
188 header.remove("x-canonical-tmp-files");
189
190 header["message-type"] = QDBusVariant(0);
191 message << header;
192
193 // convert AttachmentList struct into telepathy Message parts
194 Q_FOREACH(const AttachmentStruct &attachment, pendingMessage.attachments) {
195 QByteArray fileData;
196 QString newFilePath = QString(attachment.filePath).replace("file://", "");
197 QFile attachmentFile(newFilePath);
198 if (!attachmentFile.open(QIODevice::ReadOnly)) {
199 qWarning() << "fail to load attachment" << attachmentFile.errorString() << attachment.filePath;
200 continue;
201 }
202 if (attachment.contentType.startsWith("image/")) {
203 if (isMMS) {
204 hasImage = true;
205 parts += QString(SMIL_IMAGE_PART).arg(attachment.id);
206 // check if we need to reduce de image size in case it's bigger than 300k
207 // this check is only valid for MMS
208 if (attachmentFile.size() > 307200) {
209 QImage scaledImage(newFilePath);
210 if (!scaledImage.isNull()) {
211 QBuffer buffer(&fileData);
212 buffer.open(QIODevice::WriteOnly);
213 scaledImage.scaled(640, 640, Qt::KeepAspectRatio, Qt::SmoothTransformation).save(&buffer, "jpg");
214 }
215 } else {
216 fileData = attachmentFile.readAll();
217 }
218 }
219 } else if (attachment.contentType.startsWith("video/")) {
220 if (isMMS) {
221 hasVideo = true;
222 parts += QString(SMIL_VIDEO_PART).arg(attachment.id);
223 }
224 } else if (attachment.contentType.startsWith("audio/")) {
225 if (isMMS) {
226 hasAudio = true;
227 parts += QString(SMIL_AUDIO_PART).arg(attachment.id);
228 }
229 } else if (attachment.contentType.startsWith("text/plain")) {
230 if (isMMS) {
231 hasText = true;
232 parts += QString(SMIL_TEXT_PART).arg(attachment.id);
233 }
234 } else if (attachment.contentType.startsWith("text/vcard") ||
235 attachment.contentType.startsWith("text/x-vcard")) {
236 } else if (isMMS) {
237 // for MMS we just support the contentTypes above
238 if (temporaryFiles) {
239 attachmentFile.remove();
240 }
241 continue;
242 }
243
244 if (fileData.isEmpty()) {
245 fileData = attachmentFile.readAll();
246 }
247
248 if (temporaryFiles) {
249 attachmentFile.remove();
250 }
251
252 if (hasVideo) {
253 regions += QString(SMIL_VIDEO_REGION);
254 }
255
256 if (hasAudio) {
257 regions += QString(SMIL_AUDIO_REGION);
258 }
259
260 if (hasText) {
261 regions += QString(SMIL_TEXT_REGION);
262 }
263 if (hasImage) {
264 regions += QString(SMIL_IMAGE_REGION);
265 }
266
267 Tp::MessagePart part;
268 part["content-type"] = QDBusVariant(attachment.contentType);
269 part["identifier"] = QDBusVariant(attachment.id);
270 part["content"] = QDBusVariant(fileData);
271 part["size"] = QDBusVariant(fileData.size());
272
273 message << part;
274 }
275
276 if (!pendingMessage.message.isEmpty()) {
277 Tp::MessagePart part;
278 QString tmpTextId("text_0.txt");
279 part["content-type"] = QDBusVariant(QString("text/plain"));
280 part["identifier"] = QDBusVariant(tmpTextId);
281 part["content"] = QDBusVariant(pendingMessage.message);
282 part["size"] = QDBusVariant(pendingMessage.message.size());
283 if (isMMS) {
284 parts += QString(SMIL_TEXT_PART).arg(tmpTextId);
285 regions += QString(SMIL_TEXT_REGION);
286 }
287 message << part;
288 }
289
290 if (isMMS) {
291 Tp::MessagePart smilPart;
292 smil = QString(SMIL_FILE).arg(regions).arg(parts);
293 smilPart["content-type"] = QDBusVariant(QString("application/smil"));
294 smilPart["identifier"] = QDBusVariant(QString("smil.xml"));
295 smilPart["content"] = QDBusVariant(smil);
296 smilPart["size"] = QDBusVariant(smil.size());
297
298 message << smilPart;
299 }
300
301 return message;
302}
303
304QString TextHandler::sendMessage(const QString &accountId, const QStringList &recipients, const QString &message, const AttachmentList &attachments, const QVariantMap &properties)
305{
306 AccountEntry *account = TelepathyHelper::instance()->accountForId(accountId);
307 if (!account) {
308 // account does not exist
309 return QString();
310 }
311
312 // check if the message should be sent via multimedia account
313 // we just use fallback to 1-1 chats
314 if (account->type() == AccountEntry::PhoneAccount && recipients.size() == 1) {
315 Q_FOREACH(AccountEntry *newAccount, TelepathyHelper::instance()->accounts()) {
316 // TODO: we have to find the multimedia account that matches the same phone number,
317 // but for now we just pick any multimedia connected account
318 if (newAccount->type() != AccountEntry::MultimediaAccount) {
319 continue;
320 }
321 // FIXME: the fallback implementation needs to be changed to use protocol info and create a map of
322 // accounts. Also, it needs to check connection capabilities to determine if we can send message
323 // to offline contacts.
324 bool shouldFallback = false;
325 // if the account is offline, dont fallback to this account
326 if (!newAccount->connected()) {
327 continue;
328 }
329 QList<Tp::TextChannelPtr> channels = existingChannels(recipients, newAccount->accountId());
330 // check if we have a channel for this contact already and get the contact pointer from there,
331 // this way we avoid doing the while(op->isFinished()) all the time
332 if (!channels.isEmpty()) {
333 // if the contact is known, force fallback to this account
334 Tp::Presence presence = channels.first()->targetContact()->presence();
335 shouldFallback = (presence.type() == Tp::ConnectionPresenceTypeAvailable ||
336 presence.type() == Tp::ConnectionPresenceTypeOffline);
337 } else {
338 Tp::PendingOperation *op = newAccount->account()->connection()->contactManager()->contactsForIdentifiers(recipients);
339 while (!op->isFinished()) {
340 qApp->processEvents();
341 }
342 Tp::PendingContacts *pc = qobject_cast<Tp::PendingContacts*>(op);
343 if (pc) {
344 Tp::Presence presence = pc->contacts().first()->presence();
345 shouldFallback = (presence.type() == Tp::ConnectionPresenceTypeAvailable ||
346 presence.type() == Tp::ConnectionPresenceTypeOffline);
347 }
348 }
349 if (shouldFallback) {
350 account = newAccount;
351 break;
352 }
353 }
354 }
355
356 // keep recipient list always sorted to be able to compare
357 QStringList sortedRecipients = recipients;
358 sortedRecipients.sort();
359 PendingMessage pendingMessage = {account->accountId(), sortedRecipients, message, attachments, properties};
360
361 if (!account->connected()) {
362 mPendingMessages.append(pendingMessage);
363 return account->accountId();
364 }
365
366 QList<Tp::TextChannelPtr> channels = existingChannels(recipients, account->accountId());
367 if (channels.isEmpty()) {
368 mPendingMessages.append(pendingMessage);
369 startChat(sortedRecipients, account->accountId());
370 return account->accountId();
371 }
372
373 connect(channels.last()->send(buildMessage(pendingMessage)),
374 SIGNAL(finished(Tp::PendingOperation*)),
375 SLOT(onMessageSent(Tp::PendingOperation*)));
376
377 return account->accountId();
378}110}
379111
380void TextHandler::acknowledgeMessages(const QStringList &recipients, const QStringList &messageIds, const QString &accountId)112void TextHandler::acknowledgeMessages(const QStringList &recipients, const QStringList &messageIds, const QString &accountId)
381{113{
382 QList<Tp::TextChannelPtr> channels = existingChannels(recipients, accountId);114 QVariantMap properties;
115 properties["participantIds"] = recipients;
116
117 QList<Tp::TextChannelPtr> channels = existingChannels(accountId, properties);
383 if (channels.isEmpty()) {118 if (channels.isEmpty()) {
384 return;119 return;
385 }120 }
@@ -397,7 +132,9 @@
397132
398void TextHandler::acknowledgeAllMessages(const QStringList &recipients, const QString &accountId)133void TextHandler::acknowledgeAllMessages(const QStringList &recipients, const QString &accountId)
399{134{
400 QList<Tp::TextChannelPtr> channels = existingChannels(recipients, accountId);135 QVariantMap properties;
136 properties["participantIds"] = recipients;
137 QList<Tp::TextChannelPtr> channels = existingChannels(accountId, properties);
401 if (channels.isEmpty()) {138 if (channels.isEmpty()) {
402 return;139 return;
403 }140 }
@@ -411,14 +148,11 @@
411{148{
412 Tp::TextChannelPtr textChannel(qobject_cast<Tp::TextChannel*>(sender()));149 Tp::TextChannelPtr textChannel(qobject_cast<Tp::TextChannel*>(sender()));
413 mChannels.removeAll(textChannel);150 mChannels.removeAll(textChannel);
414 AccountEntry *account = TelepathyHelper::instance()->accountForConnection(textChannel->connection());
415 if (account) {
416 mContacts.remove(account->accountId());
417 }
418}151}
419152
420void TextHandler::onTextChannelAvailable(Tp::TextChannelPtr channel)153void TextHandler::onTextChannelAvailable(Tp::TextChannelPtr channel)
421{154{
155 qDebug() << "TextHandler::onTextChannelAvailable" << channel;
422 AccountEntry *account = TelepathyHelper::instance()->accountForConnection(channel->connection());156 AccountEntry *account = TelepathyHelper::instance()->accountForConnection(channel->connection());
423 if (!account) {157 if (!account) {
424 return;158 return;
@@ -438,10 +172,9 @@
438 QList<PendingMessage>::iterator it = mPendingMessages.begin();172 QList<PendingMessage>::iterator it = mPendingMessages.begin();
439 while (it != mPendingMessages.end()) {173 while (it != mPendingMessages.end()) {
440 bool found = false;174 bool found = false;
441 Q_FOREACH(const Tp::TextChannelPtr &existingChannel, existingChannels(it->recipients, it->accountId)) {175 Q_FOREACH(const Tp::TextChannelPtr &existingChannel, existingChannels(it->accountId, it->properties)) {
442 if (existingChannel == channel) {176 if (existingChannel == channel) {
443 // FIXME: we can't trust recipients for group chats in regular IM accounts177 sendMessage(it->accountId, it->message, it->attachments, it->properties);
444 sendMessage(it->accountId, it->recipients, it->message, it->attachments, it->properties);
445 it = mPendingMessages.erase(it);178 it = mPendingMessages.erase(it);
446 found = true;179 found = true;
447 break;180 break;
@@ -453,23 +186,15 @@
453 }186 }
454}187}
455188
456void TextHandler::onMessageSent(Tp::PendingOperation *op)189QList<Tp::TextChannelPtr> TextHandler::existingChannels(const QString &accountId, const QVariantMap &properties)
457{
458 Tp::PendingSendMessage *psm = qobject_cast<Tp::PendingSendMessage*>(op);
459 if(!psm) {
460 qWarning() << "The pending object was not a pending operation:" << op;
461 return;
462 }
463
464 if (psm->isError()) {
465 qWarning() << "Error sending message:" << psm->errorName() << psm->errorMessage();
466 return;
467 }
468}
469
470QList<Tp::TextChannelPtr> TextHandler::existingChannels(const QStringList &targetIds, const QString &accountId)
471{190{
472 QList<Tp::TextChannelPtr> channels;191 QList<Tp::TextChannelPtr> channels;
192 QStringList targetIds = properties["participantIds"].toStringList();
193 int chatType = properties["chatType"].toUInt();
194 if (chatType == 0 && targetIds.size() == 1) {
195 chatType = 1;
196 }
197 QString roomId = properties["threadId"].toString();
473198
474 Q_FOREACH(const Tp::TextChannelPtr &channel, mChannels) {199 Q_FOREACH(const Tp::TextChannelPtr &channel, mChannels) {
475 int count = 0;200 int count = 0;
@@ -479,6 +204,17 @@
479 continue;204 continue;
480 }205 }
481206
207 if (chatType != channel->targetHandleType()) {
208 continue;
209 }
210
211 if (chatType == 2) {
212 if (!roomId.isEmpty() && channel->targetHandleType() == chatType && roomId == channel->targetId()) {
213 channels.append(channel);
214 }
215 continue;
216 }
217
482 // this is a special case. We have to check if we are looking for a channel open with our self contact.218 // this is a special case. We have to check if we are looking for a channel open with our self contact.
483 bool channelToSelfContact = channel->groupContacts(true).size() == 1 && targetIds.size() == 1 &&219 bool channelToSelfContact = channel->groupContacts(true).size() == 1 && targetIds.size() == 1 &&
484 channel->targetHandleType() == Tp::HandleTypeContact &&220 channel->targetHandleType() == Tp::HandleTypeContact &&
@@ -507,17 +243,3 @@
507 }243 }
508 return channels;244 return channels;
509}245}
510
511void TextHandler::onContactsAvailable(Tp::PendingOperation *op)
512{
513 Tp::PendingContacts *pc = qobject_cast<Tp::PendingContacts*>(op);
514
515 if (!pc) {
516 qCritical() << "The pending object is not a Tp::PendingContacts";
517 return;
518 }
519 AccountEntry *account = TelepathyHelper::instance()->accountForConnection(pc->manager()->connection());
520 startChat(account->account(), pc->contacts().toSet());
521}
522
523
524246
=== modified file 'handler/texthandler.h'
--- handler/texthandler.h 2015-12-07 16:26:20 +0000
+++ handler/texthandler.h 2016-05-24 01:13:17 +0000
@@ -27,46 +27,35 @@
27#include <TelepathyQt/TextChannel>27#include <TelepathyQt/TextChannel>
28#include <TelepathyQt/ReceivedMessage>28#include <TelepathyQt/ReceivedMessage>
29#include "dbustypes.h"29#include "dbustypes.h"
3030#include "messagesendingjob.h"
31struct PendingMessage {
32 QString accountId;
33 QStringList recipients;
34 QString message;
35 AttachmentList attachments;
36 QVariantMap properties;
37};
38Q_DECLARE_METATYPE(PendingMessage)
3931
40class TextHandler : public QObject32class TextHandler : public QObject
41{33{
42 Q_OBJECT34 Q_OBJECT
43public:35public:
44 static TextHandler *instance();36 static TextHandler *instance();
45 void startChat(const QStringList &recipients, const QString &accountId);37 void startChat(const QString &accountId, const QVariantMap &properties);
46 void startChatRoom(const QString &accountId, const QStringList &initialParticipants, const QVariantMap &properties);38
47 void startChat(const Tp::AccountPtr &account, const Tp::Contacts &contacts);39 friend class MessageSendingJob;
4840
49public Q_SLOTS:41public Q_SLOTS:
50 QString sendMessage(const QString &accountId, const QStringList &recipients, const QString &message, const AttachmentList &attachments, const QVariantMap &properties);42 QString sendMessage(const QString &accountId, const QString &message, const AttachmentList &attachments, const QVariantMap &properties);
51 void acknowledgeMessages(const QStringList &recipients, const QStringList &messageIds, const QString &accountId);43 void acknowledgeMessages(const QStringList &recipients, const QStringList &messageIds, const QString &accountId);
52 void acknowledgeAllMessages(const QStringList &recipients, const QString &accountId);44 void acknowledgeAllMessages(const QStringList &recipients, const QString &accountId);
5345
54protected Q_SLOTS:46protected Q_SLOTS:
55 void onTextChannelAvailable(Tp::TextChannelPtr channel);47 void onTextChannelAvailable(Tp::TextChannelPtr channel);
56 void onTextChannelInvalidated();48 void onTextChannelInvalidated();
57 void onContactsAvailable(Tp::PendingOperation *op);
58 void onMessageSent(Tp::PendingOperation *op);
59 void onConnectedChanged();49 void onConnectedChanged();
6050
61protected:51protected:
62 QList<Tp::TextChannelPtr> existingChannels(const QStringList &targetIds, const QString &accountId);52 QList<Tp::TextChannelPtr> existingChannels(const QString &accountId, const QVariantMap &properties);
6353
64private:54private:
65 explicit TextHandler(QObject *parent = 0);55 explicit TextHandler(QObject *parent = 0);
66 Tp::MessagePartList buildMessage(const PendingMessage &pendingMessage);56
6757
68 QList<Tp::TextChannelPtr> mChannels;58 QList<Tp::TextChannelPtr> mChannels;
69 QMap<QString, QMap<QString, Tp::ContactPtr> > mContacts;
70 QList<PendingMessage> mPendingMessages;59 QList<PendingMessage> mPendingMessages;
71};60};
7261
7362
=== modified file 'indicator/TelephonyServiceIndicator.client'
--- indicator/TelephonyServiceIndicator.client 2014-11-21 13:58:47 +0000
+++ indicator/TelephonyServiceIndicator.client 2016-05-24 01:13:17 +0000
@@ -8,11 +8,6 @@
88
9[org.freedesktop.Telepathy.Client.Observer.ObserverChannelFilter 1]9[org.freedesktop.Telepathy.Client.Observer.ObserverChannelFilter 1]
10org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Text10org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Text
11org.freedesktop.Telepathy.Channel.TargetHandleType u=1
12
13[org.freedesktop.Telepathy.Client.Observer.ObserverChannelFilter 2]
14org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Text
15org.freedesktop.Telepathy.Channel.TargetHandleType u=0
1611
17[org.freedesktop.Telepathy.Client.Observer.Capabilities]12[org.freedesktop.Telepathy.Client.Observer.Capabilities]
18org.freedesktop.Telepathy.Channel.Type.Call1/audio=true13org.freedesktop.Telepathy.Channel.Type.Call1/audio=true
1914
=== modified file 'indicator/textchannelobserver.cpp'
--- indicator/textchannelobserver.cpp 2016-03-30 13:34:38 +0000
+++ indicator/textchannelobserver.cpp 2016-05-24 01:13:17 +0000
@@ -277,7 +277,9 @@
277 return;277 return;
278 }278 }
279279
280 ChatManager::instance()->sendMessage(account->accountId(), recipients, text);280 QVariantMap properties;
281 properties["participantIds"] = recipients;
282 ChatManager::instance()->sendMessage(account->accountId(), text, QVariantMap(), properties);
281}283}
282284
283void TextChannelObserver::clearNotifications()285void TextChannelObserver::clearNotifications()
@@ -341,6 +343,9 @@
341void TextChannelObserver::triggerNotificationForMessage(const Tp::ReceivedMessage &message, const QString &accountId, const QStringList &participantIds)343void TextChannelObserver::triggerNotificationForMessage(const Tp::ReceivedMessage &message, const QString &accountId, const QStringList &participantIds)
342{344{
343 Tp::ContactPtr contact = message.sender();345 Tp::ContactPtr contact = message.sender();
346 if (!contact) {
347 return;
348 }
344349
345 QByteArray token(message.messageToken().toUtf8());350 QByteArray token(message.messageToken().toUtf8());
346 if (!mUnreadMessages.contains(token)) {351 if (!mUnreadMessages.contains(token)) {
@@ -624,7 +629,7 @@
624 // we do not notify messages sent by ourselves on other devices, unless we629 // we do not notify messages sent by ourselves on other devices, unless we
625 // are dealing with phone accounts: #1547462630 // are dealing with phone accounts: #1547462
626 if (!account->account()->connection().isNull() && 631 if (!account->account()->connection().isNull() &&
627 message.sender()->handle().at(0) == account->account()->connection()->selfHandle() &&632 message.sender() && message.sender()->handle().at(0) == account->account()->connection()->selfHandle() &&
628 account->type() != AccountEntry::PhoneAccount) {633 account->type() != AccountEntry::PhoneAccount) {
629 return;634 return;
630 }635 }
631636
=== modified file 'libtelephonyservice/accountentry.cpp'
--- libtelephonyservice/accountentry.cpp 2015-11-23 20:01:58 +0000
+++ libtelephonyservice/accountentry.cpp 2016-05-24 01:13:17 +0000
@@ -106,6 +106,38 @@
106 mAccount->connection()->status() == Tp::ConnectionStatusConnected;106 mAccount->connection()->status() == Tp::ConnectionStatusConnected;
107}107}
108108
109AccountEntry::Capabilities AccountEntry::capabilities() const
110{
111 AccountEntry::Capabilities capabilities = CapabilityNone;
112
113 if (!connected()) {
114 return capabilities;
115 }
116
117 Tp::ConnectionCapabilities tpCapabilities = mAccount->capabilities();
118
119 if (tpCapabilities.textChatrooms()) {
120 capabilities |= (AccountEntry::Capabilities)AccountEntry::CapabilityTextChatrooms;
121 }
122 if (tpCapabilities.conferenceTextChats()) {
123 capabilities |= (AccountEntry::Capabilities)AccountEntry::CapabilityConferenceTextChats;
124 }
125 if (tpCapabilities.conferenceTextChatsWithInvitees()) {
126 capabilities |= (AccountEntry::Capabilities)AccountEntry::CapabilityConferenceTextChatsWithInvitees;
127 }
128 if (tpCapabilities.conferenceTextChatrooms()) {
129 capabilities |= (AccountEntry::Capabilities)AccountEntry::CapabilityConferenceTextChatrooms;
130 }
131 if (tpCapabilities.conferenceTextChatroomsWithInvitees()) {
132 capabilities |= (AccountEntry::Capabilities)AccountEntry::CapabilityConferenceTextChatroomsWithInvitees;
133 }
134 if (tpCapabilities.contactSearches()) {
135 capabilities |= (AccountEntry::Capabilities)AccountEntry::CapabilityContactSearches;
136 }
137
138 return capabilities;
139}
140
109Tp::AccountPtr AccountEntry::account() const141Tp::AccountPtr AccountEntry::account() const
110{142{
111 return mAccount;143 return mAccount;
@@ -219,6 +251,7 @@
219251
220 Q_EMIT connectedChanged();252 Q_EMIT connectedChanged();
221 Q_EMIT selfContactIdChanged();253 Q_EMIT selfContactIdChanged();
254 Q_EMIT capabilitiesChanged();
222}255}
223256
224void AccountEntry::addAccountLabel(const QString &accountId, QString &text)257void AccountEntry::addAccountLabel(const QString &accountId, QString &text)
225258
=== modified file 'libtelephonyservice/accountentry.h'
--- libtelephonyservice/accountentry.h 2015-11-23 20:01:58 +0000
+++ libtelephonyservice/accountentry.h 2016-05-24 01:13:17 +0000
@@ -45,6 +45,7 @@
45 Q_PROPERTY(bool connected READ connected NOTIFY connectedChanged)45 Q_PROPERTY(bool connected READ connected NOTIFY connectedChanged)
46 Q_PROPERTY(QStringList addressableVCardFields READ addressableVCardFields NOTIFY addressableVCardFieldsChanged)46 Q_PROPERTY(QStringList addressableVCardFields READ addressableVCardFields NOTIFY addressableVCardFieldsChanged)
47 Q_PROPERTY(Protocol* protocolInfo READ protocolInfo CONSTANT)47 Q_PROPERTY(Protocol* protocolInfo READ protocolInfo CONSTANT)
48 Q_PROPERTY(Capabilities capabilities READ capabilities NOTIFY capabilitiesChanged)
48 Q_ENUMS(AccountType)49 Q_ENUMS(AccountType)
49 friend class AccountEntryFactory;50 friend class AccountEntryFactory;
5051
@@ -55,6 +56,17 @@
55 GenericAccount56 GenericAccount
56 };57 };
5758
59 enum Capability {
60 CapabilityNone = 0,
61 CapabilityTextChatrooms = 1,
62 CapabilityConferenceTextChats = 2,
63 CapabilityConferenceTextChatsWithInvitees = 4,
64 CapabilityConferenceTextChatrooms = 8,
65 CapabilityConferenceTextChatroomsWithInvitees = 16,
66 CapabilityContactSearches = 32
67 };
68 Q_DECLARE_FLAGS(Capabilities, Capability);
69
58 bool ready() const;70 bool ready() const;
59 QString accountId() const;71 QString accountId() const;
60 QString displayName() const;72 QString displayName() const;
@@ -68,6 +80,7 @@
68 virtual bool compareIds(const QString &first, const QString &second) const;80 virtual bool compareIds(const QString &first, const QString &second) const;
69 virtual bool active() const;81 virtual bool active() const;
70 virtual bool connected() const;82 virtual bool connected() const;
83 Capabilities capabilities() const;
71 84
72 Protocol *protocolInfo() const;85 Protocol *protocolInfo() const;
7386
@@ -85,6 +98,7 @@
85 void addressableVCardFieldsChanged();98 void addressableVCardFieldsChanged();
86 void removed();99 void removed();
87 void connectionStatusChanged(Tp::ConnectionStatus status);100 void connectionStatusChanged(Tp::ConnectionStatus status);
101 void capabilitiesChanged();
88102
89protected Q_SLOTS:103protected Q_SLOTS:
90 virtual void initialize();104 virtual void initialize();
@@ -101,4 +115,6 @@
101 Protocol *mProtocol;115 Protocol *mProtocol;
102};116};
103117
118Q_DECLARE_OPERATORS_FOR_FLAGS(AccountEntry::Capabilities);
119
104#endif // ACCOUNTENTRY_H120#endif // ACCOUNTENTRY_H
105121
=== modified file 'libtelephonyservice/chatentry.cpp'
--- libtelephonyservice/chatentry.cpp 2015-08-04 19:50:53 +0000
+++ libtelephonyservice/chatentry.cpp 2016-05-24 01:13:17 +0000
@@ -31,7 +31,10 @@
3131
32ChatEntry::ChatEntry(const Tp::TextChannelPtr &channel, QObject *parent) :32ChatEntry::ChatEntry(const Tp::TextChannelPtr &channel, QObject *parent) :
33 QObject(parent),33 QObject(parent),
34 mChannel(channel)34 mChannel(channel),
35 roomInterface(NULL),
36 roomConfigInterface(NULL),
37 subjectInterface(NULL)
35{38{
36 qRegisterMetaType<ContactChatStates>();39 qRegisterMetaType<ContactChatStates>();
37 mAccount = TelepathyHelper::instance()->accountForConnection(mChannel->connection());40 mAccount = TelepathyHelper::instance()->accountForConnection(mChannel->connection());
@@ -40,12 +43,54 @@
40 mChatStates[contact->id()] = state;43 mChatStates[contact->id()] = state;
41 }44 }
4245
46 roomInterface = channel->optionalInterface<Tp::Client::ChannelInterfaceRoomInterface>();
47 roomConfigInterface = channel->optionalInterface<Tp::Client::ChannelInterfaceRoomConfigInterface>();
48 subjectInterface = channel->optionalInterface<Tp::Client::ChannelInterfaceSubjectInterface>();
49
50 if (roomInterface) {
51 roomInterface->setMonitorProperties(true);
52 connect(roomInterface, SIGNAL(propertiesChanged(const QVariantMap &,const QStringList &)),
53 SLOT(onRoomPropertiesChanged(const QVariantMap &,const QStringList &)));
54 }
55 if (roomConfigInterface) {
56 roomConfigInterface->setMonitorProperties(true);
57 connect(roomConfigInterface, SIGNAL(propertiesChanged(const QVariantMap &,const QStringList &)),
58 SLOT(onRoomPropertiesChanged(const QVariantMap &,const QStringList &)));
59 }
60 if (subjectInterface) {
61 subjectInterface->setMonitorProperties(true);
62 connect(subjectInterface, SIGNAL(propertiesChanged(const QVariantMap &,const QStringList &)),
63 SLOT(onRoomPropertiesChanged(const QVariantMap &,const QStringList &)));
64 }
65
43 connect(channel.data(), SIGNAL(chatStateChanged(const Tp::ContactPtr &, Tp::ChannelChatState)),66 connect(channel.data(), SIGNAL(chatStateChanged(const Tp::ContactPtr &, Tp::ChannelChatState)),
44 this, SLOT(onChatStateChanged(const Tp::ContactPtr &,Tp::ChannelChatState)));67 this, SLOT(onChatStateChanged(const Tp::ContactPtr &,Tp::ChannelChatState)));
45 connect(channel.data(), SIGNAL(groupMembersChanged(const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &,68 connect(channel.data(), SIGNAL(groupMembersChanged(const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &,
46 const Tp::Contacts &, const Tp::Channel::GroupMemberChangeDetails &)), this, SIGNAL(participantsChanged()));69 const Tp::Contacts &, const Tp::Channel::GroupMemberChangeDetails &)), this, SIGNAL(participantsChanged()));
47}70}
4871
72void ChatEntry::onRoomPropertiesChanged(const QVariantMap &changed,const QStringList &invalidated)
73{
74 if (changed.contains("RoomName")) {
75 mRoomName = changed["RoomName"].toString();
76 Q_EMIT roomNameChanged();
77 }
78 if (changed.contains("Title")) {
79 mTitle = changed["Title"].toString();
80 Q_EMIT titleChanged();
81 }
82}
83
84QString ChatEntry::roomName()
85{
86 return mRoomName;
87}
88
89QString ChatEntry::title()
90{
91 return mTitle;
92}
93
49ChatEntry::~ChatEntry()94ChatEntry::~ChatEntry()
50{95{
51 QMap<QString, ContactChatState*> tmp = mChatStates;96 QMap<QString, ContactChatState*> tmp = mChatStates;
@@ -56,6 +101,24 @@
56 it.next();101 it.next();
57 delete it.value();102 delete it.value();
58 }103 }
104
105 if (roomInterface) {
106 roomInterface->deleteLater();
107 }
108 if (roomConfigInterface) {
109 roomConfigInterface->deleteLater();
110 }
111 if (subjectInterface) {
112 subjectInterface->deleteLater();
113 }
114}
115
116QString ChatEntry::chatId()
117{
118 if (mChannel) {
119 return mChannel->targetId();
120 }
121 return QString();
59}122}
60123
61void ChatEntry::onChatStateChanged(const Tp::ContactPtr &contact, Tp::ChannelChatState state)124void ChatEntry::onChatStateChanged(const Tp::ContactPtr &contact, Tp::ChannelChatState state)
62125
=== modified file 'libtelephonyservice/chatentry.h'
--- libtelephonyservice/chatentry.h 2015-03-20 19:00:21 +0000
+++ libtelephonyservice/chatentry.h 2016-05-24 01:13:17 +0000
@@ -55,6 +55,9 @@
55 Q_PROPERTY(AccountEntry* account READ account CONSTANT)55 Q_PROPERTY(AccountEntry* account READ account CONSTANT)
56 Q_PROPERTY(ChatType chatType READ chatType CONSTANT)56 Q_PROPERTY(ChatType chatType READ chatType CONSTANT)
57 Q_PROPERTY(QStringList participants READ participants NOTIFY participantsChanged)57 Q_PROPERTY(QStringList participants READ participants NOTIFY participantsChanged)
58 Q_PROPERTY(QString roomName READ roomName NOTIFY roomNameChanged)
59 Q_PROPERTY(QString chatId READ chatId CONSTANT)
60 Q_PROPERTY(QString title READ title NOTIFY titleChanged)
58 Q_PROPERTY(QQmlListProperty<ContactChatState> chatStates61 Q_PROPERTY(QQmlListProperty<ContactChatState> chatStates
59 READ chatStates62 READ chatStates
60 NOTIFY chatStatesChanged)63 NOTIFY chatStatesChanged)
@@ -83,20 +86,31 @@
83 QQmlListProperty<ContactChatState> chatStates();86 QQmlListProperty<ContactChatState> chatStates();
84 QStringList participants();87 QStringList participants();
85 ChatType chatType();88 ChatType chatType();
89 QString chatId();
90 QString roomName();
91 QString title();
86 static int chatStatesCount(QQmlListProperty<ContactChatState> *p);92 static int chatStatesCount(QQmlListProperty<ContactChatState> *p);
87 static ContactChatState *chatStatesAt(QQmlListProperty<ContactChatState> *p, int index);93 static ContactChatState *chatStatesAt(QQmlListProperty<ContactChatState> *p, int index);
8894
89private Q_SLOTS:95private Q_SLOTS:
90 void onChatStateChanged(const Tp::ContactPtr &contact, Tp::ChannelChatState state);96 void onChatStateChanged(const Tp::ContactPtr &contact, Tp::ChannelChatState state);
97 void onRoomPropertiesChanged(const QVariantMap &changed,const QStringList &invalidated);
9198
92Q_SIGNALS:99Q_SIGNALS:
93 void chatStatesChanged();100 void chatStatesChanged();
94 void participantsChanged();101 void participantsChanged();
102 void roomNameChanged();
103 void titleChanged();
95104
96private:105private:
97 AccountEntry *mAccount;106 AccountEntry *mAccount;
98 Tp::TextChannelPtr mChannel;107 Tp::TextChannelPtr mChannel;
99 QMap<QString, ContactChatState*> mChatStates;108 QMap<QString, ContactChatState*> mChatStates;
109 QString mRoomName;
110 QString mTitle;
111 Tp::Client::ChannelInterfaceRoomInterface *roomInterface;
112 Tp::Client::ChannelInterfaceRoomConfigInterface *roomConfigInterface;
113 Tp::Client::ChannelInterfaceSubjectInterface *subjectInterface;
100};114};
101115
102#endif // CHATENTRY_H116#endif // CHATENTRY_H
103117
=== modified file 'libtelephonyservice/chatmanager.cpp'
--- libtelephonyservice/chatmanager.cpp 2016-03-07 19:27:55 +0000
+++ libtelephonyservice/chatmanager.cpp 2016-05-24 01:13:17 +0000
@@ -95,7 +95,7 @@
95 return manager;95 return manager;
96}96}
9797
98QString ChatManager::sendMessage(const QString &accountId, const QStringList &recipients, const QString &message, const QVariant &attachments, const QVariantMap &properties)98QString ChatManager::sendMessage(const QString &accountId, const QString &message, const QVariant &attachments, const QVariantMap &properties)
99{99{
100 AccountEntry *account = TelepathyHelper::instance()->accountForId(accountId);100 AccountEntry *account = TelepathyHelper::instance()->accountForId(accountId);
101101
@@ -103,9 +103,16 @@
103 return QString();103 return QString();
104 }104 }
105105
106 QVariantMap propMap = properties;
107
106 // check if files should be copied to a temporary location before passing them to handler108 // check if files should be copied to a temporary location before passing them to handler
107 bool tmpFiles = (properties.contains("x-canonical-tmp-files") && properties["x-canonical-tmp-files"].toBool());109 bool tmpFiles = (properties.contains("x-canonical-tmp-files") && properties["x-canonical-tmp-files"].toBool());
108110
111 // participants coming from qml are variants
112 if (properties.contains("participantIds")) {
113 propMap["participantIds"] = properties["participantIds"].toStringList();
114 }
115
109 AttachmentList newAttachments;116 AttachmentList newAttachments;
110 Q_FOREACH (const QVariant &attachment, attachments.toList()) {117 Q_FOREACH (const QVariant &attachment, attachments.toList()) {
111 AttachmentStruct newAttachment;118 AttachmentStruct newAttachment;
@@ -142,7 +149,7 @@
142 }149 }
143150
144 QDBusInterface *phoneAppHandler = TelepathyHelper::instance()->handlerInterface();151 QDBusInterface *phoneAppHandler = TelepathyHelper::instance()->handlerInterface();
145 QDBusReply<QString> reply = phoneAppHandler->call("SendMessage", account->accountId(), recipients, message, QVariant::fromValue(newAttachments), properties);152 QDBusReply<QString> reply = phoneAppHandler->call("SendMessage", account->accountId(), message, QVariant::fromValue(newAttachments), propMap);
146 if (reply.isValid()) {153 if (reply.isValid()) {
147 return reply.value();154 return reply.value();
148 }155 }
@@ -164,7 +171,7 @@
164 connect(channel.data(),171 connect(channel.data(),
165 SIGNAL(messageSent(Tp::Message,Tp::MessageSendingFlags,QString)),172 SIGNAL(messageSent(Tp::Message,Tp::MessageSendingFlags,QString)),
166 SLOT(onMessageSent(Tp::Message,Tp::MessageSendingFlags,QString)));173 SLOT(onMessageSent(Tp::Message,Tp::MessageSendingFlags,QString)));
167 connect(channel.data(),174 connect(channel.data(),
168 SIGNAL(invalidated(Tp::DBusProxy*,const QString&, const QString&)),175 SIGNAL(invalidated(Tp::DBusProxy*,const QString&, const QString&)),
169 SLOT(onChannelInvalidated()));176 SLOT(onChannelInvalidated()));
170177
@@ -206,6 +213,10 @@
206 return;213 return;
207 }214 }
208215
216 if (!message.sender()) {
217 return;
218 }
219
209 Q_EMIT messageReceived(message.sender()->id(), message.text(), message.received(), message.messageToken(), true);220 Q_EMIT messageReceived(message.sender()->id(), message.text(), message.received(), message.messageToken(), true);
210}221}
211222
@@ -278,9 +289,41 @@
278 return mChatEntries;289 return mChatEntries;
279}290}
280291
281ChatEntry *ChatManager::chatEntryForParticipants(const QString &accountId, const QStringList &participants, bool create)292ChatEntry *ChatManager::chatEntryForProperties(const QString &accountId, const QVariantMap &properties, bool create)
282{293{
283 if (participants.count() == 0 || accountId.isEmpty()) {294 QVariantMap propMap = properties;
295 int chatType = 0;
296
297 QStringList participants;
298 // participants coming from qml are variants
299 if (properties.contains("participantIds")) {
300 participants = properties["participantIds"].toStringList();
301 if (!participants.isEmpty()) {
302 propMap["participantIds"] = participants;
303 }
304 }
305
306 if (participants.isEmpty() && propMap.contains("participants")) {
307 // try to generate list of participants from "participants"
308 Q_FOREACH(const QVariant &participantMap, propMap["participants"].toList()) {
309 if (participantMap.toMap().contains("identifier")) {
310 participants << participantMap.toMap()["identifier"].toString();
311 }
312 }
313 if (!participants.isEmpty()) {
314 propMap["participantIds"] = participants;
315 }
316 }
317
318 if (properties.contains("chatType")) {
319 chatType = properties["chatType"].toInt();
320 } else {
321 if (participants.length() == 1) {
322 chatType = 1;
323 }
324 }
325
326 if ((participants.count() == 0 && chatType == 1) || accountId.isEmpty()) {
284 return NULL;327 return NULL;
285 }328 }
286329
@@ -292,6 +335,15 @@
292335
293 Q_FOREACH (ChatEntry *chatEntry, mChatEntries) {336 Q_FOREACH (ChatEntry *chatEntry, mChatEntries) {
294 int participantCount = 0;337 int participantCount = 0;
338
339 if (chatType == 2) {
340 QString roomId = propMap["threadId"].toString();
341 if (!roomId.isEmpty() && chatEntry->chatType() == 2 && roomId == chatEntry->chatId()) {
342 return chatEntry;
343 }
344 continue;
345 }
346
295 Tp::Contacts contacts = chatEntry->channel()->groupContacts(false);347 Tp::Contacts contacts = chatEntry->channel()->groupContacts(false);
296 if (participants.count() != contacts.count()) {348 if (participants.count() != contacts.count()) {
297 continue;349 continue;
@@ -320,19 +372,11 @@
320372
321 if (create) {373 if (create) {
322 QDBusInterface *phoneAppHandler = TelepathyHelper::instance()->handlerInterface();374 QDBusInterface *phoneAppHandler = TelepathyHelper::instance()->handlerInterface();
323 phoneAppHandler->call("StartChat", accountId, participants);375 phoneAppHandler->call("StartChat", accountId, propMap);
324 }376 }
325 return NULL;377 return NULL;
326}378}
327379
328ChatEntry *ChatManager::chatEntryForChatRoom(const QString &accountId, const QVariantMap &properties, bool create)
329{
330 Q_UNUSED(accountId)
331 Q_UNUSED(properties)
332 Q_UNUSED(create)
333 // FIXME: implement
334}
335
336QQmlListProperty<ChatEntry> ChatManager::chats()380QQmlListProperty<ChatEntry> ChatManager::chats()
337{381{
338 return QQmlListProperty<ChatEntry>(this, 0, chatCount, chatAt);382 return QQmlListProperty<ChatEntry>(this, 0, chatCount, chatAt);
339383
=== modified file 'libtelephonyservice/chatmanager.h'
--- libtelephonyservice/chatmanager.h 2015-12-07 16:26:20 +0000
+++ libtelephonyservice/chatmanager.h 2016-05-24 01:13:17 +0000
@@ -39,9 +39,8 @@
39public:39public:
40 static ChatManager *instance();40 static ChatManager *instance();
4141
42 Q_INVOKABLE QString sendMessage(const QString &accountId, const QStringList &recipients, const QString &message, const QVariant &attachments = QVariant(), const QVariantMap &properties = QVariantMap());42 Q_INVOKABLE QString sendMessage(const QString &accountId, const QString &message, const QVariant &attachments = QVariant(), const QVariantMap &properties = QVariantMap());
43 Q_INVOKABLE ChatEntry *chatEntryForParticipants(const QString &accountId, const QStringList &participants, bool create = false);43 Q_INVOKABLE ChatEntry *chatEntryForProperties(const QString &accountId, const QVariantMap &properties, bool create = false);
44 Q_INVOKABLE ChatEntry *chatEntryForChatRoom(const QString &accountId, const QVariantMap &properties, bool create);
4544
46 QQmlListProperty<ChatEntry> chats();45 QQmlListProperty<ChatEntry> chats();
47 static int chatCount(QQmlListProperty<ChatEntry> *p);46 static int chatCount(QQmlListProperty<ChatEntry> *p);
4847
=== modified file 'libtelephonyservice/telepathyhelper.cpp'
--- libtelephonyservice/telepathyhelper.cpp 2016-03-10 21:10:11 +0000
+++ libtelephonyservice/telepathyhelper.cpp 2016-05-24 01:13:17 +0000
@@ -56,6 +56,7 @@
56 "org.freedesktop.URfkill",56 "org.freedesktop.URfkill",
57 QDBusConnection::systemBus())57 QDBusConnection::systemBus())
58{58{
59 qRegisterMetaType<QList<AccountEntry*> >();
59 mAccountFeatures << Tp::Account::FeatureCore60 mAccountFeatures << Tp::Account::FeatureCore
60 << Tp::Account::FeatureProtocolInfo;61 << Tp::Account::FeatureProtocolInfo;
61 mContactFeatures << Tp::Contact::FeatureAlias62 mContactFeatures << Tp::Contact::FeatureAlias
@@ -585,3 +586,14 @@
585 connectivityIface.asyncCall("UnlockAllModems");586 connectivityIface.asyncCall("UnlockAllModems");
586}587}
587588
589
590QList<AccountEntry*> TelepathyHelper::accountsForType(int type)
591{
592 QList<AccountEntry*> accounts;
593 Q_FOREACH(AccountEntry *account, mAccounts) {
594 if (account->type() == (AccountEntry::AccountType)type) {
595 accounts << account;
596 }
597 }
598 return accounts;
599}
588600
=== modified file 'libtelephonyservice/telepathyhelper.h'
--- libtelephonyservice/telepathyhelper.h 2016-03-09 20:10:48 +0000
+++ libtelephonyservice/telepathyhelper.h 2016-05-24 01:13:17 +0000
@@ -31,6 +31,7 @@
31#include <TelepathyQt/ConnectionManager>31#include <TelepathyQt/ConnectionManager>
32#include <TelepathyQt/Types>32#include <TelepathyQt/Types>
33#include "channelobserver.h"33#include "channelobserver.h"
34#include "accountentry.h"
3435
35#define CANONICAL_TELEPHONY_VOICEMAIL_IFACE "com.canonical.Telephony.Voicemail"36#define CANONICAL_TELEPHONY_VOICEMAIL_IFACE "com.canonical.Telephony.Voicemail"
36#define CANONICAL_TELEPHONY_AUDIOOUTPUTS_IFACE "com.canonical.Telephony.AudioOutputs"37#define CANONICAL_TELEPHONY_AUDIOOUTPUTS_IFACE "com.canonical.Telephony.AudioOutputs"
@@ -56,12 +57,19 @@
56 Q_PROPERTY(bool emergencyCallsAvailable READ emergencyCallsAvailable NOTIFY emergencyCallsAvailableChanged)57 Q_PROPERTY(bool emergencyCallsAvailable READ emergencyCallsAvailable NOTIFY emergencyCallsAvailableChanged)
57 Q_PROPERTY(QVariantMap simNames READ simNames NOTIFY simNamesChanged)58 Q_PROPERTY(QVariantMap simNames READ simNames NOTIFY simNamesChanged)
58 Q_ENUMS(AccountType)59 Q_ENUMS(AccountType)
60 Q_ENUMS(ChatType)
59public:61public:
60 enum AccountType {62 enum AccountType {
61 Call,63 Call,
62 Messaging64 Messaging
63 };65 };
6466
67 enum ChatType {
68 ChatTypeNone = Tp::HandleTypeNone,
69 ChatTypeContact = Tp::HandleTypeContact,
70 ChatTypeRoom = Tp::HandleTypeRoom
71 };
72
65 ~TelepathyHelper();73 ~TelepathyHelper();
6674
67 static TelepathyHelper *instance();75 static TelepathyHelper *instance();
@@ -87,6 +95,7 @@
87 AccountEntry *accountForConnection(const Tp::ConnectionPtr &connection) const;95 AccountEntry *accountForConnection(const Tp::ConnectionPtr &connection) const;
88 Q_INVOKABLE AccountEntry *accountForId(const QString &accountId) const;96 Q_INVOKABLE AccountEntry *accountForId(const QString &accountId) const;
89 Q_INVOKABLE void setDefaultAccount(AccountType type, AccountEntry* account);97 Q_INVOKABLE void setDefaultAccount(AccountType type, AccountEntry* account);
98 Q_INVOKABLE QList<AccountEntry*> accountsForType(int type);
90 bool emergencyCallsAvailable() const;99 bool emergencyCallsAvailable() const;
91 Q_INVOKABLE void unlockSimCards() const;100 Q_INVOKABLE void unlockSimCards() const;
92 bool multiplePhoneAccounts() const;101 bool multiplePhoneAccounts() const;
93102
=== modified file 'tests/common/mock/connection.cpp'
--- tests/common/mock/connection.cpp 2016-03-31 19:29:44 +0000
+++ tests/common/mock/connection.cpp 2016-05-24 01:13:17 +0000
@@ -362,7 +362,9 @@
362362
363 QStringList recipients;363 QStringList recipients;
364 bool flash;364 bool flash;
365 if (hints.contains(TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialInviteeHandles"))) {365 if (hints.contains(TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialInviteeIDs"))) {
366 recipients = qdbus_cast<QStringList>(hints[TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialInviteeIDs")]);
367 } else if (hints.contains(TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialInviteeHandles"))) {
366 recipients << inspectHandles(Tp::HandleTypeContact, qdbus_cast<Tp::UIntList>(hints[TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialInviteeHandles")]), error);368 recipients << inspectHandles(Tp::HandleTypeContact, qdbus_cast<Tp::UIntList>(hints[TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialInviteeHandles")]), error);
367 } else {369 } else {
368 recipients << mHandles.value(targetHandle);370 recipients << mHandles.value(targetHandle);
@@ -465,11 +467,15 @@
465 const QString channelType = request.value(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType")).toString();467 const QString channelType = request.value(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType")).toString();
466 uint targetHandleType = request.value(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType")).toUInt();468 uint targetHandleType = request.value(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType")).toUInt();
467 uint targetHandle = request.value(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle")).toUInt();469 uint targetHandle = request.value(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle")).toUInt();
470 QString targetId = request.value(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID")).toString();
468 qDebug() << "MockConnection::createChannel" << targetHandle;471 qDebug() << "MockConnection::createChannel" << targetHandle;
469 if (mSelfPresence.type != Tp::ConnectionPresenceTypeAvailable) {472 if (mSelfPresence.type != Tp::ConnectionPresenceTypeAvailable) {
470 error->set(TP_QT_ERROR_NETWORK_ERROR, "No network available");473 error->set(TP_QT_ERROR_NETWORK_ERROR, "No network available");
471 return Tp::BaseChannelPtr();474 return Tp::BaseChannelPtr();
472 }475 }
476 if (!targetId.isEmpty()) {
477 targetHandle = ensureHandle(targetId);
478 }
473479
474 if (channelType == TP_QT_IFACE_CHANNEL_TYPE_TEXT) {480 if (channelType == TP_QT_IFACE_CHANNEL_TYPE_TEXT) {
475 return createTextChannel(targetHandleType, targetHandle, request, error);481 return createTextChannel(targetHandleType, targetHandle, request, error);
476482
=== modified file 'tests/handler/handlercontroller.cpp'
--- tests/handler/handlercontroller.cpp 2015-12-07 16:26:20 +0000
+++ tests/handler/handlercontroller.cpp 2016-05-24 01:13:17 +0000
@@ -75,7 +75,11 @@
7575
76void HandlerController::startChat(const QString &accountId, const QStringList &recipients)76void HandlerController::startChat(const QString &accountId, const QStringList &recipients)
77{77{
78 mHandlerInterface.call("StartChat", accountId, recipients);78 // TODO CHANGE SIGNATURE of this method
79 QVariantMap properties;
80 properties["participantIds"] = recipients;
81
82 mHandlerInterface.call("StartChat", accountId, properties);
79}83}
8084
81void HandlerController::startCall(const QString &number, const QString &accountId)85void HandlerController::startCall(const QString &number, const QString &accountId)
@@ -131,7 +135,10 @@
131135
132QString HandlerController::sendMessage(const QString &accountId, const QStringList &recipients, const QString &message, const AttachmentList &attachments, const QVariantMap &properties)136QString HandlerController::sendMessage(const QString &accountId, const QStringList &recipients, const QString &message, const AttachmentList &attachments, const QVariantMap &properties)
133{137{
134 QDBusReply<QString> reply = mHandlerInterface.call("SendMessage", accountId, recipients, message, QVariant::fromValue(attachments), properties);138 // TODO CHANGE SIGNATURE of this method
139 QVariantMap props = properties;
140 props["participantIds"] = recipients;
141 QDBusReply<QString> reply = mHandlerInterface.call("SendMessage", accountId, message, QVariant::fromValue(attachments), props);
135 if (reply.isValid()) {142 if (reply.isValid()) {
136 return reply.value();143 return reply.value();
137 }144 }
138145
=== modified file 'tests/libtelephonyservice/ChatEntryTest.cpp'
--- tests/libtelephonyservice/ChatEntryTest.cpp 2015-11-17 12:41:23 +0000
+++ tests/libtelephonyservice/ChatEntryTest.cpp 2016-05-24 01:13:17 +0000
@@ -96,11 +96,13 @@
96 MockController *mockController = accountId.startsWith("mock/mock") ? mGenericMockController : mMultimediaMockController;96 MockController *mockController = accountId.startsWith("mock/mock") ? mGenericMockController : mMultimediaMockController;
9797
98 QSignalSpy chatEntryCreatedSpy(ChatManager::instance(), SIGNAL(chatEntryCreated(QString, QStringList,ChatEntry *)));98 QSignalSpy chatEntryCreatedSpy(ChatManager::instance(), SIGNAL(chatEntryCreated(QString, QStringList,ChatEntry *)));
99 ChatEntry *entry = ChatManager::instance()->chatEntryForParticipants(accountId, participants, true);99 QVariantMap properties;
100 properties["participantIds"] = participants;
101 ChatEntry *entry = ChatManager::instance()->chatEntryForProperties(accountId, properties, true);
100 QVERIFY(entry == NULL);102 QVERIFY(entry == NULL);
101 QTRY_COMPARE(chatEntryCreatedSpy.count(), 1);103 QTRY_COMPARE(chatEntryCreatedSpy.count(), 1);
102104
103 entry = ChatManager::instance()->chatEntryForParticipants(accountId, participants, false);105 entry = ChatManager::instance()->chatEntryForProperties(accountId, properties, false);
104 QVERIFY(entry != NULL);106 QVERIFY(entry != NULL);
105 QList<QVariant> arguments = chatEntryCreatedSpy.takeFirst();107 QList<QVariant> arguments = chatEntryCreatedSpy.takeFirst();
106 QCOMPARE(accountId, arguments.at(0).toString());108 QCOMPARE(accountId, arguments.at(0).toString());
107109
=== modified file 'tests/libtelephonyservice/ChatManagerTest.cpp'
--- tests/libtelephonyservice/ChatManagerTest.cpp 2016-03-10 21:10:11 +0000
+++ tests/libtelephonyservice/ChatManagerTest.cpp 2016-05-24 01:13:17 +0000
@@ -104,7 +104,9 @@
104 QSignalSpy controllerMessageSentSpy(controller, SIGNAL(MessageSent(QString,QVariantList,QVariantMap)));104 QSignalSpy controllerMessageSentSpy(controller, SIGNAL(MessageSent(QString,QVariantList,QVariantMap)));
105 QSignalSpy messageSentSpy(ChatManager::instance(), SIGNAL(messageSent(QStringList,QString)));105 QSignalSpy messageSentSpy(ChatManager::instance(), SIGNAL(messageSent(QStringList,QString)));
106106
107 ChatManager::instance()->sendMessage(accountId, recipients, message);107 QVariantMap properties;
108 properties["participantIds"] = recipients;
109 ChatManager::instance()->sendMessage(accountId, message, QVariantMap(), properties);
108110
109 TRY_COMPARE(controllerMessageSentSpy.count(), 1);111 TRY_COMPARE(controllerMessageSentSpy.count(), 1);
110 QString messageText = controllerMessageSentSpy.first()[0].toString();112 QString messageText = controllerMessageSentSpy.first()[0].toString();
@@ -182,11 +184,14 @@
182 QStringList recipients;184 QStringList recipients;
183 recipients << "user@domain.com" << "user2@domain.com";185 recipients << "user@domain.com" << "user2@domain.com";
184 QSignalSpy chatEntryCreatedSpy(ChatManager::instance(), SIGNAL(chatEntryCreated(QString, QStringList,ChatEntry *)));186 QSignalSpy chatEntryCreatedSpy(ChatManager::instance(), SIGNAL(chatEntryCreated(QString, QStringList,ChatEntry *)));
185 ChatEntry *entry = ChatManager::instance()->chatEntryForParticipants("mock/mock/account0", recipients, true);187 QVariantMap properties;
188 properties["participantIds"] = recipients;
189
190 ChatEntry *entry = ChatManager::instance()->chatEntryForProperties("mock/mock/account0", properties, true);
186 QVERIFY(entry == NULL);191 QVERIFY(entry == NULL);
187 QTRY_COMPARE(chatEntryCreatedSpy.count(), 1);192 QTRY_COMPARE(chatEntryCreatedSpy.count(), 1);
188193
189 entry = ChatManager::instance()->chatEntryForParticipants("mock/mock/account0", recipients, false);194 entry = ChatManager::instance()->chatEntryForProperties("mock/mock/account0", properties, false);
190 QVERIFY(entry != NULL);195 QVERIFY(entry != NULL);
191 QList<QVariant> arguments = chatEntryCreatedSpy.takeFirst();196 QList<QVariant> arguments = chatEntryCreatedSpy.takeFirst();
192 QCOMPARE(QString("mock/mock/account0"), arguments.at(0).toString());197 QCOMPARE(QString("mock/mock/account0"), arguments.at(0).toString());
@@ -226,7 +231,9 @@
226 attachmentList << QVariant::fromValue(attachment);231 attachmentList << QVariant::fromValue(attachment);
227 QVariant attachments = QVariant::fromValue(attachmentList);232 QVariant attachments = QVariant::fromValue(attachmentList);
228233
229 ChatManager::instance()->sendMessage(accountId, recipients, message, attachments);234 QVariantMap properties;
235 properties["participantIds"] = recipients;
236 ChatManager::instance()->sendMessage(accountId, message, attachments, properties);
230237
231 TRY_COMPARE(controllerMessageSentSpy.count(), 1);238 TRY_COMPARE(controllerMessageSentSpy.count(), 1);
232 QString messageText = controllerMessageSentSpy.first()[0].toString();239 QString messageText = controllerMessageSentSpy.first()[0].toString();

Subscribers

People subscribed via source and target branches

to all changes: