23
23
#include "telepathyhelper_p.h"
24
24
#include "filter.h"
27
28
#include "pluginmanager.h"
28
29
#include "plugin.h"
29
30
#include "pluginthreadview.h"
30
31
#include "plugineventview.h"
32
#include "textevent.h"
32
34
#include <QStandardPaths>
33
35
#include <QCryptographicHash>
34
36
#include <TelepathyQt/CallChannel>
37
#include <TelepathyQt/PendingVariantMap>
35
38
#include <TelepathyQt/ReferencedHandles>
40
#include <TelepathyQt/PendingVariant>
41
#include <TelepathyQt/PendingOperation>
43
Q_DECLARE_METATYPE(RolesMap)
45
const constexpr static int AdminRole = 2;
47
enum ChannelGroupChangeReason
49
ChannelGroupChangeReasonNone = 0,
50
ChannelGroupChangeReasonOffline = 1,
51
ChannelGroupChangeReasonKicked = 2,
52
ChannelGroupChangeReasonBusy = 3,
53
ChannelGroupChangeReasonInvited = 4,
54
ChannelGroupChangeReasonBanned = 5,
55
ChannelGroupChangeReasonError = 6,
56
ChannelGroupChangeReasonInvalidContact = 7,
57
ChannelGroupChangeReasonNoAnswer = 8,
58
ChannelGroupChangeReasonRenamed = 9,
59
ChannelGroupChangeReasonPermissionDenied = 10,
60
ChannelGroupChangeReasonSeparated = 11,
62
// additional enum values not included in original ChannelGroupChangeReason
63
// telepathy enumeration but needed here to provide extra info to client when group
65
ChannelGroupChangeReasonGone = 12,
66
ChannelGroupChangeReasonRejected = 13
69
const QDBusArgument &operator>>(const QDBusArgument &argument, RolesMap &roles)
72
while ( !argument.atEnd() ) {
73
argument.beginMapEntry();
75
argument >> key >> value;
76
argument.endMapEntry();
84
bool foundAsMemberInThread(const Tp::ContactPtr& contact, QVariantMap thread)
86
Q_FOREACH (QVariant participant, thread[History::FieldParticipants].toList()) {
87
// found if same identifier and as member into thread info
88
if (History::Utils::compareIds(thread[History::FieldAccountId].toString(),
90
participant.toMap()[History::FieldIdentifier].toString()) &&
91
participant.toMap()[History::FieldParticipantState].toUInt() == History::ParticipantStateRegular)
99
bool foundInThread(const Tp::ContactPtr& contact, QVariantMap thread)
101
Q_FOREACH (QVariant participant, thread[History::FieldParticipants].toList()) {
102
if (History::Utils::compareIds(thread[History::FieldAccountId].toString(),
104
participant.toMap()[History::FieldIdentifier].toString()))
37
112
HistoryDaemon::HistoryDaemon(QObject *parent)
38
113
: QObject(parent), mCallObserver(this), mTextObserver(this)
115
qRegisterMetaType<HandleRolesMap>();
116
qDBusRegisterMetaType<HandleRolesMap>();
40
117
// get the first plugin
41
118
if (!History::PluginManager::instance()->plugins().isEmpty()) {
42
119
mBackend = History::PluginManager::instance()->plugins().first();
84
QStringList HistoryDaemon::participantsFromChannel(const Tp::TextChannelPtr &textChannel)
86
QStringList participants;
164
void HistoryDaemon::onRolesChanged(const HandleRolesMap &added, const HandleRolesMap &removed)
169
ChannelInterfaceRolesInterface *roles_interface = qobject_cast<ChannelInterfaceRolesInterface*>(sender());
170
RolesMap roles = roles_interface->getRoles();
172
Tp::TextChannelPtr channel(qobject_cast<Tp::TextChannel*>(sender()->parent()));
173
QVariantMap properties = propertiesFromChannel(channel);
174
QVariantMap thread = threadForProperties(channel->property(History::FieldAccountId).toString(),
175
History::EventTypeText,
177
matchFlagsForChannel(channel),
180
writeRolesInformationEvents(thread, channel, roles);
182
updateRoomRoles(channel, roles);
185
QVariantMap HistoryDaemon::propertiesFromChannel(const Tp::ChannelPtr &textChannel)
187
QVariantMap properties;
188
QVariantList participants;
189
QStringList participantIds;
191
ChannelInterfaceRolesInterface *roles_interface = textChannel->optionalInterface<ChannelInterfaceRolesInterface>();
193
if (roles_interface) {
194
roles = roles_interface->getRoles();
87
197
Q_FOREACH(const Tp::ContactPtr contact, textChannel->groupContacts(false)) {
88
participants << contact->id();
198
QVariantMap contactProperties;
199
contactProperties[History::FieldAlias] = contact->alias();
200
contactProperties[History::FieldAccountId] = textChannel->property(History::FieldAccountId).toString();
201
contactProperties[History::FieldIdentifier] = contact->id();
202
contactProperties[History::FieldParticipantState] = History::ParticipantStateRegular;
203
contactProperties[History::FieldParticipantRoles] = roles[contact->handle().at(0)];
204
participantIds << contact->id();
205
participants << contactProperties;
208
Q_FOREACH(const Tp::ContactPtr contact, textChannel->groupRemotePendingContacts(false)) {
209
QVariantMap contactProperties;
210
contactProperties[History::FieldAlias] = contact->alias();
211
contactProperties[History::FieldAccountId] = textChannel->property(History::FieldAccountId).toString();
212
contactProperties[History::FieldIdentifier] = contact->id();
213
contactProperties[History::FieldParticipantState] = History::ParticipantStateRemotePending;
214
contactProperties[History::FieldParticipantRoles] = roles[contact->handle().at(0)];
215
participantIds << contact->id();
216
participants << contactProperties;
219
Q_FOREACH(const Tp::ContactPtr contact, textChannel->groupLocalPendingContacts(false)) {
220
QVariantMap contactProperties;
221
contactProperties[History::FieldAlias] = contact->alias();
222
contactProperties[History::FieldAccountId] = textChannel->property(History::FieldAccountId).toString();
223
contactProperties[History::FieldIdentifier] = contact->id();
224
contactProperties[History::FieldParticipantState] = History::ParticipantStateLocalPending;
225
contactProperties[History::FieldParticipantRoles] = roles[contact->handle().at(0)];
226
participantIds << contact->id();
227
participants << contactProperties;
91
230
if (participants.isEmpty() && textChannel->targetHandleType() == Tp::HandleTypeContact &&
92
textChannel->targetContact() == textChannel->connection()->selfContact()) {
93
participants << textChannel->targetContact()->id();
231
textChannel->targetContact() == textChannel->connection()->selfContact()) {
232
QVariantMap contactProperties;
233
contactProperties[History::FieldAlias] = textChannel->targetContact()->alias();
234
contactProperties[History::FieldAccountId] = textChannel->property(History::FieldAccountId).toString();
235
contactProperties[History::FieldIdentifier] = textChannel->targetContact()->id();
236
contactProperties[History::FieldParticipantState] = History::ParticipantStateRegular;
237
participantIds << textChannel->targetContact()->id();
238
participants << contactProperties;
241
// We map chatType directly from telepathy targetHandleType: None, Contact, Room
242
properties[History::FieldChatType] = textChannel->targetHandleType();
243
properties[History::FieldParticipants] = participants;
244
properties[History::FieldParticipantIds] = participantIds;
246
QVariantMap roomProperties;
247
switch(textChannel->targetHandleType()) {
248
case Tp::HandleTypeRoom:
249
if (textChannel->hasInterface(TP_QT_IFACE_CHANNEL_INTERFACE_ROOM)) {
250
auto room_interface = textChannel->optionalInterface<Tp::Client::ChannelInterfaceRoomInterface>();
251
QVariantMap map = getInterfaceProperties(room_interface);
252
for (QVariantMap::const_iterator iter = map.begin(); iter != map.end(); ++iter) {
253
if (iter.value().isValid()) {
254
roomProperties[iter.key()] = iter.value();
258
if (textChannel->hasInterface(TP_QT_IFACE_CHANNEL_INTERFACE_ROOM_CONFIG)) {
259
auto room_config_interface = textChannel->optionalInterface<Tp::Client::ChannelInterfaceRoomConfigInterface>();
260
QVariantMap map = getInterfaceProperties(room_config_interface);
261
for (QVariantMap::const_iterator iter = map.begin(); iter != map.end(); ++iter) {
262
if (iter.value().isValid()) {
263
roomProperties[iter.key()] = iter.value();
267
if (textChannel->hasInterface(TP_QT_IFACE_CHANNEL_INTERFACE_SUBJECT)) {
268
auto subject_interface = textChannel->optionalInterface<Tp::Client::ChannelInterfaceSubjectInterface>();
269
QVariantMap map = getInterfaceProperties(subject_interface);
270
for (QVariantMap::const_iterator iter = map.begin(); iter != map.end(); ++iter) {
271
if (iter.value().isValid()) {
272
roomProperties[iter.key()] = iter.value();
277
properties[History::FieldChatRoomInfo] = roomProperties;
278
properties[History::FieldThreadId] = textChannel->targetId();
280
case Tp::HandleTypeContact:
281
case Tp::HandleTypeNone:
98
QVariantMap HistoryDaemon::threadForParticipants(const QString &accountId,
99
History::EventType type,
100
const QStringList &participants,
101
History::MatchFlags matchFlags,
289
QVariantMap HistoryDaemon::threadForProperties(const QString &accountId,
290
History::EventType type,
291
const QVariantMap &properties,
292
History::MatchFlags matchFlags,
105
296
return QVariantMap();
108
QVariantMap thread = mBackend->threadForParticipants(accountId,
299
QVariantMap thread = mBackend->threadForProperties(accountId,
112
303
if (thread.isEmpty() && create) {
113
thread = mBackend->createThreadForParticipants(accountId, type, participants);
304
thread = mBackend->createThreadForProperties(accountId, type, properties);
114
305
if (!thread.isEmpty()) {
306
if (properties.contains("Requested") && properties[History::FieldChatType].toInt() == History::ChatTypeRoom) {
307
QVariantMap map = thread[History::FieldChatRoomInfo].toMap();
308
map["Requested"] = properties["Requested"];
309
thread[History::FieldChatRoomInfo] = map;
115
311
mDBus.notifyThreadsAdded(QList<QVariantMap>() << thread);
414
611
event[History::FieldMissed] = missed;
415
612
event[History::FieldDuration] = duration;
416
613
// FIXME: check what to do when there are more than just one remote participant
417
event[History::FieldRemoteParticipant] = participants[0];
418
writeEvents(QList<QVariantMap>() << event);
614
event[History::FieldRemoteParticipant] = participants[0].toMap()[History::FieldIdentifier];
615
writeEvents(QList<QVariantMap>() << event, properties);
618
void HistoryDaemon::onTextChannelAvailable(const Tp::TextChannelPtr channel)
620
// for Rooms we need to explicitly create the thread to allow users to send messages to groups even
621
// before they receive any message.
622
// for other types, we can wait until messages are received
623
if (channel->targetHandleType() == Tp::HandleTypeRoom) {
624
QString accountId = channel->property(History::FieldAccountId).toString();
625
QVariantMap properties = propertiesFromChannel(channel);
627
// first try to fetch the existing thread to see if there is any.
628
QVariantMap thread = threadForProperties(accountId,
629
History::EventTypeText,
631
matchFlagsForChannel(channel),
633
if (thread.isEmpty()) {
634
// if there no existing thread, create one
635
properties["Requested"] = channel->isRequested();
636
thread = threadForProperties(accountId,
637
History::EventTypeText,
639
matchFlagsForChannel(channel),
642
// write information event including all initial invitees
643
Q_FOREACH(const Tp::ContactPtr contact, channel->groupRemotePendingContacts(false)) {
644
writeInformationEvent(thread, History::InformationTypeInvitationSent, contact->alias());
647
// update participants only if the thread is not available previously. Otherwise we'll wait for membersChanged event
648
// for reflect in conversation information events for modified participants.
649
updateRoomParticipants(channel);
652
// write an entry saying you joined the group if 'joined' flag in thread is false and modify that flag.
653
if (!thread[History::FieldChatRoomInfo].toMap()["Joined"].toBool()) {
654
// only write self joined notification if protocol is not a phone one.
655
// FIXME (rmescandon): as a first solution, let's take only ofono as phone protocol
656
if (History::TelepathyHelper::instance()->accountForId(accountId)->protocolName() != "ofono") {
657
writeInformationEvent(thread, History::InformationTypeSelfJoined);
660
updateRoomProperties(channel, QVariantMap{{"Joined", true}});
663
Tp::AbstractInterface *room_interface = channel->optionalInterface<Tp::Client::ChannelInterfaceRoomInterface>();
664
Tp::AbstractInterface *room_config_interface = channel->optionalInterface<Tp::Client::ChannelInterfaceRoomConfigInterface>();
665
Tp::AbstractInterface *subject_interface = channel->optionalInterface<Tp::Client::ChannelInterfaceSubjectInterface>();
666
ChannelInterfaceRolesInterface *roles_interface = channel->optionalInterface<ChannelInterfaceRolesInterface>();
668
QList<Tp::AbstractInterface*> interfaces;
669
interfaces << room_interface << room_config_interface << subject_interface << roles_interface;
670
for (auto interface : interfaces) {
672
interface->setMonitorProperties(true);
673
interface->setProperty(History::FieldAccountId, accountId);
674
interface->setProperty(History::FieldThreadId, thread[History::FieldThreadId].toString());
675
interface->setProperty(History::FieldType, thread[History::FieldType].toInt());
676
connect(interface, SIGNAL(propertiesChanged(const QVariantMap &,const QStringList &)),
677
SLOT(onRoomPropertiesChanged(const QVariantMap &,const QStringList &)));
678
// update the stored info
679
Q_EMIT interface->propertiesChanged(getInterfaceProperties(interface), QStringList());
683
connect(channel.data(), SIGNAL(groupMembersChanged(const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Channel::GroupMemberChangeDetails &)),
684
SLOT(onGroupMembersChanged(const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Channel::GroupMemberChangeDetails &)));
686
connect(roles_interface, SIGNAL(RolesChanged(const HandleRolesMap&, const HandleRolesMap&)), SLOT(onRolesChanged(const HandleRolesMap&, const HandleRolesMap&)));
690
void HistoryDaemon::onGroupMembersChanged(const Tp::Contacts &groupMembersAdded,
691
const Tp::Contacts &groupLocalPendingMembersAdded,
692
const Tp::Contacts &groupRemotePendingMembersAdded,
693
const Tp::Contacts &groupMembersRemoved,
694
const Tp::Channel::GroupMemberChangeDetails &details)
696
Tp::TextChannelPtr channel(qobject_cast<Tp::TextChannel*>(sender()));
698
QVariantMap properties;
701
// information events for members updates.
702
bool hasRemotePendingMembersAdded = groupRemotePendingMembersAdded.size() > 0;
703
bool hasMembersAdded = groupMembersAdded.size() > 0;
704
bool hasMembersRemoved = groupMembersRemoved.size() > 0;
706
if (hasRemotePendingMembersAdded || hasMembersAdded || hasMembersRemoved) {
707
properties = propertiesFromChannel(channel);
708
thread = threadForProperties(channel->property(History::FieldAccountId).toString(),
709
History::EventTypeText,
711
matchFlagsForChannel(channel),
713
if (!thread.isEmpty()) {
714
if (hasRemotePendingMembersAdded) {
715
Q_FOREACH (const Tp::ContactPtr& contact, groupRemotePendingMembersAdded) {
716
if (!foundInThread(contact, thread)) {
717
writeInformationEvent(thread, History::InformationTypeInvitationSent, contact->alias());
721
if (hasMembersAdded) {
722
Q_FOREACH (const Tp::ContactPtr& contact, groupMembersAdded) {
723
// if this member was not previously regular member in thread, notify about his join
724
if (!foundAsMemberInThread(contact, thread)) {
725
writeInformationEvent(thread, History::InformationTypeJoined, contact->alias());
730
if (hasMembersRemoved) {
731
if (channel->groupSelfContactRemoveInfo().isValid()) {
732
// evaluate if we are leaving by our own or we are kicked
733
History::InformationType type = History::InformationTypeSelfLeaving;
734
if (channel->groupSelfContactRemoveInfo().hasReason()) {
735
switch (channel->groupSelfContactRemoveInfo().reason()) {
736
case ChannelGroupChangeReasonKicked:
737
type = History::InformationTypeSelfKicked;
739
case ChannelGroupChangeReasonGone:
740
type = History::InformationTypeGroupGone;
744
writeInformationEvent(thread, type);
746
updateRoomProperties(channel, QVariantMap{{"Joined", false}});
748
else // don't notify any other group member removal if we are leaving the group
750
Q_FOREACH (const Tp::ContactPtr& contact, groupMembersRemoved) {
751
// inform about removed members other than us
752
if (contact->id() != channel->groupSelfContact()->id()) {
753
writeInformationEvent(thread, History::InformationTypeLeaving, contact->alias());
761
updateRoomParticipants(channel);
764
void HistoryDaemon::updateRoomParticipants(const Tp::TextChannelPtr channel)
770
QVariantList participants;
771
QStringList contactsAdded;
773
ChannelInterfaceRolesInterface *roles_interface = channel->optionalInterface<ChannelInterfaceRolesInterface>();
775
if (roles_interface) {
776
roles = roles_interface->getRoles();
779
Q_FOREACH(const Tp::ContactPtr contact, channel->groupRemotePendingContacts(false)) {
780
QVariantMap participant;
781
contactsAdded << contact->id();
782
participant[History::FieldIdentifier] = contact->id();
783
participant[History::FieldAlias] = contact->alias();
784
participant[History::FieldParticipantState] = History::ParticipantStateRemotePending;
785
participant[History::FieldParticipantRoles] = roles[contact->handle().at(0)];
786
participants << QVariant::fromValue(participant);
788
Q_FOREACH(const Tp::ContactPtr contact, channel->groupLocalPendingContacts(false)) {
789
QVariantMap participant;
790
contactsAdded << contact->id();
791
participant[History::FieldIdentifier] = contact->id();
792
participant[History::FieldAlias] = contact->alias();
793
participant[History::FieldParticipantState] = History::ParticipantStateLocalPending;
794
participant[History::FieldParticipantRoles] = roles[contact->handle().at(0)];
795
participants << QVariant::fromValue(participant);
798
Q_FOREACH(const Tp::ContactPtr contact, channel->groupContacts(false)) {
799
// do not include remote and local pending members
800
if (contactsAdded.contains(contact->id())) {
803
QVariantMap participant;
804
participant[History::FieldIdentifier] = contact->id();
805
participant[History::FieldAlias] = contact->alias();
806
participant[History::FieldParticipantState] = History::ParticipantStateRegular;
807
participant[History::FieldParticipantRoles] = roles[contact->handle().at(0)];
808
participants << QVariant::fromValue(participant);
811
QString accountId = channel->property(History::FieldAccountId).toString();
812
QString threadId = channel->targetId();
813
if (mBackend->updateRoomParticipants(accountId, threadId, History::EventTypeText, participants)) {
814
QVariantMap updatedThread = getSingleThread(History::EventTypeText, accountId, threadId, QVariantMap());
815
mDBus.notifyThreadsModified(QList<QVariantMap>() << updatedThread);
819
void HistoryDaemon::updateRoomRoles(const Tp::TextChannelPtr &channel, const RolesMap &rolesMap)
825
QVariantMap participantsRoles;
827
Q_FOREACH(const Tp::ContactPtr contact, channel->groupRemotePendingContacts(false)) {
828
participantsRoles[contact->id()] = rolesMap[contact->handle().at(0)];
830
Q_FOREACH(const Tp::ContactPtr contact, channel->groupLocalPendingContacts(false)) {
831
participantsRoles[contact->id()] = rolesMap[contact->handle().at(0)];
834
Q_FOREACH(const Tp::ContactPtr contact, channel->groupContacts(false)) {
835
if (!participantsRoles.contains(contact->id())) {
836
participantsRoles[contact->id()] = rolesMap[contact->handle().at(0)];
840
// update participants roles
841
QString accountId = channel->property(History::FieldAccountId).toString();
842
QString threadId = channel->targetId();
843
if (mBackend->updateRoomParticipantsRoles(accountId, threadId, History::EventTypeText, participantsRoles)) {
844
QVariantMap updatedThread = getSingleThread(History::EventTypeText, accountId, threadId, QVariantMap());
845
mDBus.notifyThreadsModified(QList<QVariantMap>() << updatedThread);
848
// update self roles in room properties
849
uint selfRoles = rolesMap[channel->groupSelfContact()->handle().at(0)];
850
updateRoomProperties(channel, QVariantMap{{"SelfRoles", selfRoles}});
853
void HistoryDaemon::onRoomPropertiesChanged(const QVariantMap &properties,const QStringList &invalidated)
855
QString accountId = sender()->property(History::FieldAccountId).toString();
856
QString threadId = sender()->property(History::FieldThreadId).toString();
857
History::EventType type = (History::EventType)sender()->property(History::FieldType).toInt();
859
// get thread before updating to see if there are changes to insert as information events
860
QVariantMap thread = getSingleThread(type, accountId, threadId, QVariantMap());
861
if (!thread.empty()) {
862
writeRoomChangesInformationEvents(thread, properties);
865
updateRoomProperties(accountId, threadId, type, properties, invalidated);
868
void HistoryDaemon::updateRoomProperties(const Tp::TextChannelPtr &channel, const QVariantMap &properties)
870
QString accountId = channel->property(History::FieldAccountId).toString();
871
QString threadId = channel->targetId();
872
History::EventType type = History::EventTypeText;
873
updateRoomProperties(accountId, threadId, type, properties, QStringList());
876
void HistoryDaemon::updateRoomProperties(const QString &accountId, const QString &threadId, History::EventType type, const QVariantMap &properties, const QStringList &invalidated)
878
if (mBackend->updateRoomInfo(accountId, threadId, type, properties, invalidated)) {
879
QVariantMap thread = getSingleThread(type, accountId, threadId, QVariantMap());
880
mDBus.notifyThreadsModified(QList<QVariantMap>() << thread);
421
884
void HistoryDaemon::onMessageReceived(const Tp::TextChannelPtr textChannel, const Tp::ReceivedMessage &message)
423
qDebug() << __PRETTY_FUNCTION__;
425
887
Tp::MessagePart header = message.header();
426
888
QString senderId;
889
QVariantMap properties = propertiesFromChannel(textChannel);
427
890
History::MessageStatus status = History::MessageStatusUnknown;
428
if (message.sender()->handle().at(0) == textChannel->connection()->selfHandle()) {
891
if (!message.sender() || message.sender()->handle().at(0) == textChannel->connection()->selfHandle()) {
429
892
senderId = "self";
430
893
status = History::MessageStatusDelivered;
707
1180
hash += "#-#" + thread[History::FieldThreadId].toString();
1184
QVariantMap HistoryDaemon::getInterfaceProperties(const Tp::AbstractInterface *interface)
1186
QDBusInterface propsInterface(interface->service(), interface->path(), "org.freedesktop.DBus.Properties");
1187
QDBusReply<QVariantMap> reply = propsInterface.call("GetAll", interface->interface());
1188
if (!reply.isValid()) {
1189
qWarning() << "Failed to fetch channel properties for interface" << interface->interface() << reply.error().message();
1191
return reply.value();
1194
void HistoryDaemon::writeInformationEvent(const QVariantMap &thread, History::InformationType type, const QString &subject, const QString &sender, const QString &text)
1196
History::TextEvent historyEvent = History::TextEvent(thread[History::FieldAccountId].toString(),
1197
thread[History::FieldThreadId].toString(),
1198
QString(QCryptographicHash::hash(QByteArray(
1199
(QDateTime::currentDateTime().toString("yyyy-MM-ddTHH:mm:ss.zzz") + subject + text).toLatin1()),
1200
QCryptographicHash::Md5).toHex()),
1202
QDateTime::currentDateTime(),
1205
History::MessageTypeInformation,
1206
History::MessageStatusUnknown,
1207
QDateTime::currentDateTime(),
1210
writeEvents(QList<QVariantMap>() << historyEvent.properties(), thread);
1213
void HistoryDaemon::writeRoomChangesInformationEvents(const QVariantMap &thread, const QVariantMap &interfaceProperties)
1215
if (!thread.isEmpty()) {
1217
QString storedSubject = thread[History::FieldChatRoomInfo].toMap()["Subject"].toString();
1218
QString newSubject = interfaceProperties["Subject"].toString();
1219
if (!newSubject.isEmpty() && storedSubject != newSubject) {
1220
//see if we have an actor. If actor is 'me', we have changed that subject
1221
QString actor = thread[History::FieldChatRoomInfo].toMap()["Actor"].toString();
1222
if (actor == "me") {
1225
writeInformationEvent(thread, History::InformationTypeTitleChanged, newSubject, actor);
1230
void HistoryDaemon::writeRolesInformationEvents(const QVariantMap &thread, const Tp::ChannelPtr &channel, const RolesMap &rolesMap)
1232
if (thread.isEmpty()) {
1236
if (!thread[History::FieldChatRoomInfo].toMap()["Joined"].toBool()) {
1240
// list of identifiers for current channel admins
1241
QStringList adminIds;
1243
Q_FOREACH(const Tp::ContactPtr contact, channel->groupContacts(false)) {
1244
// see if admin role (ChannelAdminRole == 2)
1245
if (rolesMap[contact->handle().at(0)] & AdminRole) {
1246
adminIds << contact->id();
1250
Q_FOREACH (QVariant participant, thread[History::FieldParticipants].toList()) {
1251
QString participantId = participant.toMap()[History::FieldIdentifier].toString();
1252
if (adminIds.contains(participantId)) {
1253
// see if already was admin or not (ChannelAdminRole == 2)
1254
if (! (participant.toMap()[History::FieldParticipantRoles].toUInt() & AdminRole)) {
1255
writeInformationEvent(thread, History::InformationTypeAdminGranted, participantId);
1260
//evaluate now self roles
1261
if (rolesMap[channel->groupSelfContact()->handle().at(0)] & AdminRole) {
1262
uint selfRoles = thread[History::FieldChatRoomInfo].toMap()["SelfRoles"].toUInt();
1263
if (! (selfRoles & AdminRole)) {
1264
writeInformationEvent(thread, History::InformationTypeSelfAdminGranted);