1 /***************************************************************************
2 * Copyright (C) 2005-2018 by the Quassel Project *
3 * devel@quassel-irc.org *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) version 3. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
21 #include "sqlitestorage.h"
25 #include "logmessage.h"
29 int SqliteStorage::_maxRetryCount = 150;
31 SqliteStorage::SqliteStorage(QObject *parent)
32 : AbstractSqlStorage(parent)
37 bool SqliteStorage::isAvailable() const
39 if (!QSqlDatabase::isDriverAvailable("QSQLITE")) return false;
44 QString SqliteStorage::backendId() const
46 return QString("SQLite");
50 QString SqliteStorage::displayName() const
52 // Note: Pre-0.13 clients use the displayName property for backend idenfication
53 // We identify the backend to use for the monolithic core by its displayname.
54 // so only change this string if you _really_ have to and make sure the core
55 // setup for the mono client still works ;)
60 QString SqliteStorage::description() const
62 return tr("SQLite is a file-based database engine that does not require any setup. It is suitable for small and medium-sized "
63 "databases that do not require access via network. Use SQLite if your Quassel Core should store its data on the same machine "
64 "it is running on, and if you only expect a few users to use your core.");
68 int SqliteStorage::installedSchemaVersion()
70 // only used when there is a singlethread (during startup)
71 // so we don't need locking here
72 QSqlQuery query = logDb().exec("SELECT value FROM coreinfo WHERE key = 'schemaversion'");
74 return query.value(0).toInt();
76 // maybe it's really old... (schema version 0)
77 query = logDb().exec("SELECT MAX(version) FROM coreinfo");
79 return query.value(0).toInt();
81 return AbstractSqlStorage::installedSchemaVersion();
85 bool SqliteStorage::updateSchemaVersion(int newVersion)
87 // only used when there is a singlethread (during startup)
88 // so we don't need locking here
89 QSqlQuery query(logDb());
90 query.prepare("UPDATE coreinfo SET value = :version WHERE key = 'schemaversion'");
91 query.bindValue(":version", newVersion);
95 if (query.lastError().isValid()) {
96 qCritical() << "SqliteStorage::updateSchemaVersion(int): Updating schema version failed!";
103 bool SqliteStorage::setupSchemaVersion(int version)
105 // only used when there is a singlethread (during startup)
106 // so we don't need locking here
107 QSqlQuery query(logDb());
108 query.prepare("INSERT INTO coreinfo (key, value) VALUES ('schemaversion', :version)");
109 query.bindValue(":version", version);
113 if (query.lastError().isValid()) {
114 qCritical() << "SqliteStorage::setupSchemaVersion(int): Updating schema version failed!";
121 UserId SqliteStorage::addUser(const QString &user, const QString &password, const QString &authenticator)
123 QSqlDatabase db = logDb();
127 // this scope ensures that the query is freed in sqlite before we call unlock()
128 // this ensures that our thread doesn't hold a internal after unlock is called
129 // (see sqlites doc on implicit locking for details)
132 query.prepare(queryString("insert_quasseluser"));
133 query.bindValue(":username", user);
134 query.bindValue(":password", hashPassword(password));
135 query.bindValue(":hashversion", Storage::HashVersion::Latest);
136 query.bindValue(":authenticator", authenticator);
139 if (query.lastError().isValid() && query.lastError().number() == 19) { // user already exists - sadly 19 seems to be the general constraint violation error...
143 uid = query.lastInsertId().toInt();
150 emit userAdded(uid, user);
155 bool SqliteStorage::updateUser(UserId user, const QString &password)
157 QSqlDatabase db = logDb();
158 bool success = false;
163 query.prepare(queryString("update_userpassword"));
164 query.bindValue(":userid", user.toInt());
165 query.bindValue(":password", hashPassword(password));
166 query.bindValue(":hashversion", Storage::HashVersion::Latest);
169 success = query.numRowsAffected() != 0;
177 void SqliteStorage::renameUser(UserId user, const QString &newName)
179 QSqlDatabase db = logDb();
183 query.prepare(queryString("update_username"));
184 query.bindValue(":userid", user.toInt());
185 query.bindValue(":username", newName);
191 emit userRenamed(user, newName);
195 UserId SqliteStorage::validateUser(const QString &user, const QString &password)
198 QString hashedPassword;
199 Storage::HashVersion hashVersion = Storage::HashVersion::Latest;
202 QSqlQuery query(logDb());
203 query.prepare(queryString("select_authuser"));
204 query.bindValue(":username", user);
210 userId = query.value(0).toInt();
211 hashedPassword = query.value(1).toString();
212 hashVersion = static_cast<Storage::HashVersion>(query.value(2).toInt());
218 if (userId != 0 && checkHashedPassword(userId, password, hashedPassword, hashVersion)) {
219 returnUserId = userId;
225 UserId SqliteStorage::getUserId(const QString &username)
230 QSqlQuery query(logDb());
231 query.prepare(queryString("select_userid"));
232 query.bindValue(":username", username);
238 userId = query.value(0).toInt();
246 QString SqliteStorage::getUserAuthenticator(const UserId userid)
248 QString authenticator = QString("");
251 QSqlQuery query(logDb());
252 query.prepare(queryString("select_authenticator"));
253 query.bindValue(":userid", userid.toInt());
259 authenticator = query.value(0).toString();
264 return authenticator;
267 UserId SqliteStorage::internalUser()
272 QSqlQuery query(logDb());
273 query.prepare(queryString("select_internaluser"));
278 userId = query.value(0).toInt();
287 void SqliteStorage::delUser(UserId user)
289 QSqlDatabase db = logDb();
295 query.prepare(queryString("delete_backlog_by_uid"));
296 query.bindValue(":userid", user.toInt());
299 query.prepare(queryString("delete_buffers_by_uid"));
300 query.bindValue(":userid", user.toInt());
303 query.prepare(queryString("delete_networks_by_uid"));
304 query.bindValue(":userid", user.toInt());
307 query.prepare(queryString("delete_quasseluser"));
308 query.bindValue(":userid", user.toInt());
310 // I hate the lack of foreign keys and on delete cascade... :(
315 emit userRemoved(user);
319 void SqliteStorage::setUserSetting(UserId userId, const QString &settingName, const QVariant &data)
322 QDataStream out(&rawData, QIODevice::WriteOnly);
323 out.setVersion(QDataStream::Qt_4_2);
326 QSqlDatabase db = logDb();
330 query.prepare(queryString("insert_user_setting"));
331 query.bindValue(":userid", userId.toInt());
332 query.bindValue(":settingname", settingName);
333 query.bindValue(":settingvalue", rawData);
337 if (query.lastError().isValid()) {
338 QSqlQuery updateQuery(db);
339 updateQuery.prepare(queryString("update_user_setting"));
340 updateQuery.bindValue(":userid", userId.toInt());
341 updateQuery.bindValue(":settingname", settingName);
342 updateQuery.bindValue(":settingvalue", rawData);
343 safeExec(updateQuery);
351 QVariant SqliteStorage::getUserSetting(UserId userId, const QString &settingName, const QVariant &defaultData)
353 QVariant data = defaultData;
355 QSqlQuery query(logDb());
356 query.prepare(queryString("select_user_setting"));
357 query.bindValue(":userid", userId.toInt());
358 query.bindValue(":settingname", settingName);
363 QByteArray rawData = query.value(0).toByteArray();
364 QDataStream in(&rawData, QIODevice::ReadOnly);
365 in.setVersion(QDataStream::Qt_4_2);
374 void SqliteStorage::setCoreState(const QVariantList &data)
377 QDataStream out(&rawData, QIODevice::WriteOnly);
378 out.setVersion(QDataStream::Qt_4_2);
381 QSqlDatabase db = logDb();
385 query.prepare(queryString("insert_core_state"));
386 query.bindValue(":key", "active_sessions");
387 query.bindValue(":value", rawData);
391 if (query.lastError().isValid()) {
392 QSqlQuery updateQuery(db);
393 updateQuery.prepare(queryString("update_core_state"));
394 updateQuery.bindValue(":key", "active_sessions");
395 updateQuery.bindValue(":value", rawData);
396 safeExec(updateQuery);
404 QVariantList SqliteStorage::getCoreState(const QVariantList &defaultData)
408 QSqlQuery query(logDb());
409 query.prepare(queryString("select_core_state"));
410 query.bindValue(":key", "active_sessions");
415 QByteArray rawData = query.value(0).toByteArray();
416 QDataStream in(&rawData, QIODevice::ReadOnly);
417 in.setVersion(QDataStream::Qt_4_2);
428 IdentityId SqliteStorage::createIdentity(UserId user, CoreIdentity &identity)
430 IdentityId identityId;
432 QSqlDatabase db = logDb();
437 query.prepare(queryString("insert_identity"));
438 query.bindValue(":userid", user.toInt());
439 query.bindValue(":identityname", identity.identityName());
440 query.bindValue(":realname", identity.realName());
441 query.bindValue(":awaynick", identity.awayNick());
442 query.bindValue(":awaynickenabled", identity.awayNickEnabled() ? 1 : 0);
443 query.bindValue(":awayreason", identity.awayReason());
444 query.bindValue(":awayreasonenabled", identity.awayReasonEnabled() ? 1 : 0);
445 query.bindValue(":autoawayenabled", identity.awayReasonEnabled() ? 1 : 0);
446 query.bindValue(":autoawaytime", identity.autoAwayTime());
447 query.bindValue(":autoawayreason", identity.autoAwayReason());
448 query.bindValue(":autoawayreasonenabled", identity.autoAwayReasonEnabled() ? 1 : 0);
449 query.bindValue(":detachawayenabled", identity.detachAwayEnabled() ? 1 : 0);
450 query.bindValue(":detachawayreason", identity.detachAwayReason());
451 query.bindValue(":detachawayreasonenabled", identity.detachAwayReasonEnabled() ? 1 : 0);
452 query.bindValue(":ident", identity.ident());
453 query.bindValue(":kickreason", identity.kickReason());
454 query.bindValue(":partreason", identity.partReason());
455 query.bindValue(":quitreason", identity.quitReason());
457 query.bindValue(":sslcert", identity.sslCert().toPem());
458 query.bindValue(":sslkey", identity.sslKey().toPem());
460 query.bindValue(":sslcert", QByteArray());
461 query.bindValue(":sslkey", QByteArray());
467 identityId = query.lastInsertId().toInt();
468 if (!identityId.isValid()) {
472 QSqlQuery deleteNickQuery(db);
473 deleteNickQuery.prepare(queryString("delete_nicks"));
474 deleteNickQuery.bindValue(":identityid", identityId.toInt());
475 safeExec(deleteNickQuery);
477 QSqlQuery insertNickQuery(db);
478 insertNickQuery.prepare(queryString("insert_nick"));
479 foreach(QString nick, identity.nicks()) {
480 insertNickQuery.bindValue(":identityid", identityId.toInt());
481 insertNickQuery.bindValue(":nick", nick);
482 safeExec(insertNickQuery);
488 identity.setId(identityId);
493 bool SqliteStorage::updateIdentity(UserId user, const CoreIdentity &identity)
495 QSqlDatabase db = logDb();
500 QSqlQuery checkQuery(db);
501 checkQuery.prepare(queryString("select_checkidentity"));
502 checkQuery.bindValue(":identityid", identity.id().toInt());
503 checkQuery.bindValue(":userid", user.toInt());
505 safeExec(checkQuery);
507 // there should be exactly one identity for the given id and user
508 error = (!checkQuery.first() || checkQuery.value(0).toInt() != 1);
517 query.prepare(queryString("update_identity"));
518 query.bindValue(":identityname", identity.identityName());
519 query.bindValue(":realname", identity.realName());
520 query.bindValue(":awaynick", identity.awayNick());
521 query.bindValue(":awaynickenabled", identity.awayNickEnabled() ? 1 : 0);
522 query.bindValue(":awayreason", identity.awayReason());
523 query.bindValue(":awayreasonenabled", identity.awayReasonEnabled() ? 1 : 0);
524 query.bindValue(":autoawayenabled", identity.awayReasonEnabled() ? 1 : 0);
525 query.bindValue(":autoawaytime", identity.autoAwayTime());
526 query.bindValue(":autoawayreason", identity.autoAwayReason());
527 query.bindValue(":autoawayreasonenabled", identity.autoAwayReasonEnabled() ? 1 : 0);
528 query.bindValue(":detachawayenabled", identity.detachAwayEnabled() ? 1 : 0);
529 query.bindValue(":detachawayreason", identity.detachAwayReason());
530 query.bindValue(":detachawayreasonenabled", identity.detachAwayReasonEnabled() ? 1 : 0);
531 query.bindValue(":ident", identity.ident());
532 query.bindValue(":kickreason", identity.kickReason());
533 query.bindValue(":partreason", identity.partReason());
534 query.bindValue(":quitreason", identity.quitReason());
536 query.bindValue(":sslcert", identity.sslCert().toPem());
537 query.bindValue(":sslkey", identity.sslKey().toPem());
539 query.bindValue(":sslcert", QByteArray());
540 query.bindValue(":sslkey", QByteArray());
542 query.bindValue(":identityid", identity.id().toInt());
546 QSqlQuery deleteNickQuery(db);
547 deleteNickQuery.prepare(queryString("delete_nicks"));
548 deleteNickQuery.bindValue(":identityid", identity.id().toInt());
549 safeExec(deleteNickQuery);
550 watchQuery(deleteNickQuery);
552 QSqlQuery insertNickQuery(db);
553 insertNickQuery.prepare(queryString("insert_nick"));
554 foreach(QString nick, identity.nicks()) {
555 insertNickQuery.bindValue(":identityid", identity.id().toInt());
556 insertNickQuery.bindValue(":nick", nick);
557 safeExec(insertNickQuery);
558 watchQuery(insertNickQuery);
567 void SqliteStorage::removeIdentity(UserId user, IdentityId identityId)
569 QSqlDatabase db = logDb();
574 QSqlQuery checkQuery(db);
575 checkQuery.prepare(queryString("select_checkidentity"));
576 checkQuery.bindValue(":identityid", identityId.toInt());
577 checkQuery.bindValue(":userid", user.toInt());
579 safeExec(checkQuery);
581 // there should be exactly one identity for the given id and user
582 error = (!checkQuery.first() || checkQuery.value(0).toInt() != 1);
590 QSqlQuery deleteNickQuery(db);
591 deleteNickQuery.prepare(queryString("delete_nicks"));
592 deleteNickQuery.bindValue(":identityid", identityId.toInt());
593 safeExec(deleteNickQuery);
595 QSqlQuery deleteIdentityQuery(db);
596 deleteIdentityQuery.prepare(queryString("delete_identity"));
597 deleteIdentityQuery.bindValue(":identityid", identityId.toInt());
598 deleteIdentityQuery.bindValue(":userid", user.toInt());
599 safeExec(deleteIdentityQuery);
606 QList<CoreIdentity> SqliteStorage::identities(UserId user)
608 QList<CoreIdentity> identities;
609 QSqlDatabase db = logDb();
614 query.prepare(queryString("select_identities"));
615 query.bindValue(":userid", user.toInt());
617 QSqlQuery nickQuery(db);
618 nickQuery.prepare(queryString("select_nicks"));
623 while (query.next()) {
624 CoreIdentity identity(IdentityId(query.value(0).toInt()));
626 identity.setIdentityName(query.value(1).toString());
627 identity.setRealName(query.value(2).toString());
628 identity.setAwayNick(query.value(3).toString());
629 identity.setAwayNickEnabled(!!query.value(4).toInt());
630 identity.setAwayReason(query.value(5).toString());
631 identity.setAwayReasonEnabled(!!query.value(6).toInt());
632 identity.setAutoAwayEnabled(!!query.value(7).toInt());
633 identity.setAutoAwayTime(query.value(8).toInt());
634 identity.setAutoAwayReason(query.value(9).toString());
635 identity.setAutoAwayReasonEnabled(!!query.value(10).toInt());
636 identity.setDetachAwayEnabled(!!query.value(11).toInt());
637 identity.setDetachAwayReason(query.value(12).toString());
638 identity.setDetachAwayReasonEnabled(!!query.value(13).toInt());
639 identity.setIdent(query.value(14).toString());
640 identity.setKickReason(query.value(15).toString());
641 identity.setPartReason(query.value(16).toString());
642 identity.setQuitReason(query.value(17).toString());
644 identity.setSslCert(query.value(18).toByteArray());
645 identity.setSslKey(query.value(19).toByteArray());
648 nickQuery.bindValue(":identityid", identity.id().toInt());
649 QList<QString> nicks;
651 watchQuery(nickQuery);
652 while (nickQuery.next()) {
653 nicks << nickQuery.value(0).toString();
655 identity.setNicks(nicks);
656 identities << identity;
665 NetworkId SqliteStorage::createNetwork(UserId user, const NetworkInfo &info)
669 QSqlDatabase db = logDb();
675 query.prepare(queryString("insert_network"));
676 query.bindValue(":userid", user.toInt());
677 bindNetworkInfo(query, info);
680 if (!watchQuery(query)) {
685 networkId = query.lastInsertId().toInt();
694 QSqlQuery insertServersQuery(db);
695 insertServersQuery.prepare(queryString("insert_server"));
696 foreach(Network::Server server, info.serverList) {
697 insertServersQuery.bindValue(":userid", user.toInt());
698 insertServersQuery.bindValue(":networkid", networkId.toInt());
699 bindServerInfo(insertServersQuery, server);
700 safeExec(insertServersQuery);
701 if (!watchQuery(insertServersQuery)) {
718 void SqliteStorage::bindNetworkInfo(QSqlQuery &query, const NetworkInfo &info)
720 query.bindValue(":networkname", info.networkName);
721 query.bindValue(":identityid", info.identity.toInt());
722 query.bindValue(":encodingcodec", QString(info.codecForEncoding));
723 query.bindValue(":decodingcodec", QString(info.codecForDecoding));
724 query.bindValue(":servercodec", QString(info.codecForServer));
725 query.bindValue(":userandomserver", info.useRandomServer ? 1 : 0);
726 query.bindValue(":perform", info.perform.join("\n"));
727 query.bindValue(":useautoidentify", info.useAutoIdentify ? 1 : 0);
728 query.bindValue(":autoidentifyservice", info.autoIdentifyService);
729 query.bindValue(":autoidentifypassword", info.autoIdentifyPassword);
730 query.bindValue(":usesasl", info.useSasl ? 1 : 0);
731 query.bindValue(":saslaccount", info.saslAccount);
732 query.bindValue(":saslpassword", info.saslPassword);
733 query.bindValue(":useautoreconnect", info.useAutoReconnect ? 1 : 0);
734 query.bindValue(":autoreconnectinterval", info.autoReconnectInterval);
735 query.bindValue(":autoreconnectretries", info.autoReconnectRetries);
736 query.bindValue(":unlimitedconnectretries", info.unlimitedReconnectRetries ? 1 : 0);
737 query.bindValue(":rejoinchannels", info.rejoinChannels ? 1 : 0);
738 // Custom rate limiting
739 query.bindValue(":usecustomessagerate", info.useCustomMessageRate ? 1 : 0);
740 query.bindValue(":messagerateburstsize", info.messageRateBurstSize);
741 query.bindValue(":messageratedelay", info.messageRateDelay);
742 query.bindValue(":unlimitedmessagerate", info.unlimitedMessageRate ? 1 : 0);
743 if (info.networkId.isValid())
744 query.bindValue(":networkid", info.networkId.toInt());
748 void SqliteStorage::bindServerInfo(QSqlQuery &query, const Network::Server &server)
750 query.bindValue(":hostname", server.host);
751 query.bindValue(":port", server.port);
752 query.bindValue(":password", server.password);
753 query.bindValue(":ssl", server.useSsl ? 1 : 0);
754 query.bindValue(":sslversion", server.sslVersion);
755 query.bindValue(":useproxy", server.useProxy ? 1 : 0);
756 query.bindValue(":proxytype", server.proxyType);
757 query.bindValue(":proxyhost", server.proxyHost);
758 query.bindValue(":proxyport", server.proxyPort);
759 query.bindValue(":proxyuser", server.proxyUser);
760 query.bindValue(":proxypass", server.proxyPass);
761 query.bindValue(":sslverify", server.sslVerify ? 1 : 0);
765 bool SqliteStorage::updateNetwork(UserId user, const NetworkInfo &info)
767 QSqlDatabase db = logDb();
772 QSqlQuery updateQuery(db);
773 updateQuery.prepare(queryString("update_network"));
774 updateQuery.bindValue(":userid", user.toInt());
775 bindNetworkInfo(updateQuery, info);
778 safeExec(updateQuery);
779 if (!watchQuery(updateQuery) || updateQuery.numRowsAffected() != 1) {
790 QSqlQuery dropServersQuery(db);
791 dropServersQuery.prepare("DELETE FROM ircserver WHERE networkid = :networkid");
792 dropServersQuery.bindValue(":networkid", info.networkId.toInt());
793 safeExec(dropServersQuery);
794 if (!watchQuery(dropServersQuery)) {
805 QSqlQuery insertServersQuery(db);
806 insertServersQuery.prepare(queryString("insert_server"));
807 foreach(Network::Server server, info.serverList) {
808 insertServersQuery.bindValue(":userid", user.toInt());
809 insertServersQuery.bindValue(":networkid", info.networkId.toInt());
810 bindServerInfo(insertServersQuery, server);
811 safeExec(insertServersQuery);
812 if (!watchQuery(insertServersQuery)) {
826 bool SqliteStorage::removeNetwork(UserId user, const NetworkId &networkId)
828 QSqlDatabase db = logDb();
833 QSqlQuery deleteNetworkQuery(db);
834 deleteNetworkQuery.prepare(queryString("delete_network"));
835 deleteNetworkQuery.bindValue(":networkid", networkId.toInt());
836 deleteNetworkQuery.bindValue(":userid", user.toInt());
838 safeExec(deleteNetworkQuery);
839 if (!watchQuery(deleteNetworkQuery) || deleteNetworkQuery.numRowsAffected() != 1) {
850 QSqlQuery deleteBacklogQuery(db);
851 deleteBacklogQuery.prepare(queryString("delete_backlog_for_network"));
852 deleteBacklogQuery.bindValue(":networkid", networkId.toInt());
853 safeExec(deleteBacklogQuery);
854 if (!watchQuery(deleteBacklogQuery)) {
865 QSqlQuery deleteBuffersQuery(db);
866 deleteBuffersQuery.prepare(queryString("delete_buffers_for_network"));
867 deleteBuffersQuery.bindValue(":networkid", networkId.toInt());
868 safeExec(deleteBuffersQuery);
869 if (!watchQuery(deleteBuffersQuery)) {
880 QSqlQuery deleteServersQuery(db);
881 deleteServersQuery.prepare(queryString("delete_ircservers_for_network"));
882 deleteServersQuery.bindValue(":networkid", networkId.toInt());
883 safeExec(deleteServersQuery);
884 if (!watchQuery(deleteServersQuery)) {
900 QList<NetworkInfo> SqliteStorage::networks(UserId user)
902 QList<NetworkInfo> nets;
904 QSqlDatabase db = logDb();
908 QSqlQuery networksQuery(db);
909 networksQuery.prepare(queryString("select_networks_for_user"));
910 networksQuery.bindValue(":userid", user.toInt());
912 QSqlQuery serversQuery(db);
913 serversQuery.prepare(queryString("select_servers_for_network"));
916 safeExec(networksQuery);
917 if (watchQuery(networksQuery)) {
918 while (networksQuery.next()) {
920 net.networkId = networksQuery.value(0).toInt();
921 net.networkName = networksQuery.value(1).toString();
922 net.identity = networksQuery.value(2).toInt();
923 net.codecForServer = networksQuery.value(3).toString().toLatin1();
924 net.codecForEncoding = networksQuery.value(4).toString().toLatin1();
925 net.codecForDecoding = networksQuery.value(5).toString().toLatin1();
926 net.useRandomServer = networksQuery.value(6).toInt() == 1 ? true : false;
927 net.perform = networksQuery.value(7).toString().split("\n");
928 net.useAutoIdentify = networksQuery.value(8).toInt() == 1 ? true : false;
929 net.autoIdentifyService = networksQuery.value(9).toString();
930 net.autoIdentifyPassword = networksQuery.value(10).toString();
931 net.useAutoReconnect = networksQuery.value(11).toInt() == 1 ? true : false;
932 net.autoReconnectInterval = networksQuery.value(12).toUInt();
933 net.autoReconnectRetries = networksQuery.value(13).toInt();
934 net.unlimitedReconnectRetries = networksQuery.value(14).toInt() == 1 ? true : false;
935 net.rejoinChannels = networksQuery.value(15).toInt() == 1 ? true : false;
936 net.useSasl = networksQuery.value(16).toInt() == 1 ? true : false;
937 net.saslAccount = networksQuery.value(17).toString();
938 net.saslPassword = networksQuery.value(18).toString();
939 // Custom rate limiting
940 net.useCustomMessageRate = networksQuery.value(19).toInt() == 1 ? true : false;
941 net.messageRateBurstSize = networksQuery.value(20).toUInt();
942 net.messageRateDelay = networksQuery.value(21).toUInt();
943 net.unlimitedMessageRate = networksQuery.value(22).toInt() == 1 ? true : false;
945 serversQuery.bindValue(":networkid", net.networkId.toInt());
946 safeExec(serversQuery);
947 if (!watchQuery(serversQuery)) {
952 Network::ServerList servers;
953 while (serversQuery.next()) {
954 Network::Server server;
955 server.host = serversQuery.value(0).toString();
956 server.port = serversQuery.value(1).toUInt();
957 server.password = serversQuery.value(2).toString();
958 server.useSsl = serversQuery.value(3).toInt() == 1 ? true : false;
959 server.sslVersion = serversQuery.value(4).toInt();
960 server.useProxy = serversQuery.value(5).toInt() == 1 ? true : false;
961 server.proxyType = serversQuery.value(6).toInt();
962 server.proxyHost = serversQuery.value(7).toString();
963 server.proxyPort = serversQuery.value(8).toUInt();
964 server.proxyUser = serversQuery.value(9).toString();
965 server.proxyPass = serversQuery.value(10).toString();
966 server.sslVerify = serversQuery.value(11).toInt() == 1 ? true : false;
969 net.serverList = servers;
981 QList<NetworkId> SqliteStorage::connectedNetworks(UserId user)
983 QList<NetworkId> connectedNets;
985 QSqlDatabase db = logDb();
990 query.prepare(queryString("select_connected_networks"));
991 query.bindValue(":userid", user.toInt());
996 while (query.next()) {
997 connectedNets << query.value(0).toInt();
1002 return connectedNets;
1006 void SqliteStorage::setNetworkConnected(UserId user, const NetworkId &networkId, bool isConnected)
1008 QSqlDatabase db = logDb();
1012 QSqlQuery query(db);
1013 query.prepare(queryString("update_network_connected"));
1014 query.bindValue(":userid", user.toInt());
1015 query.bindValue(":networkid", networkId.toInt());
1016 query.bindValue(":connected", isConnected ? 1 : 0);
1027 QHash<QString, QString> SqliteStorage::persistentChannels(UserId user, const NetworkId &networkId)
1029 QHash<QString, QString> persistentChans;
1031 QSqlDatabase db = logDb();
1034 QSqlQuery query(db);
1035 query.prepare(queryString("select_persistent_channels"));
1036 query.bindValue(":userid", user.toInt());
1037 query.bindValue(":networkid", networkId.toInt());
1042 while (query.next()) {
1043 persistentChans[query.value(0).toString()] = query.value(1).toString();
1047 return persistentChans;
1051 void SqliteStorage::setChannelPersistent(UserId user, const NetworkId &networkId, const QString &channel, bool isJoined)
1053 QSqlDatabase db = logDb();
1057 QSqlQuery query(db);
1058 query.prepare(queryString("update_buffer_persistent_channel"));
1059 query.bindValue(":userid", user.toInt());
1060 query.bindValue(":networkid", networkId.toInt());
1061 query.bindValue(":buffercname", channel.toLower());
1062 query.bindValue(":joined", isJoined ? 1 : 0);
1073 void SqliteStorage::setPersistentChannelKey(UserId user, const NetworkId &networkId, const QString &channel, const QString &key)
1075 QSqlDatabase db = logDb();
1079 QSqlQuery query(db);
1080 query.prepare(queryString("update_buffer_set_channel_key"));
1081 query.bindValue(":userid", user.toInt());
1082 query.bindValue(":networkid", networkId.toInt());
1083 query.bindValue(":buffercname", channel.toLower());
1084 query.bindValue(":key", key);
1095 QString SqliteStorage::awayMessage(UserId user, NetworkId networkId)
1097 QSqlDatabase db = logDb();
1102 QSqlQuery query(db);
1103 query.prepare(queryString("select_network_awaymsg"));
1104 query.bindValue(":userid", user.toInt());
1105 query.bindValue(":networkid", networkId.toInt());
1111 awayMsg = query.value(0).toString();
1120 void SqliteStorage::setAwayMessage(UserId user, NetworkId networkId, const QString &awayMsg)
1122 QSqlDatabase db = logDb();
1126 QSqlQuery query(db);
1127 query.prepare(queryString("update_network_set_awaymsg"));
1128 query.bindValue(":userid", user.toInt());
1129 query.bindValue(":networkid", networkId.toInt());
1130 query.bindValue(":awaymsg", awayMsg);
1141 QString SqliteStorage::userModes(UserId user, NetworkId networkId)
1143 QSqlDatabase db = logDb();
1148 QSqlQuery query(db);
1149 query.prepare(queryString("select_network_usermode"));
1150 query.bindValue(":userid", user.toInt());
1151 query.bindValue(":networkid", networkId.toInt());
1157 modes = query.value(0).toString();
1166 void SqliteStorage::setUserModes(UserId user, NetworkId networkId, const QString &userModes)
1168 QSqlDatabase db = logDb();
1172 QSqlQuery query(db);
1173 query.prepare(queryString("update_network_set_usermode"));
1174 query.bindValue(":userid", user.toInt());
1175 query.bindValue(":networkid", networkId.toInt());
1176 query.bindValue(":usermode", userModes);
1187 BufferInfo SqliteStorage::bufferInfo(UserId user, const NetworkId &networkId, BufferInfo::Type type, const QString &buffer, bool create)
1189 QSqlDatabase db = logDb();
1192 BufferInfo bufferInfo;
1194 QSqlQuery query(db);
1195 query.prepare(queryString("select_bufferByName"));
1196 query.bindValue(":networkid", networkId.toInt());
1197 query.bindValue(":userid", user.toInt());
1198 query.bindValue(":buffercname", buffer.toLower());
1203 if (query.first()) {
1204 bufferInfo = BufferInfo(query.value(0).toInt(), networkId, (BufferInfo::Type)query.value(1).toInt(), 0, buffer);
1206 qCritical() << "SqliteStorage::getBufferInfo(): received more then one Buffer!";
1207 qCritical() << " Query:" << query.lastQuery();
1208 qCritical() << " bound Values:";
1209 QList<QVariant> list = query.boundValues().values();
1210 for (int i = 0; i < list.size(); ++i)
1211 qCritical() << i << ":" << list.at(i).toString().toLatin1().data();
1216 // let's create the buffer
1217 QSqlQuery createQuery(db);
1218 createQuery.prepare(queryString("insert_buffer"));
1219 createQuery.bindValue(":userid", user.toInt());
1220 createQuery.bindValue(":networkid", networkId.toInt());
1221 createQuery.bindValue(":buffertype", (int)type);
1222 createQuery.bindValue(":buffername", buffer);
1223 createQuery.bindValue(":buffercname", buffer.toLower());
1224 createQuery.bindValue(":joined", type & BufferInfo::ChannelBuffer ? 1 : 0);
1228 safeExec(createQuery);
1229 watchQuery(createQuery);
1230 bufferInfo = BufferInfo(createQuery.lastInsertId().toInt(), networkId, type, 0, buffer);
1239 BufferInfo SqliteStorage::getBufferInfo(UserId user, const BufferId &bufferId)
1241 QSqlDatabase db = logDb();
1244 BufferInfo bufferInfo;
1246 QSqlQuery query(db);
1247 query.prepare(queryString("select_buffer_by_id"));
1248 query.bindValue(":userid", user.toInt());
1249 query.bindValue(":bufferid", bufferId.toInt());
1254 if (watchQuery(query) && query.first()) {
1255 bufferInfo = BufferInfo(query.value(0).toInt(), query.value(1).toInt(), (BufferInfo::Type)query.value(2).toInt(), 0, query.value(4).toString());
1256 Q_ASSERT(!query.next());
1265 QList<BufferInfo> SqliteStorage::requestBuffers(UserId user)
1267 QList<BufferInfo> bufferlist;
1269 QSqlDatabase db = logDb();
1273 QSqlQuery query(db);
1274 query.prepare(queryString("select_buffers"));
1275 query.bindValue(":userid", user.toInt());
1280 while (query.next()) {
1281 bufferlist << BufferInfo(query.value(0).toInt(), query.value(1).toInt(), (BufferInfo::Type)query.value(2).toInt(), query.value(3).toInt(), query.value(4).toString());
1291 QList<BufferId> SqliteStorage::requestBufferIdsForNetwork(UserId user, NetworkId networkId)
1293 QList<BufferId> bufferList;
1295 QSqlDatabase db = logDb();
1299 QSqlQuery query(db);
1300 query.prepare(queryString("select_buffers_for_network"));
1301 query.bindValue(":networkid", networkId.toInt());
1302 query.bindValue(":userid", user.toInt());
1307 while (query.next()) {
1308 bufferList << BufferId(query.value(0).toInt());
1318 bool SqliteStorage::removeBuffer(const UserId &user, const BufferId &bufferId)
1320 QSqlDatabase db = logDb();
1325 QSqlQuery delBufferQuery(db);
1326 delBufferQuery.prepare(queryString("delete_buffer_for_bufferid"));
1327 delBufferQuery.bindValue(":bufferid", bufferId.toInt());
1328 delBufferQuery.bindValue(":userid", user.toInt());
1331 safeExec(delBufferQuery);
1333 error = (!watchQuery(delBufferQuery) || delBufferQuery.numRowsAffected() != 1);
1343 QSqlQuery delBacklogQuery(db);
1344 delBacklogQuery.prepare(queryString("delete_backlog_for_buffer"));
1345 delBacklogQuery.bindValue(":bufferid", bufferId.toInt());
1347 safeExec(delBacklogQuery);
1348 error = !watchQuery(delBacklogQuery);
1362 bool SqliteStorage::renameBuffer(const UserId &user, const BufferId &bufferId, const QString &newName)
1364 QSqlDatabase db = logDb();
1369 QSqlQuery query(db);
1370 query.prepare(queryString("update_buffer_name"));
1371 query.bindValue(":buffername", newName);
1372 query.bindValue(":buffercname", newName.toLower());
1373 query.bindValue(":bufferid", bufferId.toInt());
1374 query.bindValue(":userid", user.toInt());
1379 error = query.lastError().isValid();
1380 // unexepcted error occured (19 == constraint violation)
1381 if (error && query.lastError().number() != 19) {
1385 error |= (query.numRowsAffected() != 1);
1399 bool SqliteStorage::mergeBuffersPermanently(const UserId &user, const BufferId &bufferId1, const BufferId &bufferId2)
1401 QSqlDatabase db = logDb();
1406 QSqlQuery checkQuery(db);
1407 checkQuery.prepare(queryString("select_buffers_for_merge"));
1408 checkQuery.bindValue(":oldbufferid", bufferId2.toInt());
1409 checkQuery.bindValue(":newbufferid", bufferId1.toInt());
1410 checkQuery.bindValue(":userid", user.toInt());
1413 safeExec(checkQuery);
1414 error = (!checkQuery.first() || checkQuery.value(0).toInt() != 2);
1423 QSqlQuery query(db);
1424 query.prepare(queryString("update_backlog_bufferid"));
1425 query.bindValue(":oldbufferid", bufferId2.toInt());
1426 query.bindValue(":newbufferid", bufferId1.toInt());
1428 error = !watchQuery(query);
1437 QSqlQuery delBufferQuery(db);
1438 delBufferQuery.prepare(queryString("delete_buffer_for_bufferid"));
1439 delBufferQuery.bindValue(":bufferid", bufferId2.toInt());
1440 delBufferQuery.bindValue(":userid", user.toInt());
1441 safeExec(delBufferQuery);
1442 error = !watchQuery(delBufferQuery);
1456 void SqliteStorage::setBufferLastSeenMsg(UserId user, const BufferId &bufferId, const MsgId &msgId)
1458 QSqlDatabase db = logDb();
1462 QSqlQuery query(db);
1463 query.prepare(queryString("update_buffer_lastseen"));
1464 query.bindValue(":userid", user.toInt());
1465 query.bindValue(":bufferid", bufferId.toInt());
1466 query.bindValue(":lastseenmsgid", msgId.toQint64());
1477 QHash<BufferId, MsgId> SqliteStorage::bufferLastSeenMsgIds(UserId user)
1479 QHash<BufferId, MsgId> lastSeenHash;
1481 QSqlDatabase db = logDb();
1486 QSqlQuery query(db);
1487 query.prepare(queryString("select_buffer_lastseen_messages"));
1488 query.bindValue(":userid", user.toInt());
1492 error = !watchQuery(query);
1494 while (query.next()) {
1495 lastSeenHash[query.value(0).toInt()] = query.value(1).toLongLong();
1502 return lastSeenHash;
1506 void SqliteStorage::setBufferMarkerLineMsg(UserId user, const BufferId &bufferId, const MsgId &msgId)
1508 QSqlDatabase db = logDb();
1512 QSqlQuery query(db);
1513 query.prepare(queryString("update_buffer_markerlinemsgid"));
1514 query.bindValue(":userid", user.toInt());
1515 query.bindValue(":bufferid", bufferId.toInt());
1516 query.bindValue(":markerlinemsgid", msgId.toQint64());
1527 QHash<BufferId, MsgId> SqliteStorage::bufferMarkerLineMsgIds(UserId user)
1529 QHash<BufferId, MsgId> markerLineHash;
1531 QSqlDatabase db = logDb();
1536 QSqlQuery query(db);
1537 query.prepare(queryString("select_buffer_markerlinemsgids"));
1538 query.bindValue(":userid", user.toInt());
1542 error = !watchQuery(query);
1544 while (query.next()) {
1545 markerLineHash[query.value(0).toInt()] = query.value(1).toLongLong();
1552 return markerLineHash;
1555 void SqliteStorage::setBufferActivity(UserId user, BufferId bufferId, Message::Types bufferActivity)
1557 QSqlDatabase db = logDb();
1561 QSqlQuery query(db);
1562 query.prepare(queryString("update_buffer_bufferactivity"));
1563 query.bindValue(":userid", user.toInt());
1564 query.bindValue(":bufferid", bufferId.toInt());
1565 query.bindValue(":bufferactivity", (int) bufferActivity);
1576 QHash<BufferId, Message::Types> SqliteStorage::bufferActivities(UserId user)
1578 QHash<BufferId, Message::Types> bufferActivityHash;
1580 QSqlDatabase db = logDb();
1585 QSqlQuery query(db);
1586 query.prepare(queryString("select_buffer_bufferactivities"));
1587 query.bindValue(":userid", user.toInt());
1591 error = !watchQuery(query);
1593 while (query.next()) {
1594 bufferActivityHash[query.value(0).toInt()] = Message::Types(query.value(1).toInt());
1601 return bufferActivityHash;
1605 Message::Types SqliteStorage::bufferActivity(BufferId bufferId, MsgId lastSeenMsgId)
1607 QSqlDatabase db = logDb();
1610 Message::Types result = Message::Types(nullptr);
1612 QSqlQuery query(db);
1613 query.prepare(queryString("select_buffer_bufferactivity"));
1614 query.bindValue(":bufferid", bufferId.toInt());
1615 query.bindValue(":lastseenmsgid", lastSeenMsgId.toQint64());
1620 result = Message::Types(query.value(0).toInt());
1628 QHash<QString, QByteArray> SqliteStorage::bufferCiphers(UserId user, const NetworkId &networkId)
1630 QHash<QString, QByteArray> bufferCiphers;
1632 QSqlDatabase db = logDb();
1635 QSqlQuery query(db);
1636 query.prepare(queryString("select_buffer_ciphers"));
1637 query.bindValue(":userid", user.toInt());
1638 query.bindValue(":networkid", networkId.toInt());
1643 while (query.next()) {
1644 bufferCiphers[query.value(0).toString()] = QByteArray::fromHex(query.value(1).toString().toUtf8());
1648 return bufferCiphers;
1651 void SqliteStorage::setBufferCipher(UserId user, const NetworkId &networkId, const QString &bufferName, const QByteArray &cipher)
1653 QSqlDatabase db = logDb();
1657 QSqlQuery query(db);
1658 query.prepare(queryString("update_buffer_cipher"));
1659 query.bindValue(":userid", user.toInt());
1660 query.bindValue(":networkid", networkId.toInt());
1661 query.bindValue(":buffercname", bufferName.toLower());
1662 query.bindValue(":cipher", QString(cipher.toHex()));
1672 void SqliteStorage::setHighlightCount(UserId user, BufferId bufferId, int count)
1674 QSqlDatabase db = logDb();
1678 QSqlQuery query(db);
1679 query.prepare(queryString("update_buffer_highlightcount"));
1680 query.bindValue(":userid", user.toInt());
1681 query.bindValue(":bufferid", bufferId.toInt());
1682 query.bindValue(":highlightcount", count);
1693 QHash<BufferId, int> SqliteStorage::highlightCounts(UserId user)
1695 QHash<BufferId, int> highlightCountHash;
1697 QSqlDatabase db = logDb();
1702 QSqlQuery query(db);
1703 query.prepare(queryString("select_buffer_highlightcounts"));
1704 query.bindValue(":userid", user.toInt());
1708 error = !watchQuery(query);
1710 while (query.next()) {
1711 highlightCountHash[query.value(0).toInt()] = query.value(1).toInt();
1718 return highlightCountHash;
1722 int SqliteStorage::highlightCount(BufferId bufferId, MsgId lastSeenMsgId)
1724 QSqlDatabase db = logDb();
1729 QSqlQuery query(db);
1730 query.prepare(queryString("select_buffer_highlightcount"));
1731 query.bindValue(":bufferid", bufferId.toInt());
1732 query.bindValue(":lastseenmsgid", lastSeenMsgId.toQint64());
1737 result = query.value(0).toInt();
1745 bool SqliteStorage::logMessage(Message &msg)
1747 QSqlDatabase db = logDb();
1752 QSqlQuery logMessageQuery(db);
1753 logMessageQuery.prepare(queryString("insert_message"));
1754 // As of SQLite schema version 31, timestamps are stored in milliseconds instead of
1755 // seconds. This nets us more precision as well as simplifying 64-bit time.
1756 logMessageQuery.bindValue(":time", msg.timestamp().toMSecsSinceEpoch());
1757 logMessageQuery.bindValue(":bufferid", msg.bufferInfo().bufferId().toInt());
1758 logMessageQuery.bindValue(":type", msg.type());
1759 logMessageQuery.bindValue(":flags", (int)msg.flags());
1760 logMessageQuery.bindValue(":sender", msg.sender());
1761 logMessageQuery.bindValue(":realname", msg.realName());
1762 logMessageQuery.bindValue(":avatarurl", msg.avatarUrl());
1763 logMessageQuery.bindValue(":senderprefixes", msg.senderPrefixes());
1764 logMessageQuery.bindValue(":message", msg.contents());
1767 safeExec(logMessageQuery);
1769 if (logMessageQuery.lastError().isValid()) {
1770 // constraint violation - must be NOT NULL constraint - probably the sender is missing...
1771 if (logMessageQuery.lastError().number() == 19) {
1772 QSqlQuery addSenderQuery(db);
1773 addSenderQuery.prepare(queryString("insert_sender"));
1774 addSenderQuery.bindValue(":sender", msg.sender());
1775 addSenderQuery.bindValue(":realname", msg.realName());
1776 addSenderQuery.bindValue(":avatarurl", msg.avatarUrl());
1777 safeExec(addSenderQuery);
1778 safeExec(logMessageQuery);
1779 error = !watchQuery(logMessageQuery);
1782 watchQuery(logMessageQuery);
1786 MsgId msgId = logMessageQuery.lastInsertId().toLongLong();
1787 if (msgId.isValid()) {
1788 msg.setMsgId(msgId);
1808 bool SqliteStorage::logMessages(MessageList &msgs)
1810 QSqlDatabase db = logDb();
1814 QSet<SenderData> senders;
1815 QSqlQuery addSenderQuery(db);
1816 addSenderQuery.prepare(queryString("insert_sender"));
1818 for (int i = 0; i < msgs.count(); i++) {
1819 auto &msg = msgs.at(i);
1820 SenderData sender = { msg.sender(), msg.realName(), msg.avatarUrl() };
1821 if (senders.contains(sender))
1825 addSenderQuery.bindValue(":sender", sender.sender);
1826 addSenderQuery.bindValue(":realname", sender.realname);
1827 addSenderQuery.bindValue(":avatarurl", sender.avatarurl);
1828 safeExec(addSenderQuery);
1834 QSqlQuery logMessageQuery(db);
1835 logMessageQuery.prepare(queryString("insert_message"));
1836 for (int i = 0; i < msgs.count(); i++) {
1837 Message &msg = msgs[i];
1838 // As of SQLite schema version 31, timestamps are stored in milliseconds instead of
1839 // seconds. This nets us more precision as well as simplifying 64-bit time.
1840 logMessageQuery.bindValue(":time", msg.timestamp().toMSecsSinceEpoch());
1841 logMessageQuery.bindValue(":bufferid", msg.bufferInfo().bufferId().toInt());
1842 logMessageQuery.bindValue(":type", msg.type());
1843 logMessageQuery.bindValue(":flags", (int)msg.flags());
1844 logMessageQuery.bindValue(":sender", msg.sender());
1845 logMessageQuery.bindValue(":realname", msg.realName());
1846 logMessageQuery.bindValue(":avatarurl", msg.avatarUrl());
1847 logMessageQuery.bindValue(":senderprefixes", msg.senderPrefixes());
1848 logMessageQuery.bindValue(":message", msg.contents());
1850 safeExec(logMessageQuery);
1851 if (!watchQuery(logMessageQuery)) {
1856 msg.setMsgId(logMessageQuery.lastInsertId().toLongLong());
1864 // we had a rollback in the db so we need to reset all msgIds
1865 for (int i = 0; i < msgs.count(); i++) {
1866 msgs[i].setMsgId(MsgId());
1877 QList<Message> SqliteStorage::requestMsgs(UserId user, BufferId bufferId, MsgId first, MsgId last, int limit)
1879 QList<Message> messagelist;
1881 QSqlDatabase db = logDb();
1885 BufferInfo bufferInfo;
1887 // code duplication from getBufferInfo:
1888 // this is due to the impossibility of nesting transactions and recursive locking
1889 QSqlQuery bufferInfoQuery(db);
1890 bufferInfoQuery.prepare(queryString("select_buffer_by_id"));
1891 bufferInfoQuery.bindValue(":userid", user.toInt());
1892 bufferInfoQuery.bindValue(":bufferid", bufferId.toInt());
1895 safeExec(bufferInfoQuery);
1896 error = !watchQuery(bufferInfoQuery) || !bufferInfoQuery.first();
1898 bufferInfo = BufferInfo(bufferInfoQuery.value(0).toInt(), bufferInfoQuery.value(1).toInt(), (BufferInfo::Type)bufferInfoQuery.value(2).toInt(), 0, bufferInfoQuery.value(4).toString());
1899 error = !bufferInfo.isValid();
1909 QSqlQuery query(db);
1910 if (last == -1 && first == -1) {
1911 query.prepare(queryString("select_messagesNewestK"));
1913 else if (last == -1) {
1914 query.prepare(queryString("select_messagesNewerThan"));
1915 query.bindValue(":firstmsg", first.toQint64());
1918 query.prepare(queryString("select_messagesRange"));
1919 query.bindValue(":lastmsg", last.toQint64());
1920 query.bindValue(":firstmsg", first.toQint64());
1922 query.bindValue(":bufferid", bufferId.toInt());
1923 query.bindValue(":limit", limit);
1928 while (query.next()) {
1930 // As of SQLite schema version 31, timestamps are stored in milliseconds instead of
1931 // seconds. This nets us more precision as well as simplifying 64-bit time.
1932 QDateTime::fromMSecsSinceEpoch(query.value(1).toLongLong()),
1934 (Message::Type)query.value(2).toInt(),
1935 query.value(8).toString(),
1936 query.value(4).toString(),
1937 query.value(5).toString(),
1938 query.value(6).toString(),
1939 query.value(7).toString(),
1940 (Message::Flags)query.value(3).toInt());
1941 msg.setMsgId(query.value(0).toLongLong());
1952 QList<Message> SqliteStorage::requestMsgsFiltered(UserId user, BufferId bufferId, MsgId first, MsgId last, int limit, Message::Types type, Message::Flags flags)
1954 QList<Message> messagelist;
1956 QSqlDatabase db = logDb();
1960 BufferInfo bufferInfo;
1962 // code dupication from getBufferInfo:
1963 // this is due to the impossibility of nesting transactions and recursive locking
1964 QSqlQuery bufferInfoQuery(db);
1965 bufferInfoQuery.prepare(queryString("select_buffer_by_id"));
1966 bufferInfoQuery.bindValue(":userid", user.toInt());
1967 bufferInfoQuery.bindValue(":bufferid", bufferId.toInt());
1970 safeExec(bufferInfoQuery);
1971 error = !watchQuery(bufferInfoQuery) || !bufferInfoQuery.first();
1973 bufferInfo = BufferInfo(bufferInfoQuery.value(0).toInt(), bufferInfoQuery.value(1).toInt(), (BufferInfo::Type)bufferInfoQuery.value(2).toInt(), 0, bufferInfoQuery.value(4).toString());
1974 error = !bufferInfo.isValid();
1984 QSqlQuery query(db);
1985 if (last == -1 && first == -1) {
1986 query.prepare(queryString("select_messagesNewestK_filtered"));
1988 else if (last == -1) {
1989 query.prepare(queryString("select_messagesNewerThan_filtered"));
1990 query.bindValue(":firstmsg", first.toQint64());
1993 query.prepare(queryString("select_messagesRange_filtered"));
1994 query.bindValue(":lastmsg", last.toQint64());
1995 query.bindValue(":firstmsg", first.toQint64());
1997 query.bindValue(":bufferid", bufferId.toInt());
1998 query.bindValue(":limit", limit);
2000 query.bindValue(":type", typeRaw);
2001 int flagsRaw = flags;
2002 query.bindValue(":flags", flagsRaw);
2007 while (query.next()) {
2009 // As of SQLite schema version 31, timestamps are stored in milliseconds
2010 // instead of seconds. This nets us more precision as well as simplifying
2012 QDateTime::fromMSecsSinceEpoch(query.value(1).toLongLong()),
2014 (Message::Type)query.value(2).toInt(),
2015 query.value(8).toString(),
2016 query.value(4).toString(),
2017 query.value(5).toString(),
2018 query.value(6).toString(),
2019 query.value(7).toString(),
2020 Message::Flags{query.value(3).toInt()});
2021 msg.setMsgId(query.value(0).toLongLong());
2032 QList<Message> SqliteStorage::requestAllMsgs(UserId user, MsgId first, MsgId last, int limit)
2034 QList<Message> messagelist;
2036 QSqlDatabase db = logDb();
2039 QHash<BufferId, BufferInfo> bufferInfoHash;
2041 QSqlQuery bufferInfoQuery(db);
2042 bufferInfoQuery.prepare(queryString("select_buffers"));
2043 bufferInfoQuery.bindValue(":userid", user.toInt());
2046 safeExec(bufferInfoQuery);
2047 watchQuery(bufferInfoQuery);
2048 while (bufferInfoQuery.next()) {
2049 BufferInfo bufferInfo = BufferInfo(bufferInfoQuery.value(0).toInt(), bufferInfoQuery.value(1).toInt(), (BufferInfo::Type)bufferInfoQuery.value(2).toInt(), bufferInfoQuery.value(3).toInt(), bufferInfoQuery.value(4).toString());
2050 bufferInfoHash[bufferInfo.bufferId()] = bufferInfo;
2053 QSqlQuery query(db);
2055 query.prepare(queryString("select_messagesAllNew"));
2058 query.prepare(queryString("select_messagesAll"));
2059 query.bindValue(":lastmsg", last.toQint64());
2061 query.bindValue(":userid", user.toInt());
2062 query.bindValue(":firstmsg", first.toQint64());
2063 query.bindValue(":limit", limit);
2068 while (query.next()) {
2070 // As of SQLite schema version 31, timestamps are stored in milliseconds instead of
2071 // seconds. This nets us more precision as well as simplifying 64-bit time.
2072 QDateTime::fromMSecsSinceEpoch(query.value(2).toLongLong()),
2073 bufferInfoHash[query.value(1).toInt()],
2074 (Message::Type)query.value(3).toInt(),
2075 query.value(9).toString(),
2076 query.value(5).toString(),
2077 query.value(6).toString(),
2078 query.value(7).toString(),
2079 query.value(8).toString(),
2080 (Message::Flags)query.value(4).toInt());
2081 msg.setMsgId(query.value(0).toLongLong());
2090 QList<Message> SqliteStorage::requestAllMsgsFiltered(UserId user, MsgId first, MsgId last, int limit, Message::Types type, Message::Flags flags)
2092 QList<Message> messagelist;
2094 QSqlDatabase db = logDb();
2097 QHash<BufferId, BufferInfo> bufferInfoHash;
2099 QSqlQuery bufferInfoQuery(db);
2100 bufferInfoQuery.prepare(queryString("select_buffers"));
2101 bufferInfoQuery.bindValue(":userid", user.toInt());
2104 safeExec(bufferInfoQuery);
2105 watchQuery(bufferInfoQuery);
2106 while (bufferInfoQuery.next()) {
2107 BufferInfo bufferInfo = BufferInfo(bufferInfoQuery.value(0).toInt(), bufferInfoQuery.value(1).toInt(), (BufferInfo::Type)bufferInfoQuery.value(2).toInt(), bufferInfoQuery.value(3).toInt(), bufferInfoQuery.value(4).toString());
2108 bufferInfoHash[bufferInfo.bufferId()] = bufferInfo;
2111 QSqlQuery query(db);
2113 query.prepare(queryString("select_messagesAllNew_filtered"));
2116 query.prepare(queryString("select_messagesAll_filtered"));
2117 query.bindValue(":lastmsg", last.toQint64());
2119 query.bindValue(":userid", user.toInt());
2120 query.bindValue(":firstmsg", first.toQint64());
2121 query.bindValue(":limit", limit);
2123 query.bindValue(":type", typeRaw);
2124 int flagsRaw = flags;
2125 query.bindValue(":flags", flagsRaw);
2130 while (query.next()) {
2132 // As of SQLite schema version 31, timestamps are stored in milliseconds
2133 // instead of seconds. This nets us more precision as well as simplifying
2135 QDateTime::fromMSecsSinceEpoch(query.value(2).toLongLong()),
2136 bufferInfoHash[query.value(1).toInt()],
2137 (Message::Type)query.value(3).toInt(),
2138 query.value(9).toString(),
2139 query.value(5).toString(),
2140 query.value(6).toString(),
2141 query.value(7).toString(),
2142 query.value(8).toString(),
2143 Message::Flags{query.value(4).toInt()});
2144 msg.setMsgId(query.value(0).toLongLong());
2153 QMap<UserId, QString> SqliteStorage::getAllAuthUserNames()
2155 QMap<UserId, QString> authusernames;
2157 QSqlDatabase db = logDb();
2160 QSqlQuery query(db);
2161 query.prepare(queryString("select_all_authusernames"));
2166 while (query.next()) {
2167 authusernames[query.value(0).toInt()] = query.value(1).toString();
2172 return authusernames;
2176 QString SqliteStorage::backlogFile()
2178 return Quassel::configDirPath() + "quassel-storage.sqlite";
2182 bool SqliteStorage::safeExec(QSqlQuery &query, int retryCount)
2186 if (!query.lastError().isValid())
2189 switch (query.lastError().number()) {
2190 case 5: // SQLITE_BUSY 5 /* The database file is locked */
2192 case 6: // SQLITE_LOCKED 6 /* A table in the database is locked */
2193 if (retryCount < _maxRetryCount)
2194 return safeExec(query, retryCount + 1);
2203 // ========================================
2205 // ========================================
2206 SqliteMigrationReader::SqliteMigrationReader()
2212 void SqliteMigrationReader::setMaxId(MigrationObject mo)
2214 QString queryString;
2217 queryString = "SELECT max(senderid) FROM sender";
2220 queryString = "SELECT max(messageid) FROM backlog";
2226 QSqlQuery query = logDb().exec(queryString);
2228 _maxId = query.value(0).toLongLong();
2232 bool SqliteMigrationReader::prepareQuery(MigrationObject mo)
2238 newQuery(queryString("migrate_read_quasseluser"), logDb());
2241 newQuery(queryString("migrate_read_identity"), logDb());
2244 newQuery(queryString("migrate_read_identity_nick"), logDb());
2247 newQuery(queryString("migrate_read_network"), logDb());
2250 newQuery(queryString("migrate_read_buffer"), logDb());
2253 newQuery(queryString("migrate_read_sender"), logDb());
2255 bindValue(1, stepSize());
2258 newQuery(queryString("migrate_read_backlog"), logDb());
2260 bindValue(1, stepSize());
2263 newQuery(queryString("migrate_read_ircserver"), logDb());
2266 newQuery(queryString("migrate_read_usersetting"), logDb());
2269 newQuery(queryString("migrate_read_corestate"), logDb());
2276 bool SqliteMigrationReader::readMo(QuasselUserMO &user)
2281 user.id = value(0).toInt();
2282 user.username = value(1).toString();
2283 user.password = value(2).toString();
2284 user.hashversion = value(3).toInt();
2285 user.authenticator = value(4).toString();
2290 bool SqliteMigrationReader::readMo(IdentityMO &identity)
2295 identity.id = value(0).toInt();
2296 identity.userid = value(1).toInt();
2297 identity.identityname = value(2).toString();
2298 identity.realname = value(3).toString();
2299 identity.awayNick = value(4).toString();
2300 identity.awayNickEnabled = value(5).toInt() == 1 ? true : false;
2301 identity.awayReason = value(6).toString();
2302 identity.awayReasonEnabled = value(7).toInt() == 1 ? true : false;
2303 identity.autoAwayEnabled = value(8).toInt() == 1 ? true : false;
2304 identity.autoAwayTime = value(9).toInt();
2305 identity.autoAwayReason = value(10).toString();
2306 identity.autoAwayReasonEnabled = value(11).toInt() == 1 ? true : false;
2307 identity.detachAwayEnabled = value(12).toInt() == 1 ? true : false;
2308 identity.detachAwayReason = value(13).toString();
2309 identity.detachAwayReasonEnabled = value(14).toInt() == 1 ? true : false;
2310 identity.ident = value(15).toString();
2311 identity.kickReason = value(16).toString();
2312 identity.partReason = value(17).toString();
2313 identity.quitReason = value(18).toString();
2314 identity.sslCert = value(19).toByteArray();
2315 identity.sslKey = value(20).toByteArray();
2320 bool SqliteMigrationReader::readMo(IdentityNickMO &identityNick)
2325 identityNick.nickid = value(0).toInt();
2326 identityNick.identityId = value(1).toInt();
2327 identityNick.nick = value(2).toString();
2332 bool SqliteMigrationReader::readMo(NetworkMO &network)
2337 network.networkid = value(0).toInt();
2338 network.userid = value(1).toInt();
2339 network.networkname = value(2).toString();
2340 network.identityid = value(3).toInt();
2341 network.encodingcodec = value(4).toString();
2342 network.decodingcodec = value(5).toString();
2343 network.servercodec = value(6).toString();
2344 network.userandomserver = value(7).toInt() == 1 ? true : false;
2345 network.perform = value(8).toString();
2346 network.useautoidentify = value(9).toInt() == 1 ? true : false;
2347 network.autoidentifyservice = value(10).toString();
2348 network.autoidentifypassword = value(11).toString();
2349 network.useautoreconnect = value(12).toInt() == 1 ? true : false;
2350 network.autoreconnectinterval = value(13).toInt();
2351 network.autoreconnectretries = value(14).toInt();
2352 network.unlimitedconnectretries = value(15).toInt() == 1 ? true : false;
2353 network.rejoinchannels = value(16).toInt() == 1 ? true : false;
2354 network.connected = value(17).toInt() == 1 ? true : false;
2355 network.usermode = value(18).toString();
2356 network.awaymessage = value(19).toString();
2357 network.attachperform = value(20).toString();
2358 network.detachperform = value(21).toString();
2359 network.usesasl = value(22).toInt() == 1 ? true : false;
2360 network.saslaccount = value(23).toString();
2361 network.saslpassword = value(24).toString();
2362 // Custom rate limiting
2363 network.usecustommessagerate = value(25).toInt() == 1 ? true : false;
2364 network.messagerateburstsize = value(26).toInt();
2365 network.messageratedelay = value(27).toUInt();
2366 network.unlimitedmessagerate = value(28).toInt() == 1 ? true : false;
2371 bool SqliteMigrationReader::readMo(BufferMO &buffer)
2376 buffer.bufferid = value(0).toInt();
2377 buffer.userid = value(1).toInt();
2378 buffer.groupid = value(2).toInt();
2379 buffer.networkid = value(3).toInt();
2380 buffer.buffername = value(4).toString();
2381 buffer.buffercname = value(5).toString();
2382 buffer.buffertype = value(6).toInt();
2383 buffer.lastmsgid = value(7).toLongLong();
2384 buffer.lastseenmsgid = value(8).toLongLong();
2385 buffer.markerlinemsgid = value(9).toLongLong();
2386 buffer.bufferactivity = value(10).toInt();
2387 buffer.highlightcount = value(11).toInt();
2388 buffer.key = value(12).toString();
2389 buffer.joined = value(13).toInt() == 1 ? true : false;
2390 buffer.cipher = value(14).toString();
2395 bool SqliteMigrationReader::readMo(SenderMO &sender)
2399 if (sender.senderId < _maxId) {
2400 bindValue(0, sender.senderId + (skipSteps * stepSize()));
2401 bindValue(1, sender.senderId + ((skipSteps + 1) * stepSize()));
2411 sender.senderId = value(0).toLongLong();
2412 sender.sender = value(1).toString();
2413 sender.realname = value(2).toString();
2414 sender.avatarurl = value(3).toString();
2419 bool SqliteMigrationReader::readMo(BacklogMO &backlog)
2421 qint64 skipSteps = 0;
2423 if (backlog.messageid < _maxId) {
2424 bindValue(0, backlog.messageid.toQint64() + (skipSteps * stepSize()));
2425 bindValue(1, backlog.messageid.toQint64() + ((skipSteps + 1) * stepSize()));
2435 backlog.messageid = value(0).toLongLong();
2436 // As of SQLite schema version 31, timestamps are stored in milliseconds instead of
2437 // seconds. This nets us more precision as well as simplifying 64-bit time.
2438 backlog.time = QDateTime::fromMSecsSinceEpoch(value(1).toLongLong()).toUTC();
2439 backlog.bufferid = value(2).toInt();
2440 backlog.type = value(3).toInt();
2441 backlog.flags = value(4).toInt();
2442 backlog.senderid = value(5).toLongLong();
2443 backlog.senderprefixes = value(6).toString();
2444 backlog.message = value(7).toString();
2449 bool SqliteMigrationReader::readMo(IrcServerMO &ircserver)
2454 ircserver.serverid = value(0).toInt();
2455 ircserver.userid = value(1).toInt();
2456 ircserver.networkid = value(2).toInt();
2457 ircserver.hostname = value(3).toString();
2458 ircserver.port = value(4).toInt();
2459 ircserver.password = value(5).toString();
2460 ircserver.ssl = value(6).toInt() == 1 ? true : false;
2461 ircserver.sslversion = value(7).toInt();
2462 ircserver.useproxy = value(8).toInt() == 1 ? true : false;
2463 ircserver.proxytype = value(9).toInt();
2464 ircserver.proxyhost = value(10).toString();
2465 ircserver.proxyport = value(11).toInt();
2466 ircserver.proxyuser = value(12).toString();
2467 ircserver.proxypass = value(13).toString();
2468 ircserver.sslverify = value(14).toInt() == 1 ? true : false;
2473 bool SqliteMigrationReader::readMo(UserSettingMO &userSetting)
2478 userSetting.userid = value(0).toInt();
2479 userSetting.settingname = value(1).toString();
2480 userSetting.settingvalue = value(2).toByteArray();
2486 bool SqliteMigrationReader::readMo(CoreStateMO &coreState)
2491 coreState.key = value(0).toString();
2492 coreState.value = value(1).toByteArray();