+QHash<QString, QByteArray> SqliteStorage::bufferCiphers(UserId user, const NetworkId& networkId)
+{
+ QHash<QString, QByteArray> bufferCiphers;
+
+ QSqlDatabase db = logDb();
+ db.transaction();
+ {
+ QSqlQuery query(db);
+ query.prepare(queryString("select_buffer_ciphers"));
+ query.bindValue(":userid", user.toInt());
+ query.bindValue(":networkid", networkId.toInt());
+
+ lockForRead();
+ safeExec(query);
+ watchQuery(query);
+ while (query.next()) {
+ bufferCiphers[query.value(0).toString()] = QByteArray::fromHex(query.value(1).toString().toUtf8());
+ }
+ }
+ unlock();
+ return bufferCiphers;
+}
+
+void SqliteStorage::setBufferCipher(UserId user, const NetworkId& networkId, const QString& bufferName, const QByteArray& cipher)
+{
+ QSqlDatabase db = logDb();
+ db.transaction();
+
+ {
+ QSqlQuery query(db);
+ query.prepare(queryString("update_buffer_cipher"));
+ query.bindValue(":userid", user.toInt());
+ query.bindValue(":networkid", networkId.toInt());
+ query.bindValue(":buffercname", bufferName.toLower());
+ query.bindValue(":cipher", QString(cipher.toHex()));
+
+ lockForWrite();
+ safeExec(query);
+ watchQuery(query);
+ db.commit();
+ }
+ unlock();
+}
+
+void SqliteStorage::setHighlightCount(UserId user, BufferId bufferId, int count)
+{
+ QSqlDatabase db = logDb();
+ db.transaction();
+
+ {
+ QSqlQuery query(db);
+ query.prepare(queryString("update_buffer_highlightcount"));
+ query.bindValue(":userid", user.toInt());
+ query.bindValue(":bufferid", bufferId.toInt());
+ query.bindValue(":highlightcount", count);
+
+ lockForWrite();
+ safeExec(query);
+ watchQuery(query);
+ }
+ db.commit();
+ unlock();
+}
+
+QHash<BufferId, int> SqliteStorage::highlightCounts(UserId user)
+{
+ QHash<BufferId, int> highlightCountHash;
+
+ QSqlDatabase db = logDb();
+ db.transaction();
+
+ bool error = false;
+ {
+ QSqlQuery query(db);
+ query.prepare(queryString("select_buffer_highlightcounts"));
+ query.bindValue(":userid", user.toInt());
+
+ lockForRead();
+ safeExec(query);
+ error = !watchQuery(query);
+ if (!error) {
+ while (query.next()) {
+ highlightCountHash[query.value(0).toInt()] = query.value(1).toInt();
+ }
+ }
+ }
+
+ db.commit();
+ unlock();
+ return highlightCountHash;
+}
+
+int SqliteStorage::highlightCount(BufferId bufferId, MsgId lastSeenMsgId)
+{
+ QSqlDatabase db = logDb();
+ db.transaction();
+
+ int result = 0;
+ {
+ QSqlQuery query(db);
+ query.prepare(queryString("select_buffer_highlightcount"));
+ query.bindValue(":bufferid", bufferId.toInt());
+ query.bindValue(":lastseenmsgid", lastSeenMsgId.toQint64());
+
+ lockForRead();
+ safeExec(query);
+ if (query.first())
+ result = query.value(0).toInt();
+ }
+
+ db.commit();
+ unlock();
+ return result;
+}
+
+bool SqliteStorage::logMessage(Message& msg)
+{
+ QSqlDatabase db = logDb();
+ db.transaction();
+
+ bool error = false;
+ {
+ QSqlQuery logMessageQuery(db);
+ logMessageQuery.prepare(queryString("insert_message"));
+ // As of SQLite schema version 31, timestamps are stored in milliseconds instead of
+ // seconds. This nets us more precision as well as simplifying 64-bit time.
+ logMessageQuery.bindValue(":time", msg.timestamp().toMSecsSinceEpoch());
+ logMessageQuery.bindValue(":bufferid", msg.bufferInfo().bufferId().toInt());
+ logMessageQuery.bindValue(":type", msg.type());
+ logMessageQuery.bindValue(":flags", (int)msg.flags());
+ logMessageQuery.bindValue(":sender", msg.sender());
+ logMessageQuery.bindValue(":realname", msg.realName());
+ logMessageQuery.bindValue(":avatarurl", msg.avatarUrl());
+ logMessageQuery.bindValue(":senderprefixes", msg.senderPrefixes());
+ logMessageQuery.bindValue(":message", msg.contents());
+
+ lockForWrite();
+ safeExec(logMessageQuery);
+
+ if (logMessageQuery.lastError().isValid()) {
+ // constraint violation - must be NOT NULL constraint - probably the sender is missing...
+ if (logMessageQuery.lastError().nativeErrorCode() == QLatin1String{"19"}) {
+ QSqlQuery addSenderQuery(db);
+ addSenderQuery.prepare(queryString("insert_sender"));
+ addSenderQuery.bindValue(":sender", msg.sender());
+ addSenderQuery.bindValue(":realname", msg.realName());
+ addSenderQuery.bindValue(":avatarurl", msg.avatarUrl());
+ safeExec(addSenderQuery);
+ safeExec(logMessageQuery);
+ error = !watchQuery(logMessageQuery);
+ }
+ else {
+ watchQuery(logMessageQuery);
+ }
+ }
+ if (!error) {
+ MsgId msgId = logMessageQuery.lastInsertId().toLongLong();
+ if (msgId.isValid()) {
+ msg.setMsgId(msgId);
+ }
+ else {
+ error = true;
+ }
+ }
+ }
+
+ if (error) {
+ db.rollback();
+ }
+ else {
+ db.commit();
+ }
+
+ unlock();
+ return !error;
+}
+
+bool SqliteStorage::logMessages(MessageList& msgs)
+{
+ QSqlDatabase db = logDb();
+ db.transaction();
+
+ {
+ QSet<SenderData> senders;
+ QSqlQuery addSenderQuery(db);
+ addSenderQuery.prepare(queryString("insert_sender"));
+ lockForWrite();
+ for (int i = 0; i < msgs.count(); i++) {
+ auto& msg = msgs.at(i);
+ SenderData sender = {msg.sender(), msg.realName(), msg.avatarUrl()};
+ if (senders.contains(sender))
+ continue;
+ senders << sender;
+
+ addSenderQuery.bindValue(":sender", sender.sender);
+ addSenderQuery.bindValue(":realname", sender.realname);
+ addSenderQuery.bindValue(":avatarurl", sender.avatarurl);
+ safeExec(addSenderQuery);
+ }
+ }
+
+ bool error = false;
+ {
+ QSqlQuery logMessageQuery(db);
+ logMessageQuery.prepare(queryString("insert_message"));
+ for (int i = 0; i < msgs.count(); i++) {
+ Message& msg = msgs[i];
+ // As of SQLite schema version 31, timestamps are stored in milliseconds instead of
+ // seconds. This nets us more precision as well as simplifying 64-bit time.
+ logMessageQuery.bindValue(":time", msg.timestamp().toMSecsSinceEpoch());
+ logMessageQuery.bindValue(":bufferid", msg.bufferInfo().bufferId().toInt());
+ logMessageQuery.bindValue(":type", msg.type());
+ logMessageQuery.bindValue(":flags", (int)msg.flags());
+ logMessageQuery.bindValue(":sender", msg.sender());
+ logMessageQuery.bindValue(":realname", msg.realName());
+ logMessageQuery.bindValue(":avatarurl", msg.avatarUrl());
+ logMessageQuery.bindValue(":senderprefixes", msg.senderPrefixes());
+ logMessageQuery.bindValue(":message", msg.contents());