144
152
QDBusInterface *phoneAppHandler = TelepathyHelper::instance()->handlerInterface();
145
QDBusReply<QString> reply = phoneAppHandler->call("SendMessage", account->accountId(), recipients, message, QVariant::fromValue(newAttachments), properties);
153
QDBusReply<QString> reply = phoneAppHandler->call("SendMessage", account->accountId(), message, QVariant::fromValue(newAttachments), propMap);
146
154
if (reply.isValid()) {
147
155
return reply.value();
149
157
return QString();
160
QList<Tp::TextChannelPtr> ChatManager::channelForProperties(const QVariantMap &properties)
162
QList<Tp::TextChannelPtr> channels;
165
Q_FOREACH (Tp::TextChannelPtr channel, mTextChannels) {
166
if (channelMatchProperties(channel, properties)) {
174
Tp::TextChannelPtr ChatManager::channelForObjectPath(const QString &objectPath)
176
Q_FOREACH(Tp::TextChannelPtr channel, mTextChannels) {
177
if (channel->objectPath() == objectPath) {
181
return Tp::TextChannelPtr();
184
bool ChatManager::channelMatchProperties(const Tp::TextChannelPtr &channel, const QVariantMap &properties)
186
QVariantMap propMap = properties;
187
ChatEntry::ChatType chatType = ChatEntry::ChatTypeNone;
189
QStringList participants;
190
// participants coming from qml are variants
191
if (properties.contains("participantIds")) {
192
participants = properties["participantIds"].toStringList();
193
if (!participants.isEmpty()) {
194
propMap["participantIds"] = participants;
198
if (participants.isEmpty() && propMap.contains("participants")) {
199
// try to generate list of participants from "participants"
200
Q_FOREACH(const QVariant &participantMap, propMap["participants"].toList()) {
201
if (participantMap.toMap().contains("identifier")) {
202
participants << participantMap.toMap()["identifier"].toString();
205
if (!participants.isEmpty()) {
206
propMap["participantIds"] = participants;
210
if (properties.contains("chatType")) {
211
chatType = (ChatEntry::ChatType)properties["chatType"].toInt();
213
if (participants.length() == 1) {
214
chatType = ChatEntry::ChatTypeContact;
219
if (propMap.contains("accountId")) {
220
accountId = propMap["accountId"].toString();
223
if (participants.count() == 0 && chatType == ChatEntry::ChatTypeContact) {
227
AccountEntry *account = TelepathyHelper::instance()->accountForConnection(channel->connection());
232
// only channels of the correct type should be returned
233
if ((ChatEntry::ChatType)channel->targetHandleType() != chatType) {
237
if (chatType == ChatEntry::ChatTypeRoom) {
238
QString chatId = propMap["threadId"].toString();
239
if (!chatId.isEmpty() && channel->targetId() == chatId) {
240
// if we are filtering by one specific accountId, make sure it matches
241
if (!accountId.isEmpty() && accountId != account->accountId()) {
250
Tp::Contacts contacts = channel->groupContacts(false);
251
if (participants.count() != contacts.count()) {
254
int participantCount = 0;
255
// iterate over participants
256
Q_FOREACH (const Tp::ContactPtr &contact, contacts) {
257
// try the easiest first
258
if (participants.contains(contact->id())) {
263
// if no exact match, try to use the account's compare function
264
Q_FOREACH(const QString &participant, participants) {
265
if (account->compareIds(participant, contact->id())) {
271
return (participantCount == participants.count());
152
274
void ChatManager::onTextChannelAvailable(Tp::TextChannelPtr channel)
155
mPendingChannels.append(channel);
158
ChatEntry *chatEntry = new ChatEntry(channel, this);
159
mChatEntries.append(chatEntry);
161
connect(channel.data(),
162
SIGNAL(messageReceived(Tp::ReceivedMessage)),
163
SLOT(onMessageReceived(Tp::ReceivedMessage)));
164
connect(channel.data(),
165
SIGNAL(messageSent(Tp::Message,Tp::MessageSendingFlags,QString)),
166
SLOT(onMessageSent(Tp::Message,Tp::MessageSendingFlags,QString)));
167
connect(channel.data(),
276
mTextChannels << channel;
277
connect(channel.data(),
168
278
SIGNAL(invalidated(Tp::DBusProxy*,const QString&, const QString&)),
169
279
SLOT(onChannelInvalidated()));
171
Q_FOREACH(const Tp::ReceivedMessage &message, channel->messageQueue()) {
172
onMessageReceived(message);
175
Q_EMIT chatsChanged();
176
Q_EMIT chatEntryCreated(chatEntry->account()->accountId(), chatEntry->participants(), chatEntry);
281
Q_EMIT textChannelAvailable(channel);
179
284
void ChatManager::onChannelInvalidated()
181
286
Tp::TextChannelPtr channel(qobject_cast<Tp::TextChannel*>(sender()));
182
ChatEntry *chatEntry = chatEntryForChannel(channel);
184
mChatEntries.removeAll(chatEntry);
185
// for some reason deleteLater is not working
187
Q_EMIT chatsChanged();
191
ChatEntry *ChatManager::chatEntryForChannel(const Tp::TextChannelPtr &channel)
193
Q_FOREACH (ChatEntry *chatEntry, mChatEntries) {
194
if (channel == chatEntry->channel()) {
201
void ChatManager::onMessageReceived(const Tp::ReceivedMessage &message)
203
// ignore delivery reports for now
204
// FIXME: we need to handle errors on sending messages at some point
205
if (message.isDeliveryReport()) {
209
Q_EMIT messageReceived(message.sender()->id(), message.text(), message.received(), message.messageToken(), true);
212
void ChatManager::onMessageSent(const Tp::Message &sentMessage, const Tp::MessageSendingFlags flags, const QString &message)
217
Tp::TextChannel *channel = qobject_cast<Tp::TextChannel*>(sender());
222
QStringList recipients;
223
Q_FOREACH(const Tp::ContactPtr &contact, channel->groupContacts(false)) {
224
recipients << contact->id();
227
Q_EMIT messageSent(recipients, sentMessage.text());
230
void ChatManager::acknowledgeMessage(const QStringList &recipients, const QString &messageId, const QString &accountId)
232
AccountEntry *account = NULL;
233
if (accountId.isNull() || accountId.isEmpty()) {
234
account = TelepathyHelper::instance()->defaultMessagingAccount();
235
if (!account && !TelepathyHelper::instance()->activeAccounts().isEmpty()) {
236
account = TelepathyHelper::instance()->activeAccounts()[0];
239
account = TelepathyHelper::instance()->accountForId(accountId);
243
mMessagesToAck[accountId][recipients].append(messageId);
287
mTextChannels.removeAll(channel);
288
Q_EMIT textChannelInvalidated(channel);
291
void ChatManager::acknowledgeMessage(const QVariantMap &properties)
293
mMessagesToAck << QVariant::fromValue(convertPropertiesForDBus(properties));
247
294
mMessagesAckTimer.start();
248
mMessagesToAck[account->accountId()][recipients].append(messageId);
251
void ChatManager::acknowledgeAllMessages(const QStringList &recipients, const QString &accountId)
297
void ChatManager::acknowledgeAllMessages(const QVariantMap &properties)
253
299
QDBusInterface *phoneAppHandler = TelepathyHelper::instance()->handlerInterface();
254
phoneAppHandler->asyncCall("AcknowledgeAllMessages", recipients, accountId);
300
phoneAppHandler->asyncCall("AcknowledgeAllMessages", convertPropertiesForDBus(properties));
257
303
void ChatManager::onAckTimerTriggered()
259
305
// ack all pending messages
260
306
QDBusInterface *phoneAppHandler = TelepathyHelper::instance()->handlerInterface();
262
QMap<QString, QMap<QStringList,QStringList> >::const_iterator it = mMessagesToAck.constBegin();
263
while (it != mMessagesToAck.constEnd()) {
264
QString accountId = it.key();
265
QMap<QStringList, QStringList>::const_iterator it2 = it.value().constBegin();
266
while (it2 != it.value().constEnd()) {
267
phoneAppHandler->asyncCall("AcknowledgeMessages", it2.key(), it2.value(), accountId);
308
phoneAppHandler->asyncCall("AcknowledgeMessages", mMessagesToAck);
273
310
mMessagesToAck.clear();
276
QList<ChatEntry*> ChatManager::chatEntries() const
281
ChatEntry *ChatManager::chatEntryForParticipants(const QString &accountId, const QStringList &participants, bool create)
283
if (participants.count() == 0 || accountId.isEmpty()) {
287
AccountEntry *account = TelepathyHelper::instance()->accountForId(accountId);
293
Q_FOREACH (ChatEntry *chatEntry, mChatEntries) {
294
int participantCount = 0;
295
Tp::Contacts contacts = chatEntry->channel()->groupContacts(false);
296
if (participants.count() != contacts.count()) {
299
// iterate over participants
300
Q_FOREACH (const Tp::ContactPtr &contact, contacts) {
301
if (account->type() == AccountEntry::PhoneAccount || account->type() == AccountEntry::MultimediaAccount) {
302
Q_FOREACH(const QString &participant, participants) {
303
if (PhoneUtils::comparePhoneNumbers(participant, contact->id()) > PhoneUtils::NO_MATCH) {
310
if (participants.contains(contact->id())) {
316
if (participantCount == participants.count()) {
322
QDBusInterface *phoneAppHandler = TelepathyHelper::instance()->handlerInterface();
323
phoneAppHandler->call("StartChat", accountId, participants);
328
ChatEntry *ChatManager::chatEntryForChatRoom(const QString &accountId, const QVariantMap &properties, bool create)
336
QQmlListProperty<ChatEntry> ChatManager::chats()
338
return QQmlListProperty<ChatEntry>(this, 0, chatCount, chatAt);
341
int ChatManager::chatCount(QQmlListProperty<ChatEntry> *p)
343
return ChatManager::instance()->chatEntries().count();
346
ChatEntry *ChatManager::chatAt(QQmlListProperty<ChatEntry> *p, int index)
348
return ChatManager::instance()->chatEntries()[index];