473
QVariantMap SQLiteHistoryPlugin::createThreadForParticipants(const QString &accountId, History::EventType type, const QStringList &participants)
514
bool SQLiteHistoryPlugin::updateRoomParticipants(const QString &accountId, const QString &threadId, History::EventType type, const QVariantList &participants)
516
QSqlQuery query(SQLiteDatabase::instance()->database());
517
if (accountId.isEmpty() || threadId.isEmpty()) {
521
SQLiteDatabase::instance()->beginTransation();
522
QString deleteString("DELETE FROM thread_participants WHERE threadId=:threadId AND type=:type AND accountId=:accountId");
523
query.prepare(deleteString);
524
query.bindValue(":accountId", accountId);
525
query.bindValue(":threadId", threadId);
526
query.bindValue(":type", type);
528
qCritical() << "Error removing old participants:" << query.lastError() << query.lastQuery();
529
SQLiteDatabase::instance()->rollbackTransaction();
533
// and insert the participants
534
Q_FOREACH(const QVariant &participantVariant, participants) {
535
QVariantMap participant = participantVariant.toMap();
536
query.prepare("INSERT INTO thread_participants (accountId, threadId, type, participantId, normalizedId, alias, state, roles)"
537
"VALUES (:accountId, :threadId, :type, :participantId, :normalizedId, :alias, :state, :roles)");
538
query.bindValue(":accountId", accountId);
539
query.bindValue(":threadId", threadId);
540
query.bindValue(":type", type);
541
query.bindValue(":participantId", participant["identifier"].toString());
542
query.bindValue(":normalizedId", participant["identifier"].toString());
543
query.bindValue(":alias", participant["alias"].toString());
544
query.bindValue(":state", participant["state"].toUInt());
545
query.bindValue(":roles", participant["roles"].toUInt());
547
qCritical() << "Error:" << query.lastError() << query.lastQuery();
548
SQLiteDatabase::instance()->rollbackTransaction();
553
if (!SQLiteDatabase::instance()->finishTransaction()) {
554
qCritical() << "Failed to commit the transaction.";
558
QVariantMap existingThread = getSingleThread(type,
563
if (!existingThread.isEmpty()) {
564
addThreadsToCache(QList<QVariantMap>() << existingThread);
570
bool SQLiteHistoryPlugin::updateRoomParticipantsRoles(const QString &accountId, const QString &threadId, History::EventType type, const QVariantMap &participantsRoles)
572
QSqlQuery query(SQLiteDatabase::instance()->database());
573
if (accountId.isEmpty() || threadId.isEmpty()) {
577
SQLiteDatabase::instance()->beginTransation();
578
Q_FOREACH(const QString &participantId, participantsRoles.keys()) {
579
query.prepare("UPDATE thread_participants SET roles=:roles WHERE accountId=:accountId AND threadId=:threadId AND type=:type AND participantId=:participantId");
580
query.bindValue(":roles", participantsRoles.value(participantId).toUInt());
581
query.bindValue(":accountId", accountId);
582
query.bindValue(":threadId", threadId);
583
query.bindValue(":type", type);
584
query.bindValue(":participantId", participantId);
586
qCritical() << "Error:" << query.lastError() << query.lastQuery();
587
SQLiteDatabase::instance()->rollbackTransaction();
592
if (!SQLiteDatabase::instance()->finishTransaction()) {
593
qCritical() << "Failed to commit the transaction.";
597
QVariantMap existingThread = getSingleThread(type,
602
if (!existingThread.isEmpty()) {
603
addThreadsToCache(QList<QVariantMap>() << existingThread);
609
bool SQLiteHistoryPlugin::updateRoomInfo(const QString &accountId, const QString &threadId, History::EventType type, const QVariantMap &properties, const QStringList &invalidated)
611
QSqlQuery query(SQLiteDatabase::instance()->database());
613
if (threadId.isEmpty() || accountId.isEmpty()) {
617
SQLiteDatabase::instance()->beginTransation();
619
QDateTime creationTimestamp = QDateTime::fromTime_t(properties["CreationTimestamp"].toUInt());
620
QDateTime timestamp = QDateTime::fromTime_t(properties["Timestamp"].toUInt());
622
QVariantMap propertyMapping;
623
propertyMapping["RoomName"] = "roomName";
624
propertyMapping["Server"] = "server";
625
propertyMapping["Creator"] = "creator";
626
propertyMapping["CreationTimestamp"] = "creationTimestamp";
627
propertyMapping["Anonymous"] = "anonymous";
628
propertyMapping["InviteOnly"] = "inviteOnly";
629
propertyMapping["Limit"] = "participantLimit";
630
propertyMapping["Moderated"] = "moderated";
631
propertyMapping["Title"] = "title";
632
propertyMapping["Description"] = "description";
633
propertyMapping["Persistent"] = "persistent";
634
propertyMapping["Private"] = "private";
635
propertyMapping["PasswordProtected"] = "passwordProtected";
636
propertyMapping["Password"] = "password";
637
propertyMapping["PasswordHint"] = "passwordHint";
638
propertyMapping["CanUpdateConfiguration"] = "canUpdateConfiguration";
639
propertyMapping["Subject"] = "subject";
640
propertyMapping["Actor"] = "actor";
641
propertyMapping["Timestamp"] = "timestamp";
642
propertyMapping["Joined"] = "joined";
643
propertyMapping["SelfRoles"] = "selfRoles";
645
QStringList changedPropListValues;
646
// populate sql query
647
Q_FOREACH (const QString &key, properties.keys()) {
648
if (propertyMapping.contains(key)) {
649
QString prop = propertyMapping[key].toString();
650
changedPropListValues << QString(prop+"=:"+ prop);
653
if (changedPropListValues.isEmpty()) {
657
query.prepare("UPDATE chat_room_info SET "+ changedPropListValues.join(", ")+" WHERE accountId=:accountId AND threadId=:threadId AND type=:type");
658
query.bindValue(":accountId", accountId);
659
query.bindValue(":threadId", threadId);
660
query.bindValue(":type", (int) type);
661
query.bindValue(":roomName", properties["RoomName"].toString());
662
query.bindValue(":server", properties["Server"].toString());
663
query.bindValue(":creator", properties["Creator"].toString());
664
query.bindValue(":creationTimestamp", creationTimestamp.toUTC().toString(timestampFormat));
665
query.bindValue(":anonymous", properties["Anonymous"].toBool());
666
query.bindValue(":inviteOnly", properties["InviteOnly"].toBool());
667
query.bindValue(":participantLimit", properties["Limit"].toInt());
668
query.bindValue(":moderated", properties["Moderated"].toBool());
669
query.bindValue(":title", properties["Title"].toString());
670
query.bindValue(":description", properties["Description"].toString());
671
query.bindValue(":persistent", properties["Persistent"].toBool());
672
query.bindValue(":private", properties["Private"].toBool());
673
query.bindValue(":passwordProtected", properties["PasswordProtected"].toBool());
674
query.bindValue(":password", properties["Password"].toString());
675
query.bindValue(":passwordHint", properties["PasswordHint"].toString());
676
query.bindValue(":canUpdateConfiguration", properties["CanUpdateConfiguration"].toBool());
677
query.bindValue(":subject", properties["Subject"].toString());
678
query.bindValue(":actor", properties["Actor"].toString());
679
query.bindValue(":timestamp", timestamp.toUTC().toString(timestampFormat));
680
query.bindValue(":joined", properties["Joined"].toBool());
681
query.bindValue(":selfRoles", properties["SelfRoles"].toInt());
684
qCritical() << "Error:" << query.lastError() << query.lastQuery();
685
SQLiteDatabase::instance()->rollbackTransaction();
689
if (!SQLiteDatabase::instance()->finishTransaction()) {
690
qCritical() << "Failed to commit the transaction.";
694
QVariantMap existingThread = getSingleThread(type,
699
if (!existingThread.isEmpty()) {
700
addThreadsToCache(QList<QVariantMap>() << existingThread);
706
QVariantMap SQLiteHistoryPlugin::createThreadForProperties(const QString &accountId, History::EventType type, const QVariantMap &properties)
475
708
// WARNING: this function does NOT test to check if the thread is already created, you should check using HistoryReader::threadForParticipants()
477
710
QVariantMap thread;
711
History::Participants participants = History::Participants::fromVariant(properties[History::FieldParticipantIds]);
479
713
// Create a new thread
480
714
// FIXME: define what the threadId will be
481
QString threadId = participants.join("%");
716
History::ChatType chatType = (History::ChatType)properties[History::FieldChatType].toInt();
717
QVariantMap chatRoomInfo;
719
SQLiteDatabase::instance()->beginTransation();
721
if (chatType == History::ChatTypeRoom) {
722
threadId = properties[History::FieldThreadId].toString();
723
// we cannot save chat room without threadId
724
if (accountId.isEmpty() || threadId.isEmpty()) {
725
SQLiteDatabase::instance()->rollbackTransaction();
728
chatRoomInfo = properties[History::FieldChatRoomInfo].toMap();
729
QSqlQuery query(SQLiteDatabase::instance()->database());
731
QDateTime creationTimestamp = QDateTime::fromTime_t(chatRoomInfo["CreationTimestamp"].toUInt());
732
QDateTime timestamp = QDateTime::fromTime_t(chatRoomInfo["Timestamp"].toUInt());
734
query.prepare("INSERT INTO chat_room_info (accountId, threadId, type, roomName, server, creator, creationTimestamp, anonymous, inviteOnly, participantLimit, moderated, title, description, persistent, private, passwordProtected, password, passwordHint, canUpdateConfiguration, subject, actor, timestamp, joined, selfRoles) "
735
"VALUES (:accountId, :threadId, :type, :roomName, :server, :creator, :creationTimestamp, :anonymous, :inviteOnly, :participantLimit, :moderated, :title, :description, :persistent, :private, :passwordProtected, :password, :passwordHint, :canUpdateConfiguration, :subject, :actor, :timestamp, :joined, :selfRoles)");
736
query.bindValue(":accountId", accountId);
737
query.bindValue(":threadId", threadId);
738
query.bindValue(":type", (int) type);
739
query.bindValue(":roomName", chatRoomInfo["RoomName"].toString());
740
query.bindValue(":server", chatRoomInfo["Server"].toString());
741
query.bindValue(":creator", chatRoomInfo["Creator"].toString());
742
query.bindValue(":creationTimestamp", creationTimestamp.toUTC().toString(timestampFormat));
743
query.bindValue(":anonymous", chatRoomInfo["Anonymous"].toBool());
744
query.bindValue(":inviteOnly", chatRoomInfo["InviteOnly"].toBool());
745
query.bindValue(":participantLimit", chatRoomInfo["Limit"].toInt());
746
query.bindValue(":moderated", chatRoomInfo["Moderated"].toBool());
747
query.bindValue(":title", chatRoomInfo["Title"].toString());
748
query.bindValue(":description", chatRoomInfo["Description"].toString());
749
query.bindValue(":persistent", chatRoomInfo["Persistent"].toBool());
750
query.bindValue(":private", chatRoomInfo["Private"].toBool());
751
query.bindValue(":passwordProtected", chatRoomInfo["PasswordProtected"].toBool());
752
query.bindValue(":password", chatRoomInfo["Password"].toString());
753
query.bindValue(":passwordHint", chatRoomInfo["PasswordHint"].toString());
754
query.bindValue(":canUpdateConfiguration", chatRoomInfo["CanUpdateConfiguration"].toBool());
755
query.bindValue(":subject", chatRoomInfo["Subject"].toString());
756
query.bindValue(":actor", chatRoomInfo["Actor"].toString());
757
query.bindValue(":timestamp", timestamp.toUTC().toString(timestampFormat));
758
query.bindValue(":joined", chatRoomInfo["Joined"].toBool());
759
query.bindValue(":selfRoles", chatRoomInfo["SelfRoles"].toInt());
762
qCritical() << "Error:" << query.lastError() << query.lastQuery();
763
SQLiteDatabase::instance()->rollbackTransaction();
764
return QVariantMap();
766
for (QVariantMap::iterator iter = chatRoomInfo.begin(); iter != chatRoomInfo.end();) {
767
if (!iter.value().isValid()) {
768
iter = chatRoomInfo.erase(iter);
773
thread[History::FieldChatRoomInfo] = chatRoomInfo;
774
} else if (chatType == History::ChatTypeContact) {
775
threadId = participants.identifiers().join("%");
777
threadId = QString("broadcast:%1").arg(QString(QCryptographicHash::hash(participants.identifiers().join(";").toLocal8Bit(),QCryptographicHash::Md5).toHex()));;
483
780
QSqlQuery query(SQLiteDatabase::instance()->database());
484
query.prepare("INSERT INTO threads (accountId, threadId, type, count, unreadCount)"
485
"VALUES (:accountId, :threadId, :type, :count, :unreadCount)");
781
query.prepare("INSERT INTO threads (accountId, threadId, type, count, unreadCount, chatType, lastEventTimestamp)"
782
"VALUES (:accountId, :threadId, :type, :count, :unreadCount, :chatType, :lastEventTimestamp)");
486
783
query.bindValue(":accountId", accountId);
487
784
query.bindValue(":threadId", threadId);
488
785
query.bindValue(":type", (int) type);
489
786
query.bindValue(":count", 0);
490
787
query.bindValue(":unreadCount", 0);
788
query.bindValue(":chatType", (int) chatType);
789
// make sure threads are created with an up-to-date timestamp
790
query.bindValue(":lastEventTimestamp", QDateTime::currentDateTimeUtc().toString(timestampFormat));
491
791
if (!query.exec()) {
492
792
qCritical() << "Error:" << query.lastError() << query.lastQuery();
793
SQLiteDatabase::instance()->rollbackTransaction();
493
794
return QVariantMap();
496
797
// and insert the participants
497
Q_FOREACH(const QString &participant, participants) {
498
query.prepare("INSERT INTO thread_participants (accountId, threadId, type, participantId, normalizedId)"
499
"VALUES (:accountId, :threadId, :type, :participantId, :normalizedId)");
798
Q_FOREACH(const History::Participant &participant, participants) {
799
query.prepare("INSERT INTO thread_participants (accountId, threadId, type, participantId, normalizedId, alias, state, roles)"
800
"VALUES (:accountId, :threadId, :type, :participantId, :normalizedId, :alias, :state, :roles)");
500
801
query.bindValue(":accountId", accountId);
501
802
query.bindValue(":threadId", threadId);
502
803
query.bindValue(":type", type);
503
query.bindValue(":participantId", participant);
504
query.bindValue(":normalizedId", History::Utils::normalizeId(accountId, participant));
804
query.bindValue(":participantId", participant.identifier());
805
query.bindValue(":normalizedId", History::Utils::normalizeId(accountId, participant.identifier()));
806
query.bindValue(":alias", participant.alias());
807
query.bindValue(":state", participant.state());
808
query.bindValue(":roles", participant.roles());
505
809
if (!query.exec()) {
506
810
qCritical() << "Error:" << query.lastError() << query.lastQuery();
811
SQLiteDatabase::instance()->rollbackTransaction();
507
812
return QVariantMap();
816
if (!SQLiteDatabase::instance()->finishTransaction()) {
817
qCritical() << "Failed to commit the transaction.";
818
return QVariantMap();
511
821
// and finally create the thread
512
822
thread[History::FieldAccountId] = accountId;
513
823
thread[History::FieldThreadId] = threadId;
514
824
thread[History::FieldType] = (int) type;
515
thread[History::FieldParticipants] = History::ContactMatcher::instance()->contactInfo(accountId, participants, true);
825
QVariantList contactList;
826
QVariantList contactInfo = History::ContactMatcher::instance()->contactInfo(accountId, participants.identifiers(), true);
827
for (int i = 0; i < participants.count(); ++i) {
828
QVariantMap map = contactInfo[i].toMap();
829
History::Participant participant = participants[i];
830
map["state"] = participant.state();
831
map["roles"] = participant.roles();
834
thread[History::FieldParticipants] = contactList;
516
835
thread[History::FieldCount] = 0;
517
836
thread[History::FieldUnreadCount] = 0;
837
thread[History::FieldChatType] = (int)chatType;
519
839
addThreadsToCache(QList<QVariantMap>() << thread);
845
QVariantMap SQLiteHistoryPlugin::createThreadForParticipants(const QString &accountId, History::EventType type, const QStringList &participants)
847
QVariantMap properties;
848
properties[History::FieldParticipantIds] = participants;
849
properties[History::FieldChatType] = participants.size() != 1 ? History::ChatTypeNone : History::ChatTypeContact;
850
return createThreadForProperties(accountId, type, properties);
524
853
bool SQLiteHistoryPlugin::removeThread(const QVariantMap &thread)
526
855
QSqlQuery query(SQLiteDatabase::instance()->database());
857
1225
thread[History::FieldAttachments] = QVariant::fromValue(attachments);
858
1226
attachments.clear();
860
thread[History::FieldMessage] = query.value(9);
861
thread[History::FieldMessageType] = query.value(10);
862
thread[History::FieldMessageStatus] = query.value(11);
863
thread[History::FieldReadTimestamp] = toLocalTimeString(query.value(12).toDateTime());
1228
thread[History::FieldMessage] = query.value(11);
1229
thread[History::FieldMessageType] = query.value(12);
1230
thread[History::FieldMessageStatus] = query.value(13);
1231
thread[History::FieldReadTimestamp] = toLocalTimeString(query.value(14).toDateTime());
1232
thread[History::FieldChatType] = query.value(15).toUInt();
1234
if (thread[History::FieldChatType].toInt() == 2) {
1235
QVariantMap chatRoomInfo;
1236
QSqlQuery query1(SQLiteDatabase::instance()->database());
1238
query1.prepare("SELECT roomName, server, creator, creationTimestamp, anonymous, inviteOnly, participantLimit, moderated, title, description, persistent, private, passwordProtected, password, passwordHint, canUpdateConfiguration, subject, actor, timestamp, joined, selfRoles FROM chat_room_info WHERE accountId=:accountId AND threadId=:threadId AND type=:type LIMIT 1");
1239
query1.bindValue(":accountId", thread[History::FieldAccountId]);
1240
query1.bindValue(":threadId", thread[History::FieldThreadId]);
1241
query1.bindValue(":type", thread[History::FieldType].toInt());
1243
if (!query1.exec()) {
1244
qCritical() << "Failed to get chat room info for thread: Error:" << query1.lastError() << query1.lastQuery();
1249
if (query1.value(0).isValid())
1250
chatRoomInfo["RoomName"] = query1.value(0);
1251
if (query1.value(1).isValid())
1252
chatRoomInfo["Server"] = query1.value(1);
1253
if (query1.value(2).isValid())
1254
chatRoomInfo["Creator"] = query1.value(2);
1255
if (query1.value(3).isValid())
1256
chatRoomInfo["CreationTimestamp"] = toLocalTimeString(query1.value(3).toDateTime());
1257
if (query1.value(4).isValid())
1258
chatRoomInfo["Anonymous"] = query1.value(4).toBool();
1259
if (query1.value(5).isValid())
1260
chatRoomInfo["InviteOnly"] = query1.value(5).toBool();
1261
if (query1.value(6).isValid())
1262
chatRoomInfo["Limit"] = query1.value(6).toInt();
1263
if (query1.value(7).isValid())
1264
chatRoomInfo["Moderated"] = query1.value(7).toBool();
1265
if (query1.value(8).isValid())
1266
chatRoomInfo["Title"] = query1.value(8);
1267
if (query1.value(9).isValid())
1268
chatRoomInfo["Description"] = query1.value(9);
1269
if (query1.value(10).isValid())
1270
chatRoomInfo["Persistent"] = query1.value(10).toBool();
1271
if (query1.value(11).isValid())
1272
chatRoomInfo["Private"] = query1.value(11).toBool();
1273
if (query1.value(12).isValid())
1274
chatRoomInfo["PasswordProtected"] = query1.value(12).toBool();
1275
if (query1.value(13).isValid())
1276
chatRoomInfo["Password"] = query1.value(13);
1277
if (query1.value(14).isValid())
1278
chatRoomInfo["PasswordHint"] = query1.value(14);
1279
if (query1.value(15).isValid())
1280
chatRoomInfo["CanUpdateConfiguration"] = query1.value(15).toBool();
1281
if (query1.value(16).isValid())
1282
chatRoomInfo["Subject"] = query1.value(16);
1283
if (query1.value(17).isValid())
1284
chatRoomInfo["Actor"] = query1.value(17);
1285
if (query1.value(18).isValid())
1286
chatRoomInfo["Timestamp"] = toLocalTimeString(query1.value(18).toDateTime());
1287
if (query1.value(19).isValid())
1288
chatRoomInfo["Joined"] = query1.value(19).toBool();
1289
if (query1.value(20).isValid())
1290
chatRoomInfo["SelfRoles"] = query1.value(20).toInt();
1292
thread[History::FieldChatRoomInfo] = chatRoomInfo;
865
1295
case History::EventTypeVoice:
866
thread[History::FieldMissed] = query.value(10);
867
thread[History::FieldDuration] = query.value(9);
868
thread[History::FieldRemoteParticipant] = History::ContactMatcher::instance()->contactInfo(accountId, query.value(11).toString(), true);
1296
thread[History::FieldMissed] = query.value(12);
1297
thread[History::FieldDuration] = query.value(11);
1298
thread[History::FieldRemoteParticipant] = History::ContactMatcher::instance()->contactInfo(accountId, query.value(13).toString(), true);
871
1301
threads << thread;