Merge lp:~phablet-team/messaging-framework/enable_message_broadcast into lp:messaging-framework

Proposed by Gustavo Pichorim Boiko
Status: Superseded
Proposed branch: lp:~phablet-team/messaging-framework/enable_message_broadcast
Merge into: lp:messaging-framework
Diff against target: 1370 lines (+784/-115)
22 files modified
debian/changelog (+18/-0)
include/messaging/broadcast.h (+45/-0)
include/messaging/group.h (+15/-2)
include/messaging/group_manager.h (+19/-10)
include/messaging/has_interfaces.h (+5/-1)
include/messaging/interface.h (+5/-0)
include/messaging/qt/tp/interfaces/base_channel_subject.h (+88/-0)
include/messaging/qt/tp/interfaces/base_channel_subject_internal.h (+59/-0)
include/messaging/qt/tp/interfaces/channel_interface_roles_adaptor.h (+1/-0)
include/messaging/qt/tp/interfaces/types.h (+2/-1)
include/messaging/qt/tp/text_channel.h (+15/-5)
include/messaging/recipient.h (+2/-1)
src/CMakeLists.txt (+4/-0)
src/messaging/broadcast.cpp (+37/-0)
src/messaging/group.cpp (+37/-3)
src/messaging/group_manager.cpp (+12/-6)
src/messaging/has_interfaces.cpp (+9/-2)
src/messaging/qt/tp/connection.cpp (+97/-62)
src/messaging/qt/tp/interfaces/base_channel_roles.cpp (+1/-1)
src/messaging/qt/tp/interfaces/base_channel_subject.cpp (+205/-0)
src/messaging/qt/tp/text_channel.cpp (+104/-21)
tests/mock_group_manager.h (+4/-0)
To merge this branch: bzr merge lp:~phablet-team/messaging-framework/enable_message_broadcast
Reviewer Review Type Date Requested Status
system-apps-ci-bot continuous-integration Needs Fixing
Ubuntu Phablet Team Pending
Review via email: mp+306014@code.launchpad.net

This proposal has been superseded by a proposal from 2016-09-17.

Commit message

Add a broadcast recipient type and make it possible to use broadcast text
channels.

Description of the change

Add a broadcast recipient type and make it possible to use broadcast text
channels.

To post a comment you must log in.
Revision history for this message
system-apps-ci-bot (system-apps-ci-bot) wrote :

FAILED: Continuous integration, rev:62
https://jenkins.canonical.com/system-apps/job/lp-messaging-framework-ci/75/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/system-apps/job/build/1541/console
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-0-fetch/1541
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=vivid+overlay/1389
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=vivid+overlay/1389/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=xenial+overlay/1389
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=xenial+overlay/1389/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=yakkety/1389
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=yakkety/1389/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=vivid+overlay/1389
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=vivid+overlay/1389/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1389
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1389/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=yakkety/1389
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=yakkety/1389/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=vivid+overlay/1389
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=vivid+overlay/1389/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=xenial+overlay/1389
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=xenial+overlay/1389/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=yakkety/1389/console

Click here to trigger a rebuild:
https://jenkins.canonical.com/system-apps/job/lp-messaging-framework-ci/75/rebuild

review: Needs Fixing (continuous-integration)
63. By Roberto Mier Escandon

merged prereq branch

64. By Gustavo Pichorim Boiko

Do not crash if the Roles interface is not available

65. By Gustavo Pichorim Boiko

Use an ID for the broadcast recipient.

66. By Roberto Mier Escandon

merged prereq lp:~phablet-team/messaging-framework/fix-roles-interface-event

67. By Roberto Mier Escandon

