Merge branch 'bufferviewoverlay'
[quassel.git] / src / core / sqlitestorage.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-07 by the Quassel Project                          *
3  *   devel@quassel-irc.org                                                 *
4  *                                                                         *
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.                                           *
9  *                                                                         *
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.                          *
14  *                                                                         *
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  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20
21 #include "sqlitestorage.h"
22
23 #include <QtSql>
24
25 #include "logger.h"
26 #include "network.h"
27 #include "quassel.h"
28
29 int SqliteStorage::_maxRetryCount = 150;
30
31 SqliteStorage::SqliteStorage(QObject *parent)
32   : AbstractSqlStorage(parent)
33 {
34 }
35
36 SqliteStorage::~SqliteStorage() {
37 }
38
39 bool SqliteStorage::isAvailable() const {
40   if(!QSqlDatabase::isDriverAvailable("QSQLITE")) return false;
41   return true;
42 }
43
44 QString SqliteStorage::displayName() const {
45   return QString("SQLite");
46 }
47
48 QString SqliteStorage::description() const {
49   return tr("SQLite is a file-based database engine that does not require any setup. It is suitable for small and medium-sized "
50             "databases that do not require access via network. Use SQLite if your Quassel Core should store its data on the same machine "
51             "it is running on, and if you only expect a few users to use your core.");
52 }
53
54 int SqliteStorage::installedSchemaVersion() {
55   // only used when there is a singlethread (during startup)
56   // so we don't need locking here
57   QSqlQuery query = logDb().exec("SELECT value FROM coreinfo WHERE key = 'schemaversion'");
58   if(query.first())
59     return query.value(0).toInt();
60
61   // maybe it's really old... (schema version 0)
62   query = logDb().exec("SELECT MAX(version) FROM coreinfo");
63   if(query.first())
64     return query.value(0).toInt();
65
66   return AbstractSqlStorage::installedSchemaVersion();
67 }
68
69 bool SqliteStorage::updateSchemaVersion(int newVersion) {
70   // only used when there is a singlethread (during startup)
71   // so we don't need locking here
72   QSqlQuery query(logDb());
73   query.prepare("UPDATE coreinfo SET value = :version WHERE key = 'schemaversion'");
74   query.bindValue(":version", newVersion);
75   query.exec();
76
77   bool success = true;
78   if(query.lastError().isValid()) {
79     qCritical() << "SqliteStorage::updateSchemaVersion(int): Updating schema version failed!";
80     success = false;
81   }
82   return success;
83 }
84
85 bool SqliteStorage::setupSchemaVersion(int version) {
86   // only used when there is a singlethread (during startup)
87   // so we don't need locking here
88   QSqlQuery query(logDb());
89   query.prepare("INSERT INTO coreinfo (key, value) VALUES ('schemaversion', :version)");
90   query.bindValue(":version", version);
91   query.exec();
92
93   bool success = true;
94   if(query.lastError().isValid()) {
95     qCritical() << "SqliteStorage::setupSchemaVersion(int): Updating schema version failed!";
96     success = false;
97   }
98   return success;
99 }
100
101 UserId SqliteStorage::addUser(const QString &user, const QString &password) {
102   QSqlDatabase db = logDb();
103   db.transaction();
104
105   QSqlQuery query(db);
106   query.prepare(queryString("insert_quasseluser"));
107   query.bindValue(":username", user);
108   query.bindValue(":password", cryptedPassword(password));
109   lockForWrite();
110   safeExec(query);
111   if(query.lastError().isValid() && query.lastError().number() == 19) { // user already exists - sadly 19 seems to be the general constraint violation error...
112     db.rollback();
113     unlock();
114     return 0;
115   }
116   UserId uid = query.lastInsertId().toInt();
117   db.commit();
118   unlock();
119   emit userAdded(uid, user);
120   return uid;
121 }
122
123 bool SqliteStorage::updateUser(UserId user, const QString &password) {
124   QSqlDatabase db = logDb();
125   db.transaction();
126
127   QSqlQuery query(db);
128   query.prepare(queryString("update_userpassword"));
129   query.bindValue(":userid", user.toInt());
130   query.bindValue(":password", cryptedPassword(password));
131   lockForWrite();
132   safeExec(query);
133   bool success = query.numRowsAffected() != 0;
134   db.commit();
135   unlock();
136   return success;
137 }
138
139 void SqliteStorage::renameUser(UserId user, const QString &newName) {
140   QSqlDatabase db = logDb();
141   db.transaction();
142
143   QSqlQuery query(db);
144   query.prepare(queryString("update_username"));
145   query.bindValue(":userid", user.toInt());
146   query.bindValue(":username", newName);
147   lockForWrite();
148   safeExec(query);
149   db.commit();
150   unlock();
151   emit userRenamed(user, newName);
152 }
153
154 UserId SqliteStorage::validateUser(const QString &user, const QString &password) {
155   UserId userId;
156
157   // this scope ensures that the query is freed in sqlite before we call unlock()
158   // this ensures that our thread doesn't hold a internal after unlock is called
159   // (see sqlites doc on implicit locking for details)
160   {
161     QSqlQuery query(logDb());
162     query.prepare(queryString("select_authuser"));
163     query.bindValue(":username", user);
164     query.bindValue(":password", cryptedPassword(password));
165
166     lockForRead();
167     safeExec(query);
168
169     if(query.first()) {
170       userId = query.value(0).toInt();
171     }
172   }
173   unlock();
174
175   return userId;
176 }
177
178 UserId SqliteStorage::getUserId(const QString &username) {
179   UserId userId;
180
181   // this scope ensures that the query is freed in sqlite before we call unlock()
182   // this ensures that our thread doesn't hold a internal after unlock is called
183   // (see sqlites doc on implicit locking for details)
184   {
185     QSqlQuery query(logDb());
186     query.prepare(queryString("select_userid"));
187     query.bindValue(":username", username);
188
189     lockForRead();
190     safeExec(query);
191
192     if(query.first()) {
193       userId = query.value(0).toInt();
194     }
195   }
196   unlock();
197
198   return userId;
199 }
200
201 UserId SqliteStorage::internalUser() {
202   UserId userId;
203
204   // this scope ensures that the query is freed in sqlite before we call unlock()
205   // this ensures that our thread doesn't hold a internal after unlock is called
206   // (see sqlites doc on implicit locking for details)
207   {
208     QSqlQuery query(logDb());
209     query.prepare(queryString("select_internaluser"));
210     lockForRead();
211     safeExec(query);
212
213     if(query.first()) {
214       userId = query.value(0).toInt();
215     }
216   }
217   unlock();
218
219   return userId;
220 }
221
222 void SqliteStorage::delUser(UserId user) {
223   QSqlDatabase db = logDb();
224   db.transaction();
225
226   lockForWrite();
227   QSqlQuery query(db);
228   query.prepare(queryString("delete_backlog_by_uid"));
229   query.bindValue(":userid", user.toInt());
230   safeExec(query);
231
232   query.prepare(queryString("delete_buffers_by_uid"));
233   query.bindValue(":userid", user.toInt());
234   safeExec(query);
235
236   query.prepare(queryString("delete_networks_by_uid"));
237   query.bindValue(":userid", user.toInt());
238   safeExec(query);
239
240   query.prepare(queryString("delete_quasseluser"));
241   query.bindValue(":userid", user.toInt());
242   safeExec(query);
243   // I hate the lack of foreign keys and on delete cascade... :(
244   db.commit();
245   unlock();
246
247   emit userRemoved(user);
248 }
249
250 void SqliteStorage::setUserSetting(UserId userId, const QString &settingName, const QVariant &data) {
251   QByteArray rawData;
252   QDataStream out(&rawData, QIODevice::WriteOnly);
253   out.setVersion(QDataStream::Qt_4_2);
254   out << data;
255
256   QSqlDatabase db = logDb();
257   db.transaction();
258   QSqlQuery query(db);
259   query.prepare(queryString("insert_user_setting"));
260   query.bindValue(":userid", userId.toInt());
261   query.bindValue(":settingname", settingName);
262   query.bindValue(":settingvalue", rawData);
263   lockForWrite();
264   safeExec(query);
265
266   if(query.lastError().isValid()) {
267     QSqlQuery updateQuery(db);
268     updateQuery.prepare(queryString("update_user_setting"));
269     updateQuery.bindValue(":userid", userId.toInt());
270     updateQuery.bindValue(":settingname", settingName);
271     updateQuery.bindValue(":settingvalue", rawData);
272     safeExec(updateQuery);
273   }
274   db.commit();
275   unlock();
276 }
277
278 QVariant SqliteStorage::getUserSetting(UserId userId, const QString &settingName, const QVariant &defaultData) {
279   QSqlQuery query(logDb());
280   query.prepare(queryString("select_user_setting"));
281   query.bindValue(":userid", userId.toInt());
282   query.bindValue(":settingname", settingName);
283   lockForRead();
284   safeExec(query);
285
286   if(query.first()) {
287     QVariant data;
288     QByteArray rawData = query.value(0).toByteArray();
289     unlock();
290     QDataStream in(&rawData, QIODevice::ReadOnly);
291     in.setVersion(QDataStream::Qt_4_2);
292     in >> data;
293     return data;
294   } else {
295     unlock();
296     return defaultData;
297   }
298 }
299
300 IdentityId SqliteStorage::createIdentity(UserId user, CoreIdentity &identity) {
301   IdentityId identityId;
302
303   QSqlDatabase db = logDb();
304   db.transaction();
305
306   QSqlQuery query(db);
307   query.prepare(queryString("insert_identity"));
308   query.bindValue(":userid", user.toInt());
309   query.bindValue(":identityname", identity.identityName());
310   query.bindValue(":realname", identity.realName());
311   query.bindValue(":awaynick", identity.awayNick());
312   query.bindValue(":awaynickenabled", identity.awayNickEnabled() ? 1 : 0);
313   query.bindValue(":awayreason", identity.awayReason());
314   query.bindValue(":awayreasonenabled", identity.awayReasonEnabled() ? 1 : 0);
315   query.bindValue(":autoawayenabled", identity.awayReasonEnabled() ? 1 : 0);
316   query.bindValue(":autoawaytime", identity.autoAwayTime());
317   query.bindValue(":autoawayreason", identity.autoAwayReason());
318   query.bindValue(":autoawayreasonenabled", identity.autoAwayReasonEnabled() ? 1 : 0);
319   query.bindValue(":detachawayenabled", identity.detachAwayEnabled() ? 1 : 0);
320   query.bindValue(":detachawayreason", identity.detachAwayReason());
321   query.bindValue(":detachawayreasonenabled", identity.detachAwayReasonEnabled() ? 1 : 0);
322   query.bindValue(":ident", identity.ident());
323   query.bindValue(":kickreason", identity.kickReason());
324   query.bindValue(":partreason", identity.partReason());
325   query.bindValue(":quitreason", identity.quitReason());
326 #ifdef HAVE_SSL
327   query.bindValue(":sslcert", identity.sslCert().toPem());
328   query.bindValue(":sslkey", identity.sslKey().toPem());
329 #else
330   query.bindValue(":sslcert", QByteArray());
331   query.bindValue(":sslkey", QByteArray());
332 #endif
333
334   lockForWrite();
335   safeExec(query);
336
337   identityId = query.lastInsertId().toInt();
338   if(!identityId.isValid()) {
339     watchQuery(query);
340   } else {
341     QSqlQuery deleteNickQuery(db);
342     deleteNickQuery.prepare(queryString("delete_nicks"));
343     deleteNickQuery.bindValue(":identityid", identityId.toInt());
344     safeExec(deleteNickQuery);
345
346     QSqlQuery insertNickQuery(db);
347     insertNickQuery.prepare(queryString("insert_nick"));
348     foreach(QString nick, identity.nicks()) {
349       insertNickQuery.bindValue(":identityid", identityId.toInt());
350       insertNickQuery.bindValue(":nick", nick);
351       safeExec(insertNickQuery);
352     }
353   }
354   db.commit();
355   unlock();
356   identity.setId(identityId);
357   return identityId;
358 }
359
360 bool SqliteStorage::updateIdentity(UserId user, const CoreIdentity &identity) {
361   QSqlDatabase db = logDb();
362   db.transaction();
363
364   QSqlQuery checkQuery(db);
365   checkQuery.prepare(queryString("select_checkidentity"));
366   checkQuery.bindValue(":identityid", identity.id().toInt());
367   checkQuery.bindValue(":userid", user.toInt());
368   lockForWrite();
369   safeExec(checkQuery);
370
371   // there should be exactly one identity for the given id and user
372   if(!checkQuery.first() || checkQuery.value(0).toInt() != 1) {
373     db.commit();
374     unlock();
375     return false;
376   }
377
378   QSqlQuery query(db);
379   query.prepare(queryString("update_identity"));
380   query.bindValue(":identityname", identity.identityName());
381   query.bindValue(":realname", identity.realName());
382   query.bindValue(":awaynick", identity.awayNick());
383   query.bindValue(":awaynickenabled", identity.awayNickEnabled() ? 1 : 0);
384   query.bindValue(":awayreason", identity.awayReason());
385   query.bindValue(":awayreasonenabled", identity.awayReasonEnabled() ? 1 : 0);
386   query.bindValue(":autoawayenabled", identity.awayReasonEnabled() ? 1 : 0);
387   query.bindValue(":autoawaytime", identity.autoAwayTime());
388   query.bindValue(":autoawayreason", identity.autoAwayReason());
389   query.bindValue(":autoawayreasonenabled", identity.autoAwayReasonEnabled() ? 1 : 0);
390   query.bindValue(":detachawayenabled", identity.detachAwayEnabled() ? 1 : 0);
391   query.bindValue(":detachawayreason", identity.detachAwayReason());
392   query.bindValue(":detachawayreasonenabled", identity.detachAwayReasonEnabled() ? 1 : 0);
393   query.bindValue(":ident", identity.ident());
394   query.bindValue(":kickreason", identity.kickReason());
395   query.bindValue(":partreason", identity.partReason());
396   query.bindValue(":quitreason", identity.quitReason());
397 #ifdef HAVE_SSL
398   query.bindValue(":sslcert", identity.sslCert().toPem());
399   query.bindValue(":sslkey", identity.sslKey().toPem());
400 #else
401   query.bindValue(":sslcert", QByteArray());
402   query.bindValue(":sslkey", QByteArray());
403 #endif
404   query.bindValue(":identityid", identity.id().toInt());
405   safeExec(query);
406   watchQuery(query);
407
408   QSqlQuery deleteNickQuery(db);
409   deleteNickQuery.prepare(queryString("delete_nicks"));
410   deleteNickQuery.bindValue(":identityid", identity.id().toInt());
411   safeExec(deleteNickQuery);
412   watchQuery(deleteNickQuery);
413
414   QSqlQuery insertNickQuery(db);
415   insertNickQuery.prepare(queryString("insert_nick"));
416   foreach(QString nick, identity.nicks()) {
417     insertNickQuery.bindValue(":identityid", identity.id().toInt());
418     insertNickQuery.bindValue(":nick", nick);
419     safeExec(insertNickQuery);
420     watchQuery(insertNickQuery);
421   }
422   db.commit();
423   unlock();
424   return true;
425 }
426
427 void SqliteStorage::removeIdentity(UserId user, IdentityId identityId) {
428   QSqlDatabase db = logDb();
429   db.transaction();
430
431   QSqlQuery checkQuery(db);
432   checkQuery.prepare(queryString("select_checkidentity"));
433   checkQuery.bindValue(":identityid", identityId.toInt());
434   checkQuery.bindValue(":userid", user.toInt());
435   lockForRead();
436   safeExec(checkQuery);
437
438   // there should be exactly one identity for the given id and user
439   if(!checkQuery.first() || checkQuery.value(0).toInt() != 1) {
440     db.commit();
441     unlock();
442     return;
443   }
444
445   QSqlQuery deleteNickQuery(db);
446   deleteNickQuery.prepare(queryString("delete_nicks"));
447   deleteNickQuery.bindValue(":identityid", identityId.toInt());
448   safeExec(deleteNickQuery);
449
450   QSqlQuery deleteIdentityQuery(db);
451   deleteIdentityQuery.prepare(queryString("delete_identity"));
452   deleteIdentityQuery.bindValue(":identityid", identityId.toInt());
453   deleteIdentityQuery.bindValue(":userid", user.toInt());
454   safeExec(deleteIdentityQuery);
455   db.commit();
456   unlock();
457 }
458
459 QList<CoreIdentity> SqliteStorage::identities(UserId user) {
460   QList<CoreIdentity> identities;
461   QSqlDatabase db = logDb();
462   db.transaction();
463
464   QSqlQuery query(db);
465   query.prepare(queryString("select_identities"));
466   query.bindValue(":userid", user.toInt());
467
468   QSqlQuery nickQuery(db);
469   nickQuery.prepare(queryString("select_nicks"));
470
471   lockForRead();
472   safeExec(query);
473
474   while(query.next()) {
475     CoreIdentity identity(IdentityId(query.value(0).toInt()));
476
477     identity.setIdentityName(query.value(1).toString());
478     identity.setRealName(query.value(2).toString());
479     identity.setAwayNick(query.value(3).toString());
480     identity.setAwayNickEnabled(!!query.value(4).toInt());
481     identity.setAwayReason(query.value(5).toString());
482     identity.setAwayReasonEnabled(!!query.value(6).toInt());
483     identity.setAutoAwayEnabled(!!query.value(7).toInt());
484     identity.setAutoAwayTime(query.value(8).toInt());
485     identity.setAutoAwayReason(query.value(9).toString());
486     identity.setAutoAwayReasonEnabled(!!query.value(10).toInt());
487     identity.setDetachAwayEnabled(!!query.value(11).toInt());
488     identity.setDetachAwayReason(query.value(12).toString());
489     identity.setDetachAwayReasonEnabled(!!query.value(13).toInt());
490     identity.setIdent(query.value(14).toString());
491     identity.setKickReason(query.value(15).toString());
492     identity.setPartReason(query.value(16).toString());
493     identity.setQuitReason(query.value(17).toString());
494 #ifdef HAVE_SSL
495     identity.setSslCert(query.value(18).toByteArray());
496     identity.setSslKey(query.value(19).toByteArray());
497 #endif
498
499     nickQuery.bindValue(":identityid", identity.id().toInt());
500     QList<QString> nicks;
501     safeExec(nickQuery);
502     watchQuery(nickQuery);
503     while(nickQuery.next()) {
504       nicks << nickQuery.value(0).toString();
505     }
506     identity.setNicks(nicks);
507     identities << identity;
508   }
509   db.commit();
510   unlock();
511   return identities;
512 }
513
514 NetworkId SqliteStorage::createNetwork(UserId user, const NetworkInfo &info) {
515   NetworkId networkId;
516
517   QSqlDatabase db = logDb();
518   db.transaction();
519
520   QSqlQuery query(db);
521   query.prepare(queryString("insert_network"));
522   query.bindValue(":userid", user.toInt());
523   bindNetworkInfo(query, info);
524   lockForWrite();
525   safeExec(query);
526   if(!watchQuery(query)) {
527     db.rollback();
528     unlock();
529     return NetworkId();
530   }
531
532   networkId = query.lastInsertId().toInt();
533
534   QSqlQuery insertServersQuery(db);
535   insertServersQuery.prepare(queryString("insert_server"));
536   foreach(Network::Server server, info.serverList) {
537     insertServersQuery.bindValue(":userid", user.toInt());
538     insertServersQuery.bindValue(":networkid", networkId.toInt());
539     bindServerInfo(insertServersQuery, server);
540     safeExec(insertServersQuery);
541     if(!watchQuery(insertServersQuery)) {
542       db.rollback();
543       unlock();
544       return NetworkId();
545     }
546   }
547
548   db.commit();
549   unlock();
550   return networkId;
551 }
552
553 void SqliteStorage::bindNetworkInfo(QSqlQuery &query, const NetworkInfo &info) {
554   query.bindValue(":networkname", info.networkName);
555   query.bindValue(":identityid", info.identity.toInt());
556   query.bindValue(":encodingcodec", QString(info.codecForEncoding));
557   query.bindValue(":decodingcodec", QString(info.codecForDecoding));
558   query.bindValue(":servercodec", QString(info.codecForServer));
559   query.bindValue(":userandomserver", info.useRandomServer ? 1 : 0);
560   query.bindValue(":perform", info.perform.join("\n"));
561   query.bindValue(":useautoidentify", info.useAutoIdentify ? 1 : 0);
562   query.bindValue(":autoidentifyservice", info.autoIdentifyService);
563   query.bindValue(":autoidentifypassword", info.autoIdentifyPassword);
564   query.bindValue(":useautoreconnect", info.useAutoReconnect ? 1 : 0);
565   query.bindValue(":autoreconnectinterval", info.autoReconnectInterval);
566   query.bindValue(":autoreconnectretries", info.autoReconnectRetries);
567   query.bindValue(":unlimitedconnectretries", info.unlimitedReconnectRetries ? 1 : 0);
568   query.bindValue(":rejoinchannels", info.rejoinChannels ? 1 : 0);
569   if(info.networkId.isValid())
570     query.bindValue(":networkid", info.networkId.toInt());
571 }
572
573 void SqliteStorage::bindServerInfo(QSqlQuery &query, const Network::Server &server) {
574   query.bindValue(":hostname", server.host);
575   query.bindValue(":port", server.port);
576   query.bindValue(":password", server.password);
577   query.bindValue(":ssl", server.useSsl ? 1 : 0);
578   query.bindValue(":sslversion", server.sslVersion);
579   query.bindValue(":useproxy", server.useProxy ? 1 : 0);
580   query.bindValue(":proxytype", server.proxyType);
581   query.bindValue(":proxyhost", server.proxyHost);
582   query.bindValue(":proxyport", server.proxyPort);
583   query.bindValue(":proxyuser", server.proxyUser);
584   query.bindValue(":proxypass", server.proxyPass);
585 }
586
587 bool SqliteStorage::updateNetwork(UserId user, const NetworkInfo &info) {
588   QSqlDatabase db = logDb();
589   db.transaction();
590
591   QSqlQuery updateQuery(db);
592   updateQuery.prepare(queryString("update_network"));
593   updateQuery.bindValue(":userid", user.toInt());
594   bindNetworkInfo(updateQuery, info);
595
596   lockForWrite();
597   safeExec(updateQuery);
598   if(!watchQuery(updateQuery) || updateQuery.numRowsAffected() != 1) {
599     db.rollback();
600     unlock();
601     return false;
602   }
603
604   QSqlQuery dropServersQuery(db);
605   dropServersQuery.prepare("DELETE FROM ircserver WHERE networkid = :networkid");
606   dropServersQuery.bindValue(":networkid", info.networkId.toInt());
607   safeExec(dropServersQuery);
608   if(!watchQuery(dropServersQuery)) {
609     db.rollback();
610     unlock();
611     return false;
612   }
613
614   QSqlQuery insertServersQuery(db);
615   insertServersQuery.prepare(queryString("insert_server"));
616   foreach(Network::Server server, info.serverList) {
617     insertServersQuery.bindValue(":userid", user.toInt());
618     insertServersQuery.bindValue(":networkid", info.networkId.toInt());
619     bindServerInfo(insertServersQuery, server);
620     safeExec(insertServersQuery);
621     if(!watchQuery(insertServersQuery)) {
622       db.rollback();
623       unlock();
624       return false;
625     }
626   }
627
628   db.commit();
629   unlock();
630   return true;
631 }
632
633 bool SqliteStorage::removeNetwork(UserId user, const NetworkId &networkId) {
634   QSqlDatabase db = logDb();
635   db.transaction();
636
637   QSqlQuery deleteNetworkQuery(db);
638   deleteNetworkQuery.prepare(queryString("delete_network"));
639   deleteNetworkQuery.bindValue(":networkid", networkId.toInt());
640   deleteNetworkQuery.bindValue(":userid", user.toInt());
641   lockForWrite();
642   safeExec(deleteNetworkQuery);
643   if(!watchQuery(deleteNetworkQuery) || deleteNetworkQuery.numRowsAffected() != 1) {
644     db.rollback();
645     unlock();
646     return false;
647   }
648
649   QSqlQuery deleteBacklogQuery(db);
650   deleteBacklogQuery.prepare(queryString("delete_backlog_for_network"));
651   deleteBacklogQuery.bindValue(":networkid", networkId.toInt());
652   safeExec(deleteBacklogQuery);
653   if(!watchQuery(deleteBacklogQuery)) {
654     db.rollback();
655     unlock();
656     return false;
657   }
658
659   QSqlQuery deleteBuffersQuery(db);
660   deleteBuffersQuery.prepare(queryString("delete_buffers_for_network"));
661   deleteBuffersQuery.bindValue(":networkid", networkId.toInt());
662   safeExec(deleteBuffersQuery);
663   if(!watchQuery(deleteBuffersQuery)) {
664     db.rollback();
665     unlock();
666     return false;
667   }
668
669   QSqlQuery deleteServersQuery(db);
670   deleteServersQuery.prepare(queryString("delete_ircservers_for_network"));
671   deleteServersQuery.bindValue(":networkid", networkId.toInt());
672   safeExec(deleteServersQuery);
673   if(!watchQuery(deleteServersQuery)) {
674     db.rollback();
675     unlock();
676     return false;
677   }
678
679   db.commit();
680   unlock();
681   return true;
682 }
683
684 QList<NetworkInfo> SqliteStorage::networks(UserId user) {
685   QList<NetworkInfo> nets;
686
687   QSqlDatabase db = logDb();
688   db.transaction();
689
690   QSqlQuery networksQuery(db);
691   networksQuery.prepare(queryString("select_networks_for_user"));
692   networksQuery.bindValue(":userid", user.toInt());
693
694   QSqlQuery serversQuery(db);
695   serversQuery.prepare(queryString("select_servers_for_network"));
696
697   lockForRead();
698   safeExec(networksQuery);
699   if(!watchQuery(networksQuery)) {
700     db.commit();
701     unlock();
702     return nets;
703   }
704
705   while(networksQuery.next()) {
706     NetworkInfo net;
707     net.networkId = networksQuery.value(0).toInt();
708     net.networkName = networksQuery.value(1).toString();
709     net.identity = networksQuery.value(2).toInt();
710     net.codecForServer = networksQuery.value(3).toString().toAscii();
711     net.codecForEncoding = networksQuery.value(4).toString().toAscii();
712     net.codecForDecoding = networksQuery.value(5).toString().toAscii();
713     net.useRandomServer = networksQuery.value(6).toInt() == 1 ? true : false;
714     net.perform = networksQuery.value(7).toString().split("\n");
715     net.useAutoIdentify = networksQuery.value(8).toInt() == 1 ? true : false;
716     net.autoIdentifyService = networksQuery.value(9).toString();
717     net.autoIdentifyPassword = networksQuery.value(10).toString();
718     net.useAutoReconnect = networksQuery.value(11).toInt() == 1 ? true : false;
719     net.autoReconnectInterval = networksQuery.value(12).toUInt();
720     net.autoReconnectRetries = networksQuery.value(13).toInt();
721     net.unlimitedReconnectRetries = networksQuery.value(14).toInt() == 1 ? true : false;
722     net.rejoinChannels = networksQuery.value(15).toInt() == 1 ? true : false;
723
724     serversQuery.bindValue(":networkid", net.networkId.toInt());
725     safeExec(serversQuery);
726     if(!watchQuery(serversQuery)) {
727       db.commit();
728       unlock();
729       return nets;
730     }
731
732     Network::ServerList servers;
733     while(serversQuery.next()) {
734       Network::Server server;
735       server.host = serversQuery.value(0).toString();
736       server.port = serversQuery.value(1).toUInt();
737       server.password = serversQuery.value(2).toString();
738       server.useSsl = serversQuery.value(3).toInt() == 1 ? true : false;
739       server.sslVersion = serversQuery.value(4).toInt();
740       server.useProxy = serversQuery.value(5).toInt() == 1 ? true : false;
741       server.proxyType = serversQuery.value(6).toInt();
742       server.proxyHost = serversQuery.value(7).toString();
743       server.proxyPort = serversQuery.value(8).toUInt();
744       server.proxyUser = serversQuery.value(9).toString();
745       server.proxyPass = serversQuery.value(10).toString();
746       servers << server;
747     }
748     net.serverList = servers;
749     nets << net;
750   }
751
752   db.commit();
753   unlock();
754   return nets;
755 }
756
757 QList<NetworkId> SqliteStorage::connectedNetworks(UserId user) {
758   QList<NetworkId> connectedNets;
759
760   QSqlDatabase db = logDb();
761   db.transaction();
762
763   QSqlQuery query(db);
764   query.prepare(queryString("select_connected_networks"));
765   query.bindValue(":userid", user.toInt());
766   lockForRead();
767   safeExec(query);
768   watchQuery(query);
769
770   while(query.next()) {
771     connectedNets << query.value(0).toInt();
772   }
773
774   db.commit();
775   unlock();
776   return connectedNets;
777 }
778
779 void SqliteStorage::setNetworkConnected(UserId user, const NetworkId &networkId, bool isConnected) {
780   QSqlDatabase db = logDb();
781   db.transaction();
782
783   QSqlQuery query(db);
784   query.prepare(queryString("update_network_connected"));
785   query.bindValue(":userid", user.toInt());
786   query.bindValue(":networkid", networkId.toInt());
787   query.bindValue(":connected", isConnected ? 1 : 0);
788
789   lockForWrite();
790   safeExec(query);
791   watchQuery(query);
792   db.commit();
793   unlock();
794 }
795
796 QHash<QString, QString> SqliteStorage::persistentChannels(UserId user, const NetworkId &networkId) {
797   QHash<QString, QString> persistentChans;
798
799   QSqlDatabase db = logDb();
800   db.transaction();
801
802   QSqlQuery query(db);
803   query.prepare(queryString("select_persistent_channels"));
804   query.bindValue(":userid", user.toInt());
805   query.bindValue(":networkid", networkId.toInt());
806
807   lockForRead();
808   safeExec(query);
809   watchQuery(query);
810   while(query.next()) {
811     persistentChans[query.value(0).toString()] = query.value(1).toString();
812   }
813   unlock();
814
815   return persistentChans;
816 }
817
818 void SqliteStorage::setChannelPersistent(UserId user, const NetworkId &networkId, const QString &channel, bool isJoined) {
819   QSqlDatabase db = logDb();
820   db.transaction();
821
822   QSqlQuery query(db);
823   query.prepare(queryString("update_buffer_persistent_channel"));
824   query.bindValue(":userid", user.toInt());
825   query.bindValue(":networkId", networkId.toInt());
826   query.bindValue(":buffercname", channel.toLower());
827   query.bindValue(":joined", isJoined ? 1 : 0);
828
829   lockForWrite();
830   safeExec(query);
831   watchQuery(query);
832   db.commit();
833   unlock();
834 }
835
836 void SqliteStorage::setPersistentChannelKey(UserId user, const NetworkId &networkId, const QString &channel, const QString &key) {
837   QSqlDatabase db = logDb();
838   db.transaction();
839
840   QSqlQuery query(db);
841   query.prepare(queryString("update_buffer_set_channel_key"));
842   query.bindValue(":userid", user.toInt());
843   query.bindValue(":networkId", networkId.toInt());
844   query.bindValue(":buffercname", channel.toLower());
845   query.bindValue(":key", key);
846
847   lockForWrite();
848   safeExec(query);
849   watchQuery(query);
850   db.commit();
851   unlock();
852 }
853
854 QString SqliteStorage::awayMessage(UserId user, NetworkId networkId) {
855   QSqlDatabase db = logDb();
856   db.transaction();
857
858   QSqlQuery query(db);
859   query.prepare(queryString("select_network_awaymsg"));
860   query.bindValue(":userid", user.toInt());
861   query.bindValue(":networkid", networkId.toInt());
862
863   lockForRead();
864   safeExec(query);
865   watchQuery(query);
866   QString awayMsg;
867   if(query.first())
868     awayMsg = query.value(0).toString();
869   db.commit();
870   unlock();
871
872   return awayMsg;
873 }
874
875 void SqliteStorage::setAwayMessage(UserId user, NetworkId networkId, const QString &awayMsg) {
876   QSqlDatabase db = logDb();
877   db.transaction();
878
879   QSqlQuery query(db);
880   query.prepare(queryString("update_network_set_awaymsg"));
881   query.bindValue(":userid", user.toInt());
882   query.bindValue(":networkid", networkId.toInt());
883   query.bindValue(":awaymsg", awayMsg);
884
885   lockForWrite();
886   safeExec(query);
887   watchQuery(query);
888   db.commit();
889   unlock();
890 }
891
892 QString SqliteStorage::userModes(UserId user, NetworkId networkId) {
893   QSqlDatabase db = logDb();
894   db.transaction();
895
896   QSqlQuery query(db);
897   query.prepare(queryString("select_network_usermode"));
898   query.bindValue(":userid", user.toInt());
899   query.bindValue(":networkid", networkId.toInt());
900
901   lockForRead();
902   safeExec(query);
903   watchQuery(query);
904   QString modes;
905   if(query.first())
906     modes = query.value(0).toString();
907   db.commit();
908   unlock();
909
910   return modes;
911 }
912
913 void SqliteStorage::setUserModes(UserId user, NetworkId networkId, const QString &userModes) {
914   QSqlDatabase db = logDb();
915   db.transaction();
916
917   QSqlQuery query(db);
918   query.prepare(queryString("update_network_set_usermode"));
919   query.bindValue(":userid", user.toInt());
920   query.bindValue(":networkid", networkId.toInt());
921   query.bindValue(":usermode", userModes);
922
923   lockForWrite();
924   safeExec(query);
925   watchQuery(query);
926   db.commit();
927   unlock();
928 }
929
930 BufferInfo SqliteStorage::bufferInfo(UserId user, const NetworkId &networkId, BufferInfo::Type type, const QString &buffer, bool create) {
931   QSqlDatabase db = logDb();
932   db.transaction();
933
934   QSqlQuery query(db);
935   query.prepare(queryString("select_bufferByName"));
936   query.bindValue(":networkid", networkId.toInt());
937   query.bindValue(":userid", user.toInt());
938   query.bindValue(":buffercname", buffer.toLower());
939
940   lockForRead();
941   safeExec(query);
942
943   if(query.first()) {
944     BufferInfo bufferInfo = BufferInfo(query.value(0).toInt(), networkId, (BufferInfo::Type)query.value(1).toInt(), 0, buffer);
945     if(query.next()) {
946       qCritical() << "SqliteStorage::getBufferInfo(): received more then one Buffer!";
947       qCritical() << "         Query:" << query.lastQuery();
948       qCritical() << "  bound Values:";
949       QList<QVariant> list = query.boundValues().values();
950       for (int i = 0; i < list.size(); ++i)
951         qCritical() << i << ":" << list.at(i).toString().toAscii().data();
952       Q_ASSERT(false);
953     }
954     db.commit();
955     unlock();
956     return bufferInfo;
957   } else if(create) {
958     // let's create the buffer
959     QSqlQuery createQuery(db);
960     createQuery.prepare(queryString("insert_buffer"));
961     createQuery.bindValue(":userid", user.toInt());
962     createQuery.bindValue(":networkid", networkId.toInt());
963     createQuery.bindValue(":buffertype", (int)type);
964     createQuery.bindValue(":buffername", buffer);
965     createQuery.bindValue(":buffercname", buffer.toLower());
966
967     unlock();
968     lockForWrite();
969     safeExec(createQuery);
970     watchQuery(createQuery);
971     BufferInfo bufferInfo = BufferInfo(createQuery.lastInsertId().toInt(), networkId, type, 0, buffer);
972     db.commit();
973     unlock();
974     return bufferInfo;
975   }
976
977   // neither found the buffer nor is its creation requested
978   db.commit();
979   unlock();
980   return BufferInfo();
981 }
982
983 BufferInfo SqliteStorage::getBufferInfo(UserId user, const BufferId &bufferId) {
984   QSqlDatabase db = logDb();
985   db.transaction();
986
987   QSqlQuery query(db);
988   query.prepare(queryString("select_buffer_by_id"));
989   query.bindValue(":userid", user.toInt());
990   query.bindValue(":bufferid", bufferId.toInt());
991
992   lockForRead();
993   safeExec(query);
994   if(!watchQuery(query) || !query.first()) {
995     db.commit();
996     unlock();
997     return BufferInfo();
998   }
999
1000   BufferInfo bufferInfo(query.value(0).toInt(), query.value(1).toInt(), (BufferInfo::Type)query.value(2).toInt(), 0, query.value(4).toString());
1001   Q_ASSERT(!query.next());
1002   db.commit();
1003   unlock();
1004   return bufferInfo;
1005 }
1006
1007 QList<BufferInfo> SqliteStorage::requestBuffers(UserId user) {
1008   QList<BufferInfo> bufferlist;
1009
1010   QSqlDatabase db = logDb();
1011   db.transaction();
1012
1013   QSqlQuery query(db);
1014   query.prepare(queryString("select_buffers"));
1015   query.bindValue(":userid", user.toInt());
1016
1017   lockForRead();
1018   safeExec(query);
1019   watchQuery(query);
1020   while(query.next()) {
1021     bufferlist << BufferInfo(query.value(0).toInt(), query.value(1).toInt(), (BufferInfo::Type)query.value(2).toInt(), query.value(3).toInt(), query.value(4).toString());
1022   }
1023   db.commit();
1024   unlock();
1025
1026   return bufferlist;
1027 }
1028
1029 QList<BufferId> SqliteStorage::requestBufferIdsForNetwork(UserId user, NetworkId networkId) {
1030   QList<BufferId> bufferList;
1031
1032   QSqlDatabase db = logDb();
1033   db.transaction();
1034
1035   QSqlQuery query(db);
1036   query.prepare(queryString("select_buffers_for_network"));
1037   query.bindValue(":networkid", networkId.toInt());
1038   query.bindValue(":userid", user.toInt());
1039
1040   lockForRead();
1041   safeExec(query);
1042   watchQuery(query);
1043   while(query.next()) {
1044     bufferList << BufferId(query.value(0).toInt());
1045   }
1046   db.commit();
1047   unlock();
1048
1049   return bufferList;
1050 }
1051
1052 bool SqliteStorage::removeBuffer(const UserId &user, const BufferId &bufferId) {
1053   QSqlDatabase db = logDb();
1054   db.transaction();
1055
1056   QSqlQuery delBufferQuery(db);
1057   delBufferQuery.prepare(queryString("delete_buffer_for_bufferid"));
1058   delBufferQuery.bindValue(":bufferid", bufferId.toInt());
1059   delBufferQuery.bindValue(":userid", user.toInt());
1060
1061   lockForWrite();
1062   safeExec(delBufferQuery);
1063   if(!watchQuery(delBufferQuery) || delBufferQuery.numRowsAffected() != 1) {
1064     db.rollback();
1065     unlock();
1066     return false;
1067   }
1068
1069   QSqlQuery delBacklogQuery(db);
1070   delBacklogQuery.prepare(queryString("delete_backlog_for_buffer"));
1071   delBacklogQuery.bindValue(":bufferid", bufferId.toInt());
1072   safeExec(delBacklogQuery);
1073   if(!watchQuery(delBacklogQuery)) {
1074     db.rollback();
1075     unlock();
1076     return false;
1077   }
1078
1079   db.commit();
1080   unlock();
1081   return true;
1082 }
1083
1084 bool SqliteStorage::renameBuffer(const UserId &user, const BufferId &bufferId, const QString &newName) {
1085   QSqlDatabase db = logDb();
1086   db.transaction();
1087
1088   QSqlQuery query(db);
1089   query.prepare(queryString("update_buffer_name"));
1090   query.bindValue(":buffername", newName);
1091   query.bindValue(":buffercname", newName.toLower());
1092   query.bindValue(":bufferid", bufferId.toInt());
1093   query.bindValue(":userid", user.toInt());
1094
1095   lockForWrite();
1096   safeExec(query);
1097   if(query.lastError().isValid()) {
1098     // unexepcted error occured (19 == constraint violation)
1099     if(query.lastError().number() != 19)
1100       watchQuery(query);
1101     db.rollback();
1102     unlock();
1103     return false;
1104   }
1105
1106   if(query.numRowsAffected() != 1) {
1107     db.rollback();
1108     unlock();
1109     return false;
1110   }
1111
1112   db.commit();
1113   unlock();
1114   return true;
1115 }
1116
1117 bool SqliteStorage::mergeBuffersPermanently(const UserId &user, const BufferId &bufferId1, const BufferId &bufferId2) {
1118   QSqlDatabase db = logDb();
1119   db.transaction();
1120
1121   QSqlQuery checkQuery(db);
1122   checkQuery.prepare(queryString("select_buffers_for_merge"));
1123   checkQuery.bindValue(":oldbufferid", bufferId2.toInt());
1124   checkQuery.bindValue(":newbufferid", bufferId1.toInt());
1125   checkQuery.bindValue(":userid", user.toInt());
1126
1127   lockForRead();
1128   safeExec(checkQuery);
1129   if(!checkQuery.first() || checkQuery.value(0).toInt() != 2) {
1130     db.rollback();
1131     unlock();
1132     return false;
1133   }
1134
1135   QSqlQuery query(db);
1136   query.prepare(queryString("update_backlog_bufferid"));
1137   query.bindValue(":oldbufferid", bufferId2.toInt());
1138   query.bindValue(":newbufferid", bufferId1.toInt());
1139   safeExec(query);
1140   if(!watchQuery(query)) {
1141     db.rollback();
1142     unlock();
1143     return false;
1144   }
1145
1146   QSqlQuery delBufferQuery(db);
1147   delBufferQuery.prepare(queryString("delete_buffer_for_bufferid"));
1148   delBufferQuery.bindValue(":bufferid", bufferId2.toInt());
1149   safeExec(delBufferQuery);
1150   if(!watchQuery(delBufferQuery)) {
1151     db.rollback();
1152     unlock();
1153     return false;
1154   }
1155
1156   db.commit();
1157   unlock();
1158   return true;
1159 }
1160
1161 void SqliteStorage::setBufferLastSeenMsg(UserId user, const BufferId &bufferId, const MsgId &msgId) {
1162   QSqlDatabase db = logDb();
1163   db.transaction();
1164
1165   QSqlQuery query(db);
1166   query.prepare(queryString("update_buffer_lastseen"));
1167   query.bindValue(":userid", user.toInt());
1168   query.bindValue(":bufferid", bufferId.toInt());
1169   query.bindValue(":lastseenmsgid", msgId.toInt());
1170
1171   lockForWrite();
1172   safeExec(query);
1173   watchQuery(query);
1174   db.commit();
1175   unlock();
1176 }
1177
1178 QHash<BufferId, MsgId> SqliteStorage::bufferLastSeenMsgIds(UserId user) {
1179   QHash<BufferId, MsgId> lastSeenHash;
1180
1181   QSqlDatabase db = logDb();
1182   db.transaction();
1183
1184   QSqlQuery query(db);
1185   query.prepare(queryString("select_buffer_lastseen_messages"));
1186   query.bindValue(":userid", user.toInt());
1187
1188   lockForRead();
1189   safeExec(query);
1190   if(!watchQuery(query)) {
1191     db.commit();
1192     unlock();
1193     return lastSeenHash;
1194   }
1195
1196   while(query.next()) {
1197     lastSeenHash[query.value(0).toInt()] = query.value(1).toInt();
1198   }
1199   db.commit();
1200   unlock();
1201
1202   return lastSeenHash;
1203 }
1204
1205 bool SqliteStorage::logMessage(Message &msg) {
1206   QSqlDatabase db = logDb();
1207   db.transaction();
1208
1209   QSqlQuery logMessageQuery(db);
1210   logMessageQuery.prepare(queryString("insert_message"));
1211
1212   logMessageQuery.bindValue(":time", msg.timestamp().toTime_t());
1213   logMessageQuery.bindValue(":bufferid", msg.bufferInfo().bufferId().toInt());
1214   logMessageQuery.bindValue(":type", msg.type());
1215   logMessageQuery.bindValue(":flags", (int)msg.flags());
1216   logMessageQuery.bindValue(":sender", msg.sender());
1217   logMessageQuery.bindValue(":message", msg.contents());
1218
1219   lockForWrite();
1220   safeExec(logMessageQuery);
1221
1222   if(logMessageQuery.lastError().isValid()) {
1223     // constraint violation - must be NOT NULL constraint - probably the sender is missing...
1224     if(logMessageQuery.lastError().number() == 19) {
1225       QSqlQuery addSenderQuery(db);
1226       addSenderQuery.prepare(queryString("insert_sender"));
1227       addSenderQuery.bindValue(":sender", msg.sender());
1228       safeExec(addSenderQuery);
1229       safeExec(logMessageQuery);
1230       if(!watchQuery(logMessageQuery)) {
1231         db.rollback();
1232         unlock();
1233         return false;
1234       }
1235     } else {
1236       watchQuery(logMessageQuery);
1237     }
1238   }
1239
1240   MsgId msgId = logMessageQuery.lastInsertId().toInt();
1241   if(msgId.isValid()) {
1242     msg.setMsgId(msgId);
1243     db.commit();
1244     unlock();
1245     return true;
1246   } else {
1247     db.rollback();
1248     unlock();
1249     return false;
1250   }
1251 }
1252
1253 bool SqliteStorage::logMessages(MessageList &msgs) {
1254   QSqlDatabase db = logDb();
1255   db.transaction();
1256
1257   QSet<QString> senders;
1258
1259   QSqlQuery addSenderQuery(db);
1260   addSenderQuery.prepare(queryString("insert_sender"));
1261   lockForWrite();
1262   for(int i = 0; i < msgs.count(); i++) {
1263     const QString &sender = msgs.at(i).sender();
1264     if(senders.contains(sender))
1265       continue;
1266     senders << sender;
1267
1268     addSenderQuery.bindValue(":sender", sender);
1269     safeExec(addSenderQuery);
1270   }
1271
1272   QSqlQuery logMessageQuery(db);
1273   logMessageQuery.prepare(queryString("insert_message"));
1274   bool error = false;
1275   for(int i = 0; i < msgs.count(); i++) {
1276     Message &msg = msgs[i];
1277
1278     logMessageQuery.bindValue(":time", msg.timestamp().toTime_t());
1279     logMessageQuery.bindValue(":bufferid", msg.bufferInfo().bufferId().toInt());
1280     logMessageQuery.bindValue(":type", msg.type());
1281     logMessageQuery.bindValue(":flags", (int)msg.flags());
1282     logMessageQuery.bindValue(":sender", msg.sender());
1283     logMessageQuery.bindValue(":message", msg.contents());
1284
1285     safeExec(logMessageQuery);
1286     if(!watchQuery(logMessageQuery)) {
1287       db.rollback();
1288       unlock();
1289       error = true;
1290       break;
1291     } else {
1292       msg.setMsgId(logMessageQuery.lastInsertId().toInt());
1293     }
1294   }
1295
1296   if(error) {
1297     // we had a rollback in the db so we need to reset all msgIds
1298     for(int i = 0; i < msgs.count(); i++) {
1299       msgs[i].setMsgId(MsgId());
1300     }
1301     return false;
1302   }
1303
1304   db.commit();
1305   unlock();
1306   return true;
1307 }
1308
1309 QList<Message> SqliteStorage::requestMsgs(UserId user, BufferId bufferId, MsgId first, MsgId last, int limit) {
1310   QList<Message> messagelist;
1311
1312   QSqlDatabase db = logDb();
1313   db.transaction();
1314
1315   // code dupication from getBufferInfo:
1316   // this is due to the impossibility of nesting transactions and recursive locking
1317   QSqlQuery bufferInfoQuery(db);
1318   bufferInfoQuery.prepare(queryString("select_buffer_by_id"));
1319   bufferInfoQuery.bindValue(":userid", user.toInt());
1320   bufferInfoQuery.bindValue(":bufferid", bufferId.toInt());
1321
1322   lockForRead();
1323   safeExec(bufferInfoQuery);
1324   if(!watchQuery(bufferInfoQuery) || !bufferInfoQuery.first()) {
1325     db.commit();
1326     unlock();
1327     return messagelist;
1328   }
1329
1330   BufferInfo bufferInfo(bufferInfoQuery.value(0).toInt(), bufferInfoQuery.value(1).toInt(), (BufferInfo::Type)bufferInfoQuery.value(2).toInt(), 0, bufferInfoQuery.value(4).toString());
1331   if(!bufferInfo.isValid()) {
1332     db.commit();
1333     unlock();
1334     return messagelist;
1335   }
1336
1337   QSqlQuery query(db);
1338   if(last == -1 && first == -1) {
1339     query.prepare(queryString("select_messagesNewestK"));
1340   } else if(last == -1) {
1341     query.prepare(queryString("select_messagesNewerThan"));
1342     query.bindValue(":firstmsg", first.toInt());
1343   } else {
1344     query.prepare(queryString("select_messages"));
1345     query.bindValue(":lastmsg", last.toInt());
1346     query.bindValue(":firstmsg", first.toInt());
1347   }
1348   query.bindValue(":bufferid", bufferId.toInt());
1349   query.bindValue(":limit", limit);
1350
1351   safeExec(query);
1352   watchQuery(query);
1353
1354   while(query.next()) {
1355     Message msg(QDateTime::fromTime_t(query.value(1).toInt()),
1356                 bufferInfo,
1357                 (Message::Type)query.value(2).toUInt(),
1358                 query.value(5).toString(),
1359                 query.value(4).toString(),
1360                 (Message::Flags)query.value(3).toUInt());
1361     msg.setMsgId(query.value(0).toInt());
1362     messagelist << msg;
1363   }
1364   db.commit();
1365   unlock();
1366
1367   return messagelist;
1368 }
1369
1370 QList<Message> SqliteStorage::requestAllMsgs(UserId user, MsgId first, MsgId last, int limit) {
1371   QList<Message> messagelist;
1372
1373   QSqlDatabase db = logDb();
1374   db.transaction();
1375
1376   QHash<BufferId, BufferInfo> bufferInfoHash;
1377   QSqlQuery bufferInfoQuery(db);
1378   bufferInfoQuery.prepare(queryString("select_buffers"));
1379   bufferInfoQuery.bindValue(":userid", user.toInt());
1380
1381   lockForRead();
1382   safeExec(bufferInfoQuery);
1383   watchQuery(bufferInfoQuery);
1384   while(bufferInfoQuery.next()) {
1385     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());
1386     bufferInfoHash[bufferInfo.bufferId()] = bufferInfo;
1387   }
1388
1389   QSqlQuery query(db);
1390   if(last == -1) {
1391     query.prepare(queryString("select_messagesAllNew"));
1392   } else {
1393     query.prepare(queryString("select_messagesAll"));
1394     query.bindValue(":lastmsg", last.toInt());
1395   }
1396   query.bindValue(":userid", user.toInt());
1397   query.bindValue(":firstmsg", first.toInt());
1398   query.bindValue(":limit", limit);
1399   safeExec(query);
1400
1401   watchQuery(query);
1402
1403   while(query.next()) {
1404     Message msg(QDateTime::fromTime_t(query.value(2).toInt()),
1405                 bufferInfoHash[query.value(1).toInt()],
1406                 (Message::Type)query.value(3).toUInt(),
1407                 query.value(6).toString(),
1408                 query.value(5).toString(),
1409                 (Message::Flags)query.value(4).toUInt());
1410     msg.setMsgId(query.value(0).toInt());
1411     messagelist << msg;
1412   }
1413
1414   db.commit();
1415   unlock();
1416   return messagelist;
1417 }
1418
1419 QString SqliteStorage::backlogFile() {
1420   return Quassel::configDirPath() + "quassel-storage.sqlite";
1421 }
1422
1423 bool SqliteStorage::safeExec(QSqlQuery &query, int retryCount) {
1424   query.exec();
1425
1426   if(!query.lastError().isValid())
1427     return true;
1428
1429   switch(query.lastError().number()) {
1430   case 5: // SQLITE_BUSY         5   /* The database file is locked */
1431   case 6: // SQLITE_LOCKED       6   /* A table in the database is locked */
1432     if(retryCount < _maxRetryCount)
1433       return safeExec(query, retryCount + 1);
1434   default:
1435     return false;
1436   }
1437 }
1438
1439
1440 // ========================================
1441 //  SqliteMigration
1442 // ========================================
1443 SqliteMigrationReader::SqliteMigrationReader()
1444   : SqliteStorage(),
1445     _maxId(0)
1446 {
1447 }
1448
1449 void SqliteMigrationReader::setMaxId(MigrationObject mo) {
1450   QString queryString;
1451   switch(mo) {
1452   case Sender:
1453     queryString = "SELECT max(senderid) FROM sender";
1454     break;
1455   case Backlog:
1456     queryString = "SELECT max(messageid) FROM backlog";
1457     break;
1458   default:
1459     _maxId = 0;
1460     return;
1461   }
1462   QSqlQuery query = logDb().exec(queryString);
1463   query.first();
1464   _maxId = query.value(0).toInt();
1465 }
1466
1467 bool SqliteMigrationReader::prepareQuery(MigrationObject mo) {
1468   setMaxId(mo);
1469
1470   switch(mo) {
1471   case QuasselUser:
1472     newQuery(queryString("migrate_read_quasseluser"), logDb());
1473     break;
1474   case Identity:
1475     newQuery(queryString("migrate_read_identity"), logDb());
1476     break;
1477   case IdentityNick:
1478     newQuery(queryString("migrate_read_identity_nick"), logDb());
1479     break;
1480   case Network:
1481     newQuery(queryString("migrate_read_network"), logDb());
1482     break;
1483   case Buffer:
1484     newQuery(queryString("migrate_read_buffer"), logDb());
1485     break;
1486   case Sender:
1487     newQuery(queryString("migrate_read_sender"), logDb());
1488     bindValue(0, 0);
1489     bindValue(1, stepSize());
1490     break;
1491   case Backlog:
1492     newQuery(queryString("migrate_read_backlog"), logDb());
1493     bindValue(0, 0);
1494     bindValue(1, stepSize());
1495     break;
1496   case IrcServer:
1497     newQuery(queryString("migrate_read_ircserver"), logDb());
1498     break;
1499   case UserSetting:
1500     newQuery(queryString("migrate_read_usersetting"), logDb());
1501     break;
1502   }
1503   return exec();
1504 }
1505
1506 bool SqliteMigrationReader::readMo(QuasselUserMO &user) {
1507   if(!next())
1508     return false;
1509
1510   user.id = value(0).toInt();
1511   user.username = value(1).toString();
1512   user.password = value(2).toString();
1513   return true;
1514 }
1515
1516 bool SqliteMigrationReader::readMo(IdentityMO &identity) {
1517   if(!next())
1518     return false;
1519
1520   identity.id = value(0).toInt();
1521   identity.userid = value(1).toInt();
1522   identity.identityname = value(2).toString();
1523   identity.realname = value(3).toString();
1524   identity.awayNick = value(4).toString();
1525   identity.awayNickEnabled = value(5).toInt() == 1 ? true : false;
1526   identity.awayReason = value(6).toString();
1527   identity.awayReasonEnabled = value(7).toInt() == 1 ? true : false;
1528   identity.autoAwayEnabled = value(8).toInt() == 1 ? true : false;
1529   identity.autoAwayTime = value(9).toInt();
1530   identity.autoAwayReason = value(10).toString();
1531   identity.autoAwayReasonEnabled = value(11).toInt() == 1 ? true : false;
1532   identity.detachAwayEnabled = value(12).toInt() == 1 ? true : false;
1533   identity.detachAwayReason = value(13).toString();
1534   identity.detchAwayReasonEnabled = value(14).toInt() == 1 ? true : false;
1535   identity.ident = value(15).toString();
1536   identity.kickReason = value(16).toString();
1537   identity.partReason = value(17).toString();
1538   identity.quitReason = value(18).toString();
1539   identity.sslCert = value(19).toByteArray();
1540   identity.sslKey = value(20).toByteArray();
1541   return true;
1542 }
1543
1544 bool SqliteMigrationReader::readMo(IdentityNickMO &identityNick) {
1545   if(!next())
1546     return false;
1547
1548   identityNick.nickid = value(0).toInt();
1549   identityNick.identityId = value(1).toInt();
1550   identityNick.nick = value(2).toString();
1551   return true;
1552 }
1553
1554 bool SqliteMigrationReader::readMo(NetworkMO &network) {
1555   if(!next())
1556     return false;
1557
1558   network.networkid = value(0).toInt();
1559   network.userid = value(1).toInt();
1560   network.networkname = value(2).toString();
1561   network.identityid = value(3).toInt();
1562   network.encodingcodec = value(4).toString();
1563   network.decodingcodec = value(5).toString();
1564   network.servercodec = value(6).toString();
1565   network.userandomserver = value(7).toInt() == 1 ? true : false;
1566   network.perform = value(8).toString();
1567   network.useautoidentify = value(9).toInt() == 1 ? true : false;
1568   network.autoidentifyservice = value(10).toString();
1569   network.autoidentifypassword = value(11).toString();
1570   network.useautoreconnect = value(12).toInt() == 1 ? true : false;
1571   network.autoreconnectinterval = value(13).toInt();
1572   network.autoreconnectretries = value(14).toInt();
1573   network.unlimitedconnectretries = value(15).toInt() == 1 ? true : false;
1574   network.rejoinchannels = value(16).toInt() == 1 ? true : false;
1575   network.connected = value(17).toInt() == 1 ? true : false;
1576   network.usermode = value(18).toString();
1577   network.awaymessage = value(19).toString();
1578   network.attachperform = value(20).toString();
1579   network.detachperform = value(21).toString();
1580   return true;
1581 }
1582
1583 bool SqliteMigrationReader::readMo(BufferMO &buffer) {
1584   if(!next())
1585     return false;
1586
1587   buffer.bufferid = value(0).toInt();
1588   buffer.userid = value(1).toInt();
1589   buffer.groupid = value(2).toInt();
1590   buffer.networkid = value(3).toInt();
1591   buffer.buffername = value(4).toString();
1592   buffer.buffercname = value(5).toString();
1593   buffer.buffertype = value(6).toInt();
1594   buffer.lastseenmsgid = value(7).toInt();
1595   buffer.key = value(8).toString();
1596   buffer.joined = value(9).toInt() == 1 ? true : false;
1597   return true;
1598 }
1599
1600 bool SqliteMigrationReader::readMo(SenderMO &sender) {
1601   int skipSteps = 0;
1602   while(!next()) {
1603     if(sender.senderId < _maxId) {
1604       bindValue(0, sender.senderId + (skipSteps * stepSize()));
1605       bindValue(1, sender.senderId + ((skipSteps + 1) * stepSize()));
1606       skipSteps++;
1607       if(!exec())
1608         return false;
1609     } else {
1610       return false;
1611     }
1612   }
1613
1614   sender.senderId = value(0).toInt();
1615   sender.sender = value(1).toString();
1616   return true;
1617 }
1618
1619 bool SqliteMigrationReader::readMo(BacklogMO &backlog) {
1620   int skipSteps = 0;
1621   while(!next()) {
1622     if(backlog.messageid < _maxId) {
1623       bindValue(0, backlog.messageid.toInt() + (skipSteps * stepSize()));
1624       bindValue(1, backlog.messageid.toInt() + ((skipSteps + 1) * stepSize()));
1625       skipSteps++;
1626       if(!exec())
1627         return false;
1628     } else {
1629       return false;
1630     }
1631   }
1632
1633   backlog.messageid = value(0).toInt();
1634   backlog.time = QDateTime::fromTime_t(value(1).toInt());
1635   backlog.bufferid = value(2).toInt();
1636   backlog.type = value(3).toInt();
1637   backlog.flags = value(4).toInt();
1638   backlog.senderid = value(5).toInt();
1639   backlog.message = value(6).toString();
1640   return true;
1641 }
1642
1643 bool SqliteMigrationReader::readMo(IrcServerMO &ircserver) {
1644   if(!next())
1645     return false;
1646
1647   ircserver.serverid = value(0).toInt();
1648   ircserver.userid = value(1).toInt();
1649   ircserver.networkid = value(2).toInt();
1650   ircserver.hostname = value(3).toString();
1651   ircserver.port = value(4).toInt();
1652   ircserver.password = value(5).toString();
1653   ircserver.ssl = value(6).toInt() == 1 ? true : false;
1654   ircserver.sslversion = value(7).toInt();
1655   ircserver.useproxy = value(8).toInt() == 1 ? true : false;
1656   ircserver.proxytype = value(9).toInt();
1657   ircserver.proxyhost = value(10).toString();
1658   ircserver.proxyport = value(11).toInt();
1659   ircserver.proxyuser = value(12).toString();
1660   ircserver.proxypass = value(13).toString();
1661   return true;
1662 }
1663
1664 bool SqliteMigrationReader::readMo(UserSettingMO &userSetting) {
1665   if(!next())
1666     return false;
1667
1668   userSetting.userid = value(0).toInt();
1669   userSetting.settingname = value(1).toString();
1670   userSetting.settingvalue = value(2).toByteArray();
1671
1672   return true;
1673 }