creating broadcast using group_starter, for it to have an initial id

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/changelog'
2--- debian/changelog 2016-08-25 20:07:12 +0000
3+++ debian/changelog 2016-09-17 21:47:53 +0000
4@@ -1,3 +1,21 @@
5+messaging-framework (0.1-1ubuntu28) vivid; urgency=medium
6+
7+ * Subject interface
8+
9+ -- Roberto Mier Escandon <roberto.escandon@canonical.com> Wed, 14 Sep 2016 13:04:50 +0200
10+
11+messaging-framework (0.1-1ubuntu27) vivid; urgency=medium
12+
13+ * snapshot
14+
15+ -- Roberto Mier Escandon <roberto.escandon@canonical.com> Tue, 13 Sep 2016 18:11:06 +0200
16+
17+messaging-framework (0.1-1ubuntu26) vivid; urgency=medium
18+
19+ * Group has additional properties if plugins want to add there their specific values
20+
21+ -- Roberto Mier Escandon <roberto.escandon@canonical.com> Mon, 12 Sep 2016 17:01:04 +0200
22+
23 messaging-framework (0.1-1ubuntu25) vivid; urgency=medium
24
25 * Fixed self handle included in members
26
27=== added file 'include/messaging/broadcast.h'
28--- include/messaging/broadcast.h 1970-01-01 00:00:00 +0000
29+++ include/messaging/broadcast.h 2016-09-17 21:47:53 +0000
30@@ -0,0 +1,45 @@
31+/*
32+ * Copyright © 2016 Canonical Ltd.
33+ *
34+ * This program is free software: you can redistribute it and/or modify it
35+ * under the terms of the GNU Lesser General Public License version 3,
36+ * as published by the Free Software Foundation.
37+ *
38+ * This program is distributed in the hope that it will be useful,
39+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
40+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
41+ * GNU Lesser General Public License for more details.
42+ *
43+ * You should have received a copy of the GNU Lesser General Public License
44+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
45+ */
46+
47+#ifndef BROADCAST_H
48+#define BROADCAST_H
49+
50+#include <messaging/recipient.h>
51+#include <messaging/member.h>
52+#include <messaging/members.h>
53+
54+namespace messaging
55+{
56+
57+class MESSAGING_FW_PUBLIC Broadcast : public Recipient
58+{
59+public:
60+ Broadcast(const Members &members = Members{});
61+
62+ RecipientType type() const override;
63+ Members members() const;
64+
65+ typedef std::shared_ptr<Broadcast> shared_ptr;
66+private:
67+ /// @cond
68+ struct Private;
69+ std::shared_ptr<Private> impl;
70+ /// @endcond
71+};
72+
73+}
74+
75+#endif // BROADCAST_H
76
77=== modified file 'include/messaging/group.h'
78--- include/messaging/group.h 2016-08-17 13:25:23 +0000
79+++ include/messaging/group.h 2016-09-17 21:47:53 +0000
80@@ -27,15 +27,28 @@
81 class MESSAGING_FW_PUBLIC Group : public Recipient
82 {
83 public:
84+ static const std::string ROOM_NAME;
85+ static const std::string DESCRIPTION;
86+ static const std::string SERVER;
87+ static const std::string CREATION_TIMESTAMP;
88+ static const std::string SUBJECT;
89+
90 Group(std::string id,
91 const Members &initial_invitees = Members{},
92 std::string initial_title = std::string{},
93- const std::shared_ptr<Member> &creator = std::make_shared<Member>(std::string{}));
94-
95+ const std::shared_ptr<Member> &creator = std::make_shared<Member>(std::string{}),
96+ const VariantMap &additional_properties = VariantMap{});
97+
98 RecipientType type() const override;
99+
100 Members initial_invitees() const;
101 std::string initial_title() const;
102 std::shared_ptr<Member> creator() const;
103+ VariantMap &additional_properties();
104+
105+ std::shared_ptr<Variant> additional_property(const std::string &key) const;
106+ void set_additional_property(const std::string &key, const std::shared_ptr<messaging::Variant> &value);
107+ bool exists_additional_property(const std::string &key) const;
108
109 typedef std::shared_ptr<Group> shared_ptr;
110 private:
111
112=== modified file 'include/messaging/group_manager.h'
113--- include/messaging/group_manager.h 2016-08-25 11:04:57 +0000
114+++ include/messaging/group_manager.h 2016-09-17 21:47:53 +0000
115@@ -33,11 +33,12 @@
116 // Maintain sequence of 2 multiples if adding new values to preserve flags management
117 enum class GroupPermissions : uint
118 {
119- NoPermissions = 0, //0
120- CanChangeTitle = 1 << 0, //1
121- CanKick = 1 << 1, //2
122- CanSetAdmin = 1 << 2, //4
123- CanDissolve = 1 << 3 //8
124+ NoPermissions = 0, //0
125+ CanChangeTitle = 1 << 0, //1
126+ CanKick = 1 << 1, //2
127+ CanSetAdmin = 1 << 2, //4
128+ CanDissolve = 1 << 3, //8
129+ CanChangeSubject = 1 << 4 //16
130 };
131
132 enum class CancelGroupReason
133@@ -62,8 +63,9 @@
134
135 virtual void on_group_created() = 0;
136 virtual void on_group_cancelled(CancelGroupReason reason, const std::string &message) = 0;
137- virtual void on_group_title_changed(const std::string& new_title,
138- const Member& actor,
139+ virtual void on_group_title_changed(const std::string& new_title) = 0;
140+ virtual void on_group_subject_changed(const std::string& new_subject,
141+ const std::shared_ptr<Member>& actor,
142 const std::chrono::system_clock::time_point& when) = 0;
143 virtual void on_members_updated(const Members& members) = 0;
144 virtual void on_group_permissions_changed(const Flags<GroupPermissions> &permissions) = 0;
145@@ -88,12 +90,18 @@
146 /// @brief change_group_title modifies the title of the group
147 virtual void change_group_title(const std::string& title) = 0;
148
149+ /// @brief change_group_subject modifies the subject of the group
150+ virtual void change_group_subject(const std::string& subject) = 0;
151+
152 /// @brief group_id returns the id of the group being managed
153 virtual std::string group_id() = 0;
154
155 /// @brief group_title returns the title of the group being managed
156 virtual std::string group_title() = 0;
157
158+ /// @brief group_subject returns the subject of the group being managed
159+ virtual std::string group_subject() = 0;
160+
161 /// @brief creator returns the creator of the group being managed
162 virtual std::shared_ptr<Member> group_creator() = 0;
163
164@@ -117,9 +125,10 @@
165
166 void announce_group_created();
167 void announce_group_cancelled(CancelGroupReason reason, const std::string& message);
168- void announce_group_title_changed(const std::string& new_title,
169- const Member& actor = Member{std::string{}},
170- const std::chrono::system_clock::time_point& when = std::chrono::system_clock::now());
171+ void announce_group_title_changed(const std::string& new_title);
172+ void announce_group_subject_changed(const std::string& new_subject,
173+ const std::shared_ptr<Member>& actor = std::make_shared<Member>(std::string{}),
174+ const std::chrono::system_clock::time_point& when = std::chrono::system_clock::now());
175 void announce_members_updated(const Members& members);
176 void announce_group_permissions_changed(const Flags<GroupPermissions> &permissions);
177
178
179=== modified file 'include/messaging/has_interfaces.h'
180--- include/messaging/has_interfaces.h 2016-03-30 19:19:19 +0000
181+++ include/messaging/has_interfaces.h 2016-09-17 21:47:53 +0000
182@@ -22,7 +22,7 @@
183 namespace messaging
184 {
185
186-class MESSAGING_FW_PUBLIC HasInterfaces
187+class MESSAGING_FW_PUBLIC HasInterfaces : public std::enable_shared_from_this<HasInterfaces>
188 {
189 public:
190 virtual ~HasInterfaces() = default;
191@@ -51,6 +51,10 @@
192 protected:
193 HasInterfaces();
194
195+ /// @brief on_interface_plugged overwrite this virtual method in subclasses if wanted to perform any action when
196+ /// certain interface is plugged
197+ virtual void on_interface_plugged(const std::shared_ptr<Interface>& interface);
198+
199 private:
200 /// @cond
201 struct Private;
202
203=== modified file 'include/messaging/interface.h'
204--- include/messaging/interface.h 2016-03-30 19:19:19 +0000
205+++ include/messaging/interface.h 2016-09-17 21:47:53 +0000
206@@ -26,6 +26,7 @@
207 namespace messaging
208 {
209
210+class HasInterfaces;
211 class Interface;
212
213 typedef std::set<std::shared_ptr<Interface>, std::owner_less<std::shared_ptr<Interface>>> InterfacesSet;
214@@ -34,6 +35,10 @@
215 {
216 public:
217 virtual ~Interface() = default;
218+
219+ /// @brief on_plugged executed when this interfaces is plugged to a host object. Overwrite this method
220+ /// in subclasses if wanted certain behaviour when plug happens.
221+ virtual void on_plugged(const std::weak_ptr<HasInterfaces> &where) = 0;
222 };
223
224 }
225
226=== added file 'include/messaging/qt/tp/interfaces/base_channel_subject.h'
227--- include/messaging/qt/tp/interfaces/base_channel_subject.h 1970-01-01 00:00:00 +0000
228+++ include/messaging/qt/tp/interfaces/base_channel_subject.h 2016-09-17 21:47:53 +0000
229@@ -0,0 +1,88 @@
230+/*
231+ * Copyright © 2016 Canonical Ltd.
232+ *
233+ * This program is free software: you can redistribute it and/or modify it
234+ * under the terms of the GNU Lesser General Public License version 3,
235+ * as published by the Free Software Foundation.
236+ *
237+ * This program is distributed in the hope that it will be useful,
238+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
239+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
240+ * GNU Lesser General Public License for more details.
241+ *
242+ * You should have received a copy of the GNU Lesser General Public License
243+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
244+ */
245+
246+#ifndef MESSAGING_QT_TP_INTERFACES_BASE_CHANNEL_SUBJECT_H
247+#define MESSAGING_QT_TP_INTERFACES_BASE_CHANNEL_SUBJECT_H
248+
249+#include <TelepathyQt/BaseChannel>
250+
251+#include <messaging/visibility.h>
252+
253+#include <messaging/qt/tp/interfaces/types.h>
254+
255+namespace messaging
256+{
257+namespace qt
258+{
259+namespace tp
260+{
261+namespace interfaces
262+{
263+
264+class MESSAGING_FW_LOCAL BaseChannelSubjectInterface : public Tp::AbstractChannelInterface
265+{
266+ Q_OBJECT
267+ Q_DISABLE_COPY(BaseChannelSubjectInterface)
268+
269+public:
270+ static BaseChannelSubjectInterfacePtr create() {
271+ return BaseChannelSubjectInterfacePtr(new BaseChannelSubjectInterface());
272+ }
273+ template<typename BaseChannelSubjectInterfaceSubclass>
274+ static Tp::SharedPtr<BaseChannelSubjectInterfaceSubclass> create() {
275+ return Tp::SharedPtr<BaseChannelSubjectInterfaceSubclass>(
276+ new BaseChannelSubjectInterfaceSubclass());
277+ }
278+ virtual ~BaseChannelSubjectInterface();
279+
280+ QVariantMap immutableProperties() const;
281+
282+ QString subject() const;
283+ void setSubject(const QString& subject);
284+
285+ QString actor() const;
286+ void setActor(const QString &actor);
287+
288+ uint actorHandle() const;
289+ void setActorHandle(uint handle);
290+
291+ qlonglong timestamp() const;
292+ void setTimestamp(qlonglong timestamp);
293+
294+ bool canSet() const;
295+ void setCanSet(bool canSet);
296+
297+ typedef Tp::Callback2<void, const QString&, Tp::DBusError*> SetSubjectCallback;
298+ void setSetSubjectCallback(const SetSubjectCallback &cb);
299+ void setSubject(const QString &subject, Tp::DBusError *error);
300+
301+private:
302+ BaseChannelSubjectInterface();
303+ void createAdaptor();
304+
305+ class Adaptee;
306+ friend class Adaptee;
307+ struct Private;
308+ friend struct Private;
309+ Private *mPriv;
310+};
311+
312+
313+}
314+}
315+}
316+}
317+#endif // MESSAGING_QT_TP_INTERFACES_BASE_CHANNEL_SUBJECT_H
318
319=== added file 'include/messaging/qt/tp/interfaces/base_channel_subject_internal.h'
320--- include/messaging/qt/tp/interfaces/base_channel_subject_internal.h 1970-01-01 00:00:00 +0000
321+++ include/messaging/qt/tp/interfaces/base_channel_subject_internal.h 2016-09-17 21:47:53 +0000
322@@ -0,0 +1,59 @@
323+/*
324+ * Copyright © 2016 Canonical Ltd.
325+ *
326+ * This program is free software: you can redistribute it and/or modify it
327+ * under the terms of the GNU Lesser General Public License version 3,
328+ * as published by the Free Software Foundation.
329+ *
330+ * This program is distributed in the hope that it will be useful,
331+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
332+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
333+ * GNU Lesser General Public License for more details.
334+ *
335+ * You should have received a copy of the GNU Lesser General Public License
336+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
337+ */
338+
339+#ifndef MESSAGING_QT_TP_INTERFACES_BASE_CHANNEL_SUBJECT_INTERNAL_H_
340+#define MESSAGING_QT_TP_INTERFACES_BASE_CHANNEL_SUBJECT_INTERNAL_H_
341+
342+#include <TelepathyQt/_gen/svc-channel.h>
343+#include <messaging/qt/tp/interfaces/base_channel_subject.h>
344+#include <messaging/visibility.h>
345+
346+namespace messaging
347+{
348+namespace qt
349+{
350+namespace tp
351+{
352+namespace interfaces
353+{
354+
355+class MESSAGING_FW_LOCAL BaseChannelSubjectInterface::Adaptee : public QObject
356+{
357+ Q_OBJECT
358+public:
359+ Adaptee(BaseChannelSubjectInterface *interface);
360+ ~Adaptee();
361+
362+ QString subject() const;
363+ QString actor() const;
364+ uint actorHandle() const;
365+ qlonglong timestamp() const;
366+ bool canSet() const;
367+
368+public Q_SLOTS:
369+ void setSubject(const QString &subject, const Tp::Service::ChannelInterfaceSubjectAdaptor::SetSubjectContextPtr &context);
370+
371+public:
372+ BaseChannelSubjectInterface *mInterface;
373+};
374+
375+}
376+}
377+}
378+}
379+
380+#endif // MESSAGING_QT_TP_INTERFACES_BASE_CHANNEL_SUBJECT_INTERNAL_H_
381+
382
383=== modified file 'include/messaging/qt/tp/interfaces/channel_interface_roles_adaptor.h'
384--- include/messaging/qt/tp/interfaces/channel_interface_roles_adaptor.h 2016-08-11 21:39:57 +0000
385+++ include/messaging/qt/tp/interfaces/channel_interface_roles_adaptor.h 2016-09-17 21:47:53 +0000
386@@ -13,6 +13,7 @@
387 * You should have received a copy of the GNU Lesser General Public License
388 * along with this program. If not, see <http://www.gnu.org/licenses/>.
389 */
390+
391 #ifndef MESSAGING_QT_TP_INTERFACES_CHANNEL_INTERFACE_ROLES_ADAPTOR_H
392 #define MESSAGING_QT_TP_INTERFACES_CHANNEL_INTERFACE_ROLES_ADAPTOR_H
393
394
395=== modified file 'include/messaging/qt/tp/interfaces/types.h'
396--- include/messaging/qt/tp/interfaces/types.h 2016-08-16 16:23:42 +0000
397+++ include/messaging/qt/tp/interfaces/types.h 2016-09-17 21:47:53 +0000
398@@ -33,10 +33,11 @@
399
400 class BaseChannelDestroyableInterface;
401 class BaseChannelRolesInterface;
402+class BaseChannelSubjectInterface;
403
404 typedef Tp::SharedPtr<BaseChannelDestroyableInterface> BaseChannelDestroyableInterfacePtr;
405 typedef Tp::SharedPtr<BaseChannelRolesInterface> BaseChannelRolesInterfacePtr;
406-
407+typedef Tp::SharedPtr<BaseChannelSubjectInterface> BaseChannelSubjectInterfacePtr;
408
409 /**
410 * \struct HandleRolesMap
411
412=== modified file 'include/messaging/qt/tp/text_channel.h'
413--- include/messaging/qt/tp/text_channel.h 2016-08-30 18:46:08 +0000
414+++ include/messaging/qt/tp/text_channel.h 2016-09-17 21:47:53 +0000
415@@ -23,6 +23,7 @@
416
417 #include <messaging/qt/tp/interfaces/base_channel_destroyable.h>
418 #include <messaging/qt/tp/interfaces/base_channel_roles.h>
419+#include <messaging/qt/tp/interfaces/base_channel_subject.h>
420 #include <messaging/qt/tp/interfaces/types.h>
421 #include <messaging/qt/tp/interfaces/constants.h>
422
423@@ -81,8 +82,11 @@
424 void on_group_cancelled(CancelGroupReason reason, const std::string &message) override;
425
426 /// @brief on_group_title_changed when group title has changed in the server
427- void on_group_title_changed(const std::string& new_title,
428- const Member& actor,
429+ void on_group_title_changed(const std::string& new_title) override;
430+
431+ /// @brief on_group_subject_changed when group title has changed in the server
432+ void on_group_subject_changed(const std::string& new_subject,
433+ const std::shared_ptr<Member>& actor,
434 const std::chrono::system_clock::time_point& when) override;
435
436 /// @brief on_members_updated when group members have changed (added/removed) in server
437@@ -148,9 +152,12 @@
438 void on_group_cancelled(CancelGroupReason reason, const std::string &message) override;
439
440 /// @brief on_group_title_changed when group title has changed in the server
441- void on_group_title_changed(const std::string& new_title,
442- const Member& actor,
443- const std::chrono::system_clock::time_point& when) override;
444+ void on_group_title_changed(const std::string& new_title) override;
445+
446+ /// @brief on_group_subject_changed when group title has changed in the server
447+ void on_group_subject_changed(const std::string& new_subject,
448+ const std::shared_ptr<Member>& actor,
449+ const std::chrono::system_clock::time_point& when) override;
450
451 /// @brief on_members_updated when group members have changed (added/removed) in server
452 void on_members_updated(const Members& members) override;
453@@ -192,6 +199,8 @@
454 void update_group_configuration(const QVariantMap &properties, Tp::DBusError *error);
455 // Handler action to update roles for current channel group members
456 void update_roles(const interfaces::HandleRolesMap &contact_roles, Tp::DBusError *error);
457+ // Handle action to update current channel subject
458+ void set_subject(const QString &subject, Tp::DBusError *error);
459
460 // channel destruction request. only supported in group chats
461 void destroy(Tp::DBusError* error);
462@@ -211,6 +220,7 @@
463 Tp::BaseChannelChatStateInterfacePtr chat_state_interface;
464 interfaces::BaseChannelDestroyableInterfacePtr destroyable_interface;
465 interfaces::BaseChannelRolesInterfacePtr roles_interface;
466+ interfaces::BaseChannelSubjectInterfacePtr subject_interface;
467
468 // NOTE(rmescandon): this is a temporal member in the class not needed from Telepathy Qt >= 0.9.7.0 which
469 // includes Tp::BaseChannel::connection() method to obtain it whenever is needed.
470
471=== modified file 'include/messaging/recipient.h'
472--- include/messaging/recipient.h 2016-03-30 19:19:19 +0000
473+++ include/messaging/recipient.h 2016-09-17 21:47:53 +0000
474@@ -26,7 +26,8 @@
475 enum RecipientType
476 {
477 user, ///< the peer is a user
478- group ///< the peer is a group
479+ group, ///< the peer is a group
480+ broadcast ///< the peer is a broadcast group
481 };
482
483 class MESSAGING_FW_PUBLIC Recipient
484
485=== modified file 'src/CMakeLists.txt'
486--- src/CMakeLists.txt 2016-08-26 14:11:06 +0000
487+++ src/CMakeLists.txt 2016-09-17 21:47:53 +0000
488@@ -9,6 +9,8 @@
489 ${CMAKE_SOURCE_DIR}/include/messaging/qt/tp/interfaces/base_channel_destroyable_internal.h
490 ${CMAKE_SOURCE_DIR}/include/messaging/qt/tp/interfaces/base_channel_roles.h
491 ${CMAKE_SOURCE_DIR}/include/messaging/qt/tp/interfaces/base_channel_roles_internal.h
492+ ${CMAKE_SOURCE_DIR}/include/messaging/qt/tp/interfaces/base_channel_subject.h
493+ ${CMAKE_SOURCE_DIR}/include/messaging/qt/tp/interfaces/base_channel_subject_internal.h
494 ${CMAKE_SOURCE_DIR}/include/messaging/qt/tp/interfaces/channel_interface_roles_adaptor.h)
495
496 set(
497@@ -16,6 +18,7 @@
498
499 messaging/associative_connector_factory.cpp
500 messaging/boost/variant.cpp
501+ messaging/broadcast.cpp
502 messaging/chat.cpp
503 messaging/group.cpp
504 messaging/group_manager.cpp
505@@ -48,6 +51,7 @@
506
507 messaging/qt/tp/interfaces/base_channel_destroyable.cpp
508 messaging/qt/tp/interfaces/base_channel_roles.cpp
509+ messaging/qt/tp/interfaces/base_channel_subject.cpp
510 messaging/qt/tp/interfaces/channel_interface_roles_adaptor.cpp
511
512 messaging/runner.cpp
513
514=== added file 'src/messaging/broadcast.cpp'
515--- src/messaging/broadcast.cpp 1970-01-01 00:00:00 +0000
516+++ src/messaging/broadcast.cpp 2016-09-17 21:47:53 +0000
517@@ -0,0 +1,37 @@
518+/*
519+ * Copyright © 2016 Canonical Ltd.
520+ *
521+ * This program is free software: you can redistribute it and/or modify it
522+ * under the terms of the GNU Lesser General Public License version 3,
523+ * as published by the Free Software Foundation.
524+ *
525+ * This program is distributed in the hope that it will be useful,
526+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
527+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
528+ * GNU Lesser General Public License for more details.
529+ *
530+ * You should have received a copy of the GNU Lesser General Public License
531+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
532+ */
533+
534+#include <messaging/broadcast.h>
535+
536+struct messaging::Broadcast::Private
537+{
538+ messaging::Members members;
539+};
540+
541+messaging::Broadcast::Broadcast(const messaging::Members &members)
542+ : Recipient{std::string{}}, impl{new Private{members}}
543+{
544+}
545+
546+messaging::RecipientType messaging::Broadcast::type() const
547+{
548+ return messaging::RecipientType::broadcast;
549+}
550+
551+messaging::Members messaging::Broadcast::members() const
552+{
553+ return impl->members;
554+}
555
556=== modified file 'src/messaging/group.cpp'
557--- src/messaging/group.cpp 2016-08-17 13:25:23 +0000
558+++ src/messaging/group.cpp 2016-09-17 21:47:53 +0000
559@@ -16,15 +16,24 @@
560
561 #include <messaging/group.h>
562
563+#include <messaging/qt/variant.h>
564+
565+const std::string messaging::Group::ROOM_NAME = "roomName";
566+const std::string messaging::Group::DESCRIPTION = "description";
567+const std::string messaging::Group::SERVER = "server";
568+const std::string messaging::Group::CREATION_TIMESTAMP = "creationTimestamp";
569+const std::string messaging::Group::SUBJECT = "subject";
570+
571 struct messaging::Group::Private
572 {
573 messaging::Members initial_invitees;
574 std::string initial_title;
575 std::shared_ptr<messaging::Member> creator;
576+ messaging::VariantMap additional_properties;
577 };
578
579-messaging::Group::Group(std::string id, const messaging::Members &initial_invitees, std::string initial_title, const std::shared_ptr<Member> &creator)
580- : Recipient{id}, impl{new Private{initial_invitees, initial_title, creator}}
581+messaging::Group::Group(std::string id, const messaging::Members &initial_invitees, std::string initial_title, const std::shared_ptr<Member> &creator, const VariantMap &additional_properties)
582+ : Recipient{id}, impl{new Private{initial_invitees, initial_title, creator, additional_properties}}
583 {
584 }
585
586@@ -45,5 +54,30 @@
587
588 std::shared_ptr<messaging::Member> messaging::Group::creator() const
589 {
590- return impl->creator;
591+ return impl->creator;
592+}
593+
594+messaging::VariantMap &messaging::Group::additional_properties()
595+{
596+ return impl->additional_properties;
597+}
598+
599+std::shared_ptr<messaging::Variant> messaging::Group::additional_property(const std::string &key) const
600+{
601+ auto it = impl->additional_properties.find(key);
602+ if (it != impl->additional_properties.end()) {
603+ return it->second;
604+ }
605+ return std::make_shared<messaging::qt::Variant>(QVariant{});
606+}
607+
608+void messaging::Group::set_additional_property(const std::string &key, const std::shared_ptr<messaging::Variant> &value)
609+{
610+ impl->additional_properties[key] = value;
611+}
612+
613+bool messaging::Group::exists_additional_property(const std::string &key) const
614+{
615+ auto it = impl->additional_properties.find(key);
616+ return it != impl->additional_properties.end();
617 }
618
619=== modified file 'src/messaging/group_manager.cpp'
620--- src/messaging/group_manager.cpp 2016-08-25 11:04:57 +0000
621+++ src/messaging/group_manager.cpp 2016-09-17 21:47:53 +0000
622@@ -64,12 +64,18 @@
623 impl->observer->on_group_cancelled(reason, message);
624 }
625
626-void messaging::GroupManager::announce_group_title_changed(const std::string &new_title,
627- const Member &actor,
628- const std::chrono::system_clock::time_point &when)
629-{
630- validate_observer();
631- impl->observer->on_group_title_changed(new_title, actor, when);
632+void messaging::GroupManager::announce_group_title_changed(const std::string &new_title)
633+{
634+ validate_observer();
635+ impl->observer->on_group_title_changed(new_title);
636+}
637+
638+void messaging::GroupManager::announce_group_subject_changed(const std::string &new_subject,
639+ const std::shared_ptr<Member> &actor,
640+ const std::chrono::system_clock::time_point &when)
641+{
642+ validate_observer();
643+ impl->observer->on_group_subject_changed(new_subject, actor, when);
644 }
645
646 void messaging::GroupManager::announce_members_updated(const Members& members)
647
648=== modified file 'src/messaging/has_interfaces.cpp'
649--- src/messaging/has_interfaces.cpp 2016-03-30 19:19:19 +0000
650+++ src/messaging/has_interfaces.cpp 2016-09-17 21:47:53 +0000
651@@ -36,5 +36,12 @@
652 void messaging::HasInterfaces::plug_interface(const std::shared_ptr<Interface>& interface)
653 {
654 impl->interfaces.insert(interface);
655-}
656-
657+
658+ interface->on_plugged(shared_from_this());
659+ on_interface_plugged(interface);
660+}
661+
662+void messaging::HasInterfaces::on_interface_plugged(const std::shared_ptr<Interface> &/*interface*/)
663+{
664+ // left empty on purpose
665+}
666
667=== modified file 'src/messaging/qt/tp/connection.cpp'
668--- src/messaging/qt/tp/connection.cpp 2016-08-24 21:51:07 +0000
669+++ src/messaging/qt/tp/connection.cpp 2016-09-17 21:47:53 +0000
670@@ -22,6 +22,7 @@
671 #include <messaging/qt/tp/interfaces/base_channel_destroyable.h>
672 #include <messaging/qt/tp/interfaces/base_channel_roles.h>
673
674+#include <messaging/broadcast.h>
675 #include <messaging/message.h>
676 #include <messaging/presence_status_not_supported.h>
677 #include <messaging/user.h>
678@@ -593,7 +594,6 @@
679 {
680 std::shared_ptr<GroupStarter> group_starter = connection->group_starter();
681 group_manager = group_starter->accept_group(group);
682-
683 if (group_manager->group_id().empty())
684 {
685 LOG(ERROR) << "Group creation rejected";
686@@ -601,14 +601,20 @@
687 return Tp::BaseChannelPtr{};
688 }
689
690- // update recipient with id, title and members
691+ // update recipient with id, title, creator, members and additional properties
692+ // FIXME(rmescandon): a refactor is needed to move all this to a group_manager->group() object
693+ // and create a copy constructor for Group which can be populated with cached data when needed
694+ auto additional_properties = group->additional_properties();
695+ if (not group_manager->group_subject().empty()) {
696+ additional_properties[Group::SUBJECT] = std::make_shared<messaging::BoostVariant>(group_manager->group_subject());
697+ }
698 auto members = group_manager->members();
699 recipient = std::make_shared<messaging::Group>(
700 group_manager->group_id(),
701 members,
702 group_manager->group_title(),
703- group_manager->group_creator());
704-
705+ group_manager->group_creator(),
706+ additional_properties);
707 }
708 catch (const std::exception &e)
709 {
710@@ -650,13 +656,20 @@
711 return Tp::BaseChannelPtr{};
712 }
713
714- // update recipient with id, title and members
715+ // update recipient with id, title, creator, members and additional properties
716+ // FIXME(rmescandon): a refactor is needed to move all this to a group_manager->group() object
717+ // and create a copy constructor for Group which can be populated with cached data when needed
718+ auto additional_properties = group->additional_properties();
719+ if (not group_manager->group_subject().empty()) {
720+ additional_properties[Group::SUBJECT] = std::make_shared<messaging::BoostVariant>(group_manager->group_subject());
721+ }
722 auto members = group_manager->members();
723 recipient = std::make_shared<messaging::Group>(
724 group_manager->group_id(),
725 members,
726 group_manager->group_title(),
727- group_manager->group_creator());
728+ group_manager->group_creator(),
729+ additional_properties);
730 }
731 catch (const std::exception &e)
732 {
733@@ -673,11 +686,15 @@
734 break;
735 }
736 case Tp::HandleTypeNone: {
737- // This is the case of creating a group from the app. There is not type for the handle of the channel to be created when
738+ bool is_room = hints.contains(TP_QT_IFACE_CHANNEL_INTERFACE_ROOM + QLatin1String(".RoomName"));
739+
740+ // There are two possible cases in which handle type is going to be none: chat rooms and broadcast channels.
741+ // For broadcast channels the handle type will remain as none during the entire channel lifetime. For chat rooms
742+ // once the creation is finished, the type will change to room.
743+ // For the chat room case, this code will be called when creating a group from the app.
744+ // There is not type for the handle of the channel to be created when
745 // received the request. We have to switch to Room type and get the provided information
746-
747 messaging::Members initial_invitees;
748- std::string title;
749 if (hints.contains(TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialInviteeIDs")))
750 {
751 QStringList initial_invitees_ids =
752@@ -698,73 +715,91 @@
753 //FIXME: get contact attribute display name for the user second param
754 //FIXME: consider here if needed to provide initial roles to members
755 initial_invitees.push_back(std::make_shared<Member>(normalized_id,
756- PendingStatus::Remote,
757+ is_room ? PendingStatus::Remote : PendingStatus::None,
758 Flags<Role>(Role::Member),
759 std::string{}/* display_name*/ ));
760 }
761 }
762
763- if (hints.contains(TP_QT_IFACE_CHANNEL_INTERFACE_ROOM_CONFIG + QLatin1String(".Title")))
764- {
765- title = hints[TP_QT_IFACE_CHANNEL_INTERFACE_ROOM_CONFIG + QLatin1String(".Title")].toString().toStdString();
766- }
767-
768 // check if the client requested a chat room
769- if (hints.contains(TP_QT_IFACE_CHANNEL_INTERFACE_ROOM + QLatin1String(".RoomName")))
770+ // if so, create the group related stuff
771+ if (is_room)
772 {
773 target_handle_type = Tp::HandleTypeRoom;
774- }
775-
776- std::string initiator_handle;
777- if (hints.contains(TP_QT_IFACE_CHANNEL + QLatin1String(".InitiatorHandle")))
778- {
779- initiator_handle = hints[TP_QT_IFACE_CHANNEL + QLatin1String(".InitiatorHandle")].toString().toStdString();
780- }
781-
782- //FIXME: fill group title parameter when got somehow
783- // create initial group recipient with no identifier for plugin to create the group
784- recipient = std::make_shared<messaging::Group>(
785- std::string{} /* no id exists yet */,
786- initial_invitees,
787- title,
788- std::make_shared<messaging::Member>(initiator_handle));
789-
790- try
791- {
792- std::shared_ptr<GroupStarter> group_starter = connection->group_starter();
793- messaging::Group::shared_ptr group = std::dynamic_pointer_cast<messaging::Group>(recipient);
794- group_manager = group_starter->create_group(group);
795-
796- if (group_manager->group_id().empty())
797+
798+ std::string title;
799+ auto additional_properties = VariantMap{};
800+
801+ if (hints.contains(TP_QT_IFACE_CHANNEL_INTERFACE_ROOM_CONFIG + QLatin1String(".Title")))
802+ {
803+ title = hints[TP_QT_IFACE_CHANNEL_INTERFACE_ROOM_CONFIG + QLatin1String(".Title")].toString().toStdString();
804+ }
805+
806+ std::string initiator_handle;
807+ if (hints.contains(TP_QT_IFACE_CHANNEL + QLatin1String(".InitiatorHandle")))
808+ {
809+ initiator_handle = hints[TP_QT_IFACE_CHANNEL + QLatin1String(".InitiatorHandle")].toString().toStdString();
810+ }
811+
812+ if (hints.contains(TP_QT_IFACE_CHANNEL_INTERFACE_SUBJECT + QLatin1String(".Subject")))
813+ {
814+ additional_properties[Group::SUBJECT] =
815+ std::make_shared<messaging::BoostVariant>(
816+ hints[TP_QT_IFACE_CHANNEL_INTERFACE_SUBJECT + QLatin1String(".Subject")].toString().toStdString());
817+ }
818+
819+ // create initial group recipient with no identifier for plugin to create the group
820+ recipient = std::make_shared<messaging::Group>(
821+ std::string{} /* no id exists yet */,
822+ initial_invitees,
823+ title,
824+ std::make_shared<messaging::Member>(initiator_handle),
825+ additional_properties);
826+ try
827+ {
828+ std::shared_ptr<GroupStarter> group_starter = connection->group_starter();
829+ messaging::Group::shared_ptr group = std::dynamic_pointer_cast<messaging::Group>(recipient);
830+ group_manager = group_starter->create_group(group);
831+
832+ if (group_manager->group_id().empty())
833+ {
834+ LOG(ERROR) << "Group creation rejected";
835+ error->set(TP_QT_ERROR_CANCELLED, "Group creation rejected");
836+ return Tp::BaseChannelPtr{};
837+ }
838+
839+ // update recipient with id, title, members and additional properties
840+ auto additional_properties = group->additional_properties();
841+ if (not group_manager->group_subject().empty()) {
842+ additional_properties[Group::SUBJECT] = std::make_shared<messaging::BoostVariant>(group_manager->group_subject());
843+ }
844+ recipient = std::make_shared<messaging::Group>(
845+ group_manager->group_id(),
846+ group_manager->members(),
847+ group_manager->group_title(),
848+ group_manager->group_creator(),
849+ additional_properties);
850+ }
851+ catch (const std::exception &e)
852+ {
853+ LOG(ERROR) << "Group creation rejected, " << e.what();
854+ error->set(TP_QT_ERROR_CANCELLED, "Group creation rejected");
855+ return Tp::BaseChannelPtr{};
856+ }
857+ catch (...)
858 {
859 LOG(ERROR) << "Group creation rejected";
860 error->set(TP_QT_ERROR_CANCELLED, "Group creation rejected");
861 return Tp::BaseChannelPtr{};
862 }
863
864- // update recipient with id, title and members
865- recipient = std::make_shared<messaging::Group>(
866- group_manager->group_id(),
867- group_manager->members(),
868- group_manager->group_title(),
869- group_manager->group_creator());
870- }
871- catch (const std::exception &e)
872- {
873- LOG(ERROR) << "Group creation rejected, " << e.what();
874- error->set(TP_QT_ERROR_CANCELLED, "Group creation rejected");
875- return Tp::BaseChannelPtr{};
876- }
877- catch (...)
878- {
879- LOG(ERROR) << "Group creation rejected";
880- error->set(TP_QT_ERROR_CANCELLED, "Group creation rejected");
881- return Tp::BaseChannelPtr{};
882- }
883-
884- // request handle from group_manager id, filled with the group id after calling start_group()
885- Tp::DBusError error;
886- target_handle = request_handles(Tp::HandleTypeRoom, QStringList() << QString::fromStdString(group_manager->group_id()), &error)[0];
887+ // request handle from group_manager id, filled with the group id after calling start_group()
888+ Tp::DBusError error;
889+ target_handle = request_handles(Tp::HandleTypeRoom, QStringList() << QString::fromStdString(group_manager->group_id()), &error)[0];
890+ } else {
891+ // if not, consider this a broadcast channel
892+ recipient = std::make_shared<messaging::Broadcast>(initial_invitees);
893+ }
894 break;
895 }
896 default:
897
898=== modified file 'src/messaging/qt/tp/interfaces/base_channel_roles.cpp'
899--- src/messaging/qt/tp/interfaces/base_channel_roles.cpp 2016-08-12 13:19:22 +0000
900+++ src/messaging/qt/tp/interfaces/base_channel_roles.cpp 2016-09-17 21:47:53 +0000
901@@ -148,7 +148,7 @@
902 }
903
904 if (!canUpdateRoles()) {
905- error->set(TP_QT_ERROR_PERMISSION_DENIED, QLatin1String("Operation not allowed; anUpdateRoles flag set to false"));
906+ error->set(TP_QT_ERROR_PERMISSION_DENIED, QLatin1String("Operation not allowed; canUpdateRoles flag set to false"));
907 }
908
909 return mPriv->updateRolesCB(contactRoles, error);
910
911=== added file 'src/messaging/qt/tp/interfaces/base_channel_subject.cpp'
912--- src/messaging/qt/tp/interfaces/base_channel_subject.cpp 1970-01-01 00:00:00 +0000
913+++ src/messaging/qt/tp/interfaces/base_channel_subject.cpp 2016-09-17 21:47:53 +0000
914@@ -0,0 +1,205 @@
915+/*
916+ * Copyright © 2016 Canonical Ltd.
917+ *
918+ * This program is free software: you can redistribute it and/or modify it
919+ * under the terms of the GNU Lesser General Public License version 3,
920+ * as published by the Free Software Foundation.
921+ *
922+ * This program is distributed in the hope that it will be useful,
923+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
924+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
925+ * GNU Lesser General Public License for more details.
926+ *
927+ * You should have received a copy of the GNU Lesser General Public License
928+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
929+ */
930+
931+#include <TelepathyQt/DBusObject>
932+#include <messaging/qt/tp/interfaces/base_channel_subject.h>
933+#include <messaging/qt/tp/interfaces/base_channel_subject_internal.h>
934+
935+namespace mqti = messaging::qt::tp::interfaces;
936+
937+// Chan.I.Subject
938+mqti::BaseChannelSubjectInterface::Adaptee::Adaptee(BaseChannelSubjectInterface *interface)
939+ : QObject(interface),
940+ mInterface(interface)
941+{
942+}
943+
944+mqti::BaseChannelSubjectInterface::Adaptee::~Adaptee()
945+{
946+}
947+
948+struct TP_QT_NO_EXPORT mqti::BaseChannelSubjectInterface::Private {
949+ Private(BaseChannelSubjectInterface *parent)
950+ :adaptee(new BaseChannelSubjectInterface::Adaptee(parent)) {
951+ }
952+
953+ QString subject;
954+ QString actor;
955+ uint actorHandle;
956+ qlonglong timestamp;
957+ bool canSet;
958+ SetSubjectCallback setSubjectCB;
959+ BaseChannelSubjectInterface::Adaptee *adaptee;
960+};
961+
962+QString mqti::BaseChannelSubjectInterface::Adaptee::subject() const
963+{
964+ return mInterface->subject();
965+}
966+
967+QString mqti::BaseChannelSubjectInterface::Adaptee::actor() const
968+{
969+ return mInterface->actor();
970+}
971+
972+uint mqti::BaseChannelSubjectInterface::Adaptee::actorHandle() const
973+{
974+ return mInterface->actorHandle();
975+}
976+
977+qlonglong mqti::BaseChannelSubjectInterface::Adaptee::timestamp() const
978+{
979+ return mInterface->timestamp();
980+}
981+
982+bool mqti::BaseChannelSubjectInterface::Adaptee::canSet() const
983+{
984+ return mInterface->canSet();
985+}
986+
987+void mqti::BaseChannelSubjectInterface::Adaptee::setSubject(const QString &subject, const Tp::Service::ChannelInterfaceSubjectAdaptor::SetSubjectContextPtr &context)
988+{
989+ if (!mInterface->mPriv->setSubjectCB.isValid()) {
990+ context->setFinishedWithError(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented"));
991+ return;
992+ }
993+
994+ Tp::DBusError error;
995+ mInterface->mPriv->setSubjectCB(subject, &error);
996+ if (error.isValid()) {
997+ context->setFinishedWithError(error.name(), error.message());
998+ return;
999+ }
1000+ context->setFinished();
1001+}
1002+
1003+/**
1004+ * \class BaseChannelSubjectInterface
1005+ *
1006+ * \brief Base class for implementations of Channel.Interface.Subject
1007+ *
1008+ */
1009+
1010+/**
1011+ * Class constructor.
1012+ */
1013+mqti::BaseChannelSubjectInterface::BaseChannelSubjectInterface()
1014+ : Tp::AbstractChannelInterface(TP_QT_IFACE_CHANNEL_INTERFACE_SUBJECT),
1015+ mPriv(new Private(this))
1016+{
1017+}
1018+
1019+void mqti::BaseChannelSubjectInterface::setSetSubjectCallback(const SetSubjectCallback &cb)
1020+{
1021+ mPriv->setSubjectCB = cb;
1022+}
1023+
1024+/**
1025+ * Class destructor.
1026+ */
1027+mqti::BaseChannelSubjectInterface::~BaseChannelSubjectInterface()
1028+{
1029+ delete mPriv;
1030+}
1031+
1032+/**
1033+ * Return the immutable properties of this interface.
1034+ *
1035+ * Immutable properties cannot change after the interface has been registered
1036+ * on a service on the bus with registerInterface().
1037+ *
1038+ * \return The immutable properties of this interface.
1039+ */
1040+QVariantMap mqti::BaseChannelSubjectInterface::immutableProperties() const
1041+{
1042+ QVariantMap map;
1043+ return map;
1044+}
1045+
1046+void mqti::BaseChannelSubjectInterface::createAdaptor()
1047+{
1048+ (void) new Tp::Service::ChannelInterfaceSubjectAdaptor(dbusObject()->dbusConnection(),
1049+ mPriv->adaptee, dbusObject());
1050+}
1051+
1052+void mqti::BaseChannelSubjectInterface::setSubject(const QString &subject, Tp::DBusError *error)
1053+{
1054+ if (!mPriv->setSubjectCB.isValid()) {
1055+ error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented"));
1056+ return;
1057+ }
1058+
1059+ if (!canSet()) {
1060+ error->set(TP_QT_ERROR_PERMISSION_DENIED, QLatin1String("Operation not allowed; canSet flag set to false"));
1061+ }
1062+
1063+ return mPriv->setSubjectCB(subject, error);
1064+}
1065+
1066+QString mqti::BaseChannelSubjectInterface::subject() const
1067+{
1068+ return mPriv->subject;
1069+}
1070+
1071+void mqti::BaseChannelSubjectInterface::setSubject(const QString &subject)
1072+{
1073+ mPriv->subject = subject;
1074+ notifyPropertyChanged(QLatin1String("Subject"), QVariant::fromValue(subject));
1075+}
1076+
1077+QString mqti::BaseChannelSubjectInterface::actor() const
1078+{
1079+ return mPriv->actor;
1080+}
1081+
1082+void mqti::BaseChannelSubjectInterface::setActor(const QString &actor)
1083+{
1084+ mPriv->actor = actor;
1085+ notifyPropertyChanged(QLatin1String("Actor"), QVariant::fromValue(actor));
1086+}
1087+
1088+uint mqti::BaseChannelSubjectInterface::actorHandle() const
1089+{
1090+ return mPriv->actorHandle;
1091+}
1092+
1093+void mqti::BaseChannelSubjectInterface::setActorHandle(uint handle)
1094+{
1095+ mPriv->actorHandle = handle;
1096+ notifyPropertyChanged(QLatin1String("ActorHandle"), QVariant::fromValue(handle));
1097+}
1098+
1099+qlonglong mqti::BaseChannelSubjectInterface::timestamp() const
1100+{
1101+ return mPriv->timestamp;
1102+}
1103+
1104+void mqti::BaseChannelSubjectInterface::setTimestamp(qlonglong timestamp)
1105+{
1106+ mPriv->timestamp = timestamp;
1107+ notifyPropertyChanged(QLatin1String("Timestamp"), QVariant::fromValue(timestamp));
1108+}
1109+
1110+bool mqti::BaseChannelSubjectInterface::canSet() const
1111+{
1112+ return mPriv->canSet;
1113+}
1114+
1115+void mqti::BaseChannelSubjectInterface::setCanSet(bool canSet)
1116+{
1117+ mPriv->canSet = canSet;
1118+ notifyPropertyChanged(QLatin1String("CanSet"), QVariant::fromValue(canSet));
1119+}
1120
1121=== modified file 'src/messaging/qt/tp/text_channel.cpp'
1122--- src/messaging/qt/tp/text_channel.cpp 2016-08-30 18:46:08 +0000
1123+++ src/messaging/qt/tp/text_channel.cpp 2016-09-17 21:47:53 +0000
1124@@ -21,6 +21,7 @@
1125
1126 #include <messaging/qt/variant.h>
1127
1128+#include <messaging/broadcast.h>
1129 #include <messaging/connection.h>
1130 #include <messaging/group.h>
1131 #include <messaging/messenger.h>
1132@@ -181,13 +182,21 @@
1133 });
1134 }
1135
1136-void mqt::tp::TextChannel::Observer::on_group_title_changed(const std::string &new_title,
1137- const Member& actor,
1138- const std::chrono::system_clock::time_point& when)
1139-{
1140- auto thiz = shared_from_this();
1141- runtime->enter_with_task([thiz, new_title, actor, when]() {
1142- thiz->tc->on_group_title_changed(new_title, actor, when);
1143+void mqt::tp::TextChannel::Observer::on_group_title_changed(const std::string &new_title)
1144+{
1145+ auto thiz = shared_from_this();
1146+ runtime->enter_with_task([thiz, new_title]() {
1147+ thiz->tc->on_group_title_changed(new_title);
1148+ });
1149+}
1150+
1151+void mqt::tp::TextChannel::Observer::on_group_subject_changed(const std::string &new_subject,
1152+ const std::shared_ptr<Member>& actor,
1153+ const std::chrono::system_clock::time_point& when)
1154+{
1155+ auto thiz = shared_from_this();
1156+ runtime->enter_with_task([thiz, new_subject, actor, when]() {
1157+ thiz->tc->on_group_subject_changed(new_subject, actor, when);
1158 });
1159 }
1160
1161@@ -322,6 +331,27 @@
1162 return;
1163 }
1164
1165+ // NOTE (rmescandon): Build and populate values for Subject interface before than roomConfig one. This is needed for having
1166+ // available subject Actor before setting the title in room config. That way, same value could be taken as actor for subject
1167+ // and title in upper layers
1168+ subject_interface = interfaces::BaseChannelSubjectInterface::create();
1169+ subject_interface->setActor(QString::fromStdString(group->creator()->id()));
1170+ subject_interface->setActorHandle(creator_handle);
1171+ subject_interface->setTimestamp(static_cast<qlonglong>(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now())));
1172+
1173+ try
1174+ {
1175+ subject_interface->setCanSet(group_manager->permissions().is_set(GroupPermissions::CanChangeSubject));
1176+ // the last thing to set is the subject itself. This way, all the properties should be available in client
1177+ // for composing all the information like "%Actor% set subject to %Subject%"
1178+ subject_interface->setSubject(QString::fromStdString(group_manager->group_subject()));
1179+ }
1180+ catch (...)
1181+ {
1182+ LOG(ERROR) << "An exception has been thrown when setting group title as channel subject";
1183+ return;
1184+ }
1185+
1186 // uncomment the following code when room name is part of messaging::Group
1187 //QString roomName = QString::fromStdString(group->id());
1188 room_interface = Tp::BaseChannelRoomInterface::create(/* roomName */ QString(),
1189@@ -343,8 +373,8 @@
1190
1191 room_config_interface->setConfigurationRetrieved(true);
1192
1193- // FIXME (rmescandon): as telepathy does not offer a way to differentiate whether it can be changed one configuration element
1194- // or other, let's use the flag to enable/dissable all configuration properties permissions by now
1195+ // As telepathy does not offer a way to differentiate whether it can be changed one configuration element
1196+ // or other, let's use the flag to enable/dissable all configuration properties permissions
1197 room_config_interface->setCanUpdateConfiguration(group_manager->permissions().is_set(GroupPermissions::CanChangeTitle));
1198
1199 // FIXME: check what flags we want by default
1200@@ -366,6 +396,24 @@
1201 // we need to set the initial group members
1202 on_members_updated(group->initial_invitees());
1203 }
1204+ else if (recipient->type() == RecipientType::broadcast)
1205+ {
1206+ messaging::Broadcast::shared_ptr broadcast = std::dynamic_pointer_cast<messaging::Broadcast>(recipient);
1207+ // for broadcast channels we just need to plug the group interface with limited capabilities
1208+ Tp::ChannelGroupFlags groupFlags = Tp::ChannelGroupFlagHandleOwnersNotAvailable |
1209+ Tp::ChannelGroupFlagMembersChangedDetailed |
1210+ Tp::ChannelGroupFlagProperties;
1211+ group_interface = Tp::BaseChannelGroupInterface::create();
1212+ group_interface->setGroupFlags(groupFlags);
1213+
1214+ // we need to plug this interface here to avoid a crash
1215+ plug_interface_if_available(group_interface);
1216+
1217+ destroyable_interface = mqt::tp::interfaces::BaseChannelDestroyableInterface::create();
1218+
1219+ // we need to set the initial group members
1220+ on_members_updated(broadcast->members());
1221+ }
1222
1223 chat_state_interface = Tp::BaseChannelChatStateInterface::create();
1224
1225@@ -588,7 +636,6 @@
1226 LOG(ERROR) << "An exception has been thrown when setting group self handle";
1227 return;
1228 }
1229-
1230 }
1231
1232 void mqt::tp::TextChannel::close_channel_with_reason(uint reason, const QString &message)
1233@@ -662,22 +709,42 @@
1234 close_channel_with_reason(reason, message);
1235 }
1236
1237-void mqt::tp::TextChannel::on_group_title_changed(const std::string &new_title,
1238- const Member& actor,
1239- const std::chrono::system_clock::time_point& when)
1240+void mqt::tp::TextChannel::on_group_title_changed(const std::string &new_title)
1241 {
1242- //TODO(rmescandon): must be implemented interface Subject2 in order to use parameters actor and when
1243- // (see https://telepathy.freedesktop.org/spec/Channel_Interface_Subject.html)
1244- // meanwhile they are unused
1245- Q_UNUSED(actor);
1246- Q_UNUSED(when);
1247-
1248+ // for a flexible management in client, set as title both room_config title and subject
1249 if (room_config_interface)
1250 {
1251 room_config_interface->setTitle(QString::fromStdString(new_title));
1252 }
1253 }
1254
1255+void mqt::tp::TextChannel::on_group_subject_changed(const std::string &new_subject,
1256+ const std::shared_ptr<Member>& actor,
1257+ const std::chrono::system_clock::time_point& when)
1258+{
1259+ if (subject_interface)
1260+ {
1261+ if (not actor->id().empty())
1262+ {
1263+ Tp::DBusError error;
1264+ uint handle;
1265+ if (actor->id() == "me") {
1266+ handle = tp_connection->selfHandle();
1267+ } else {
1268+ handle = tp_connection->requestHandles(Tp::HandleTypeContact, QStringList() << QString::fromStdString(actor->id()), &error)[0];
1269+ }
1270+ // set always the actor before the subject, for having it available in client when subject is available
1271+ subject_interface->setActor(QString::fromStdString(actor->id()));
1272+ subject_interface->setActorHandle(handle);
1273+ }
1274+
1275+ subject_interface->setTimestamp(static_cast<qlonglong>(std::chrono::system_clock::to_time_t(when)));
1276+ // the last thing to set is the subject itself. This way, all the properties should be available in client
1277+ // for composing all the information like "%Actor% set subject to %Subject%"
1278+ subject_interface->setSubject(QString::fromStdString(new_subject));
1279+ }
1280+}
1281+
1282 void mqt::tp::TextChannel::on_members_updated(const Members& received_members)
1283 {
1284 LOG(INFO) << __PRETTY_FUNCTION__;
1285@@ -778,6 +845,11 @@
1286 room_config_interface->setCanUpdateConfiguration(permissions.is_set(GroupPermissions::CanChangeTitle));
1287 }
1288
1289+ if (not subject_interface.isNull())
1290+ {
1291+ subject_interface->setCanSet(permissions.is_set(GroupPermissions::CanChangeTitle));
1292+ }
1293+
1294 // Can kick other participants?
1295 if (not group_interface.isNull())
1296 {
1297@@ -966,6 +1038,11 @@
1298 return;
1299 }
1300
1301+ set_subject(properties["Title"].toString(), error);
1302+}
1303+
1304+void mqt::tp::TextChannel::set_subject(const QString &subject, Tp::DBusError *error)
1305+{
1306 try
1307 {
1308 std::shared_ptr<messaging::GroupManager> group_manager = chat->interface<GroupManager>();
1309@@ -979,11 +1056,11 @@
1310 return;
1311 }
1312
1313- group_manager->change_group_title(properties["Title"].toString().toStdString());
1314+ group_manager->change_group_title(subject.toStdString());
1315 }
1316 catch (...)
1317 {
1318- LOG(ERROR) << "An exception has been thrown when updating group configuration";
1319+ LOG(ERROR) << "An exception has been thrown when setting subject";
1320 }
1321 }
1322
1323@@ -1081,6 +1158,11 @@
1324 {
1325 roles_interface->setUpdateRolesCallback(Tp::memFun(this, &TextChannel::update_roles));
1326 }
1327+
1328+ if (!subject_interface.isNull())
1329+ {
1330+ subject_interface->setSetSubjectCallback(Tp::memFun(this, &TextChannel::set_subject));
1331+ }
1332 }
1333
1334 void mqt::tp::TextChannel::plug_interfaces_once()
1335@@ -1092,6 +1174,7 @@
1336 plug_interface_if_available(chat_state_interface);
1337 plug_interface_if_available(destroyable_interface);
1338 plug_interface_if_available(roles_interface);
1339+ plug_interface_if_available(subject_interface);
1340 }
1341
1342 void mqt::tp::TextChannel::plug_interface_if_available(const Tp::AbstractChannelInterfacePtr &interface)
1343
1344=== modified file 'tests/mock_group_manager.h'
1345--- tests/mock_group_manager.h 2016-08-17 15:04:16 +0000
1346+++ tests/mock_group_manager.h 2016-09-17 21:47:53 +0000
1347@@ -34,19 +34,23 @@
1348 MOCK_METHOD1(on_group_created, void(const std::string& id));
1349 MOCK_METHOD0(on_group_cancelled, void());
1350 MOCK_METHOD1(on_group_title_changed, void(const std::string&));
1351+ MOCK_METHOD3(on_group_subject_changed, void(const std::string&, const std::shared_ptr<messaging::Member>&, const std::chrono::system_clock::time_point&));
1352 };
1353
1354 MOCK_METHOD0(leave_group, void());
1355 MOCK_METHOD0(dissolve_group, void());
1356 MOCK_METHOD0(join_group, void());
1357 MOCK_METHOD1(change_group_title, void(const std::string&));
1358+ MOCK_METHOD1(change_group_subject, void(const std::string&));
1359 MOCK_METHOD1(add_members, void(const messaging::Members&));
1360 MOCK_METHOD1(remove_members, void(const messaging::Members&));
1361 MOCK_METHOD0(group_id, std::string());
1362 MOCK_METHOD0(group_title, std::string());
1363+ MOCK_METHOD0(group_subject, std::string());
1364 MOCK_METHOD0(group_creator, std::shared_ptr<messaging::Member>());
1365 MOCK_METHOD0(members, messaging::Members());
1366 MOCK_METHOD1(set_observer, void(const std::shared_ptr<Observer>&));
1367+ MOCK_METHOD1(on_plugged, void(const std::weak_ptr<messaging::HasInterfaces>&));
1368 };
1369
1370 }

Subscribers

People subscribed via source and target branches

to all changes: