Fixed some indentation issues (and a typo).
[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   delBufferQuery.bindValue(":userid", user.toInt());
1150   safeExec(delBufferQuery);
1151   if(!watchQuery(delBufferQuery)) {
1152     db.rollback();
1153     unlock();
1154     return false;
1155   }
1156
1157   db.commit();
1158   unlock();
1159   return true;
1160 }
1161
1162 void SqliteStorage::setBufferLastSeenMsg(UserId user, const BufferId &bufferId, const MsgId &msgId) {
1163   QSqlDatabase db = logDb();
1164   db.transaction();
1165
1166   QSqlQuery query(db);
1167   query.prepare(queryString("update_buffer_lastseen"));
1168   query.bindValue(":userid", user.toInt());
1169   query.bindValue(":bufferid", bufferId.toInt());
1170   query.bindValue(":lastseenmsgid", msgId.toInt());
1171
1172   lockForWrite();
1173   safeExec(query);
1174   watchQuery(query);
1175   db.commit();
1176   unlock();
1177 }
1178
1179 QHash<BufferId, MsgId> SqliteStorage::bufferLastSeenMsgIds(UserId user) {
1180   QHash<BufferId, MsgId> lastSeenHash;
1181
1182   QSqlDatabase db = logDb();
1183   db.transaction();
1184
1185   QSqlQuery query(db);
1186   query.prepare(queryString("select_buffer_lastseen_messages"));
1187   query.bindValue(":userid", user.toInt());
1188
1189   lockForRead();
1190   safeExec(query);
1191   if(!watchQuery(query)) {
1192     db.commit();
1193     unlock();
1194     return lastSeenHash;
1195   }
1196
1197   while(query.next()) {
1198     lastSeenHash[query.value(0).toInt()] = query.value(1).toInt();
1199   }
1200   db.commit();
1201   unlock();
1202
1203   return lastSeenHash;
1204 }
1205
1206 bool SqliteStorage::logMessage(Message &msg) {
1207   QSqlDatabase db = logDb();
1208   db.transaction();
1209
1210   QSqlQuery logMessageQuery(db);
1211   logMessageQuery.prepare(queryString("insert_message"));
1212
1213   logMessageQuery.bindValue(":time", msg.timestamp().toTime_t());
1214   logMessageQuery.bindValue(":bufferid", msg.bufferInfo().bufferId().toInt());
1215   logMessageQuery.bindValue(":type", msg.type());
1216   logMessageQuery.bindValue(":flags", (int)msg.flags());
1217   logMessageQuery.bindValue(":sender", msg.sender());
1218   logMessageQuery.bindValue(":message", msg.contents());
1219
1220   lockForWrite();
1221   safeExec(logMessageQuery);
1222
1223   if(logMessageQuery.lastError().isValid()) {
1224     // constraint violation - must be NOT NULL constraint - probably the sender is missing...
1225     if(logMessageQuery.lastError().number() == 19) {
1226       QSqlQuery addSenderQuery(db);
1227       addSenderQuery.prepare(queryString("insert_sender"));
1228       addSenderQuery.bindValue(":sender", msg.sender());
1229       safeExec(addSenderQuery);
1230       safeExec(logMessageQuery);
1231       if(!watchQuery(logMessageQuery)) {
1232         db.rollback();
1233         unlock();
1234         return false;
1235       }
1236     } else {
1237       watchQuery(logMessageQuery);
1238     }
1239   }
1240
1241   MsgId msgId = logMessageQuery.lastInsertId().toInt();
1242   if(msgId.isValid()) {
1243     msg.setMsgId(msgId);
1244     db.commit();
1245     unlock();
1246     return true;
1247   } else {
1248     db.rollback();
1249     unlock();
1250     return false;
1251   }
1252 }
1253
1254 bool SqliteStorage::logMessages(MessageList &msgs) {
1255   QSqlDatabase db = logDb();
1256   db.transaction();
1257
1258   QSet<QString> senders;
1259
1260   QSqlQuery addSenderQuery(db);
1261   addSenderQuery.prepare(queryString("insert_sender"));
1262   lockForWrite();
1263   for(int i = 0; i < msgs.count(); i++) {
1264     const QString &sender = msgs.at(i).sender();
1265     if(senders.contains(sender))
1266       continue;
1267     senders << sender;
1268
1269     addSenderQuery.bindValue(":sender", sender);
1270     safeExec(addSenderQuery);
1271   }
1272
1273   QSqlQuery logMessageQuery(db);
1274   logMessageQuery.prepare(queryString("insert_message"));
1275   bool error = false;
1276   for(int i = 0; i < msgs.count(); i++) {
1277     Message &msg = msgs[i];
1278
1279     logMessageQuery.bindValue(":time", msg.timestamp().toTime_t());
1280     logMessageQuery.bindValue(":bufferid", msg.bufferInfo().bufferId().toInt());
1281     logMessageQuery.bindValue(":type", msg.type());
1282     logMessageQuery.bindValue(":flags", (int)msg.flags());
1283     logMessageQuery.bindValue(":sender", msg.sender());
1284     logMessageQuery.bindValue(":message", msg.contents());
1285
1286     safeExec(logMessageQuery);
1287     if(!watchQuery(logMessageQuery)) {
1288       db.rollback();
1289       unlock();
1290       error = true;
1291       break;
1292     } else {
1293       msg.setMsgId(logMessageQuery.lastInsertId().toInt());
1294     }
1295   }
1296
1297   if(error) {
1298     // we had a rollback in the db so we need to reset all msgIds
1299     for(int i = 0; i < msgs.count(); i++) {
1300       msgs[i].setMsgId(MsgId());
1301     }
1302     return false;
1303   }
1304
1305   db.commit();
1306   unlock();
1307   return true;
1308 }
1309
1310 QList<Message> SqliteStorage::requestMsgs(UserId user, BufferId bufferId, MsgId first, MsgId last, int limit) {
1311   QList<Message> messagelist;
1312
1313   QSqlDatabase db = logDb();
1314   db.transaction();
1315
1316   // code dupication from getBufferInfo:
1317   // this is due to the impossibility of nesting transactions and recursive locking
1318   QSqlQuery bufferInfoQuery(db);
1319   bufferInfoQuery.prepare(queryString("select_buffer_by_id"));
1320   bufferInfoQuery.bindValue(":userid", user.toInt());
1321   bufferInfoQuery.bindValue(":bufferid", bufferId.toInt());
1322
1323   lockForRead();
1324   safeExec(bufferInfoQuery);
1325   if(!watchQuery(bufferInfoQuery) || !bufferInfoQuery.first()) {
1326     db.commit();
1327     unlock();
1328     return messagelist;
1329   }
1330
1331   BufferInfo bufferInfo(bufferInfoQuery.value(0).toInt(), bufferInfoQuery.value(1).toInt(), (BufferInfo::Type)bufferInfoQuery.value(2).toInt(), 0, bufferInfoQuery.value(4).toString());
1332   if(!bufferInfo.isValid()) {
1333     db.commit();
1334     unlock();
1335     return messagelist;
1336   }
1337
1338   QSqlQuery query(db);
1339   if(last == -1 && first == -1) {
1340     query.prepare(queryString("select_messagesNewestK"));
1341   } else if(last == -1) {
1342     query.prepare(queryString("select_messagesNewerThan"));
1343     query.bindValue(":firstmsg", first.toInt());
1344   } else {
1345     query.prepare(queryString("select_messages"));
1346     query.bindValue(":lastmsg", last.toInt());
1347     query.bindValue(":firstmsg", first.toInt());
1348   }
1349   query.bindValue(":bufferid", bufferId.toInt());
1350   query.bindValue(":limit", limit);
1351
1352   safeExec(query);
1353   watchQuery(query);
1354
1355   while(query.next()) {
1356     Message msg(QDateTime::fromTime_t(query.value(1).toInt()),
1357                 bufferInfo,
1358                 (Message::Type)query.value(2).toUInt(),
1359                 query.value(5).toString(),
1360                 query.value(4).toString(),
1361                 (Message::Flags)query.value(3).toUInt());
1362     msg.setMsgId(query.value(0).toInt());
1363     messagelist << msg;
1364   }
1365   db.commit();
1366   unlock();
1367
1368   return messagelist;
1369 }
1370
1371 QList<Message> SqliteStorage::requestAllMsgs(UserId user, MsgId first, MsgId last, int limit) {
1372   QList<Message> messagelist;
1373
1374   QSqlDatabase db = logDb();
1375   db.transaction();
1376
1377   QHash<BufferId, BufferInfo> bufferInfoHash;
1378   QSqlQuery bufferInfoQuery(db);
1379   bufferInfoQuery.prepare(queryString("select_buffers"));
1380   bufferInfoQuery.bindValue(":userid", user.toInt());
1381
1382   lockForRead();
1383   safeExec(bufferInfoQuery);
1384   watchQuery(bufferInfoQuery);
1385   while(bufferInfoQuery.next()) {
1386     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());
1387     bufferInfoHash[bufferInfo.bufferId()] = bufferInfo;
1388   }
1389
1390   QSqlQuery query(db);
1391   if(last == -1) {
1392     query.prepare(queryString("select_messagesAllNew"));
1393   } else {
1394     query.prepare(queryString("select_messagesAll"));
1395     query.bindValue(":lastmsg", last.toInt());
1396   }
1397   query.bindValue(":userid", user.toInt());
1398   query.bindValue(":firstmsg", first.toInt());
1399   query.bindValue(":limit", limit);
1400   safeExec(query);
1401
1402   watchQuery(query);
1403
1404   while(query.next()) {
1405     Message msg(QDateTime::fromTime_t(query.value(2).toInt()),
1406                 bufferInfoHash[query.value(1).toInt()],
1407                 (Message::Type)query.value(3).toUInt(),
1408                 query.value(6).toString(),
1409                 query.value(5).toString(),
1410                 (Message::Flags)query.value(4).toUInt());
1411     msg.setMsgId(query.value(0).toInt());
1412     messagelist << msg;
1413   }
1414
1415   db.commit();
1416   unlock();
1417   return messagelist;
1418 }
1419
1420 QString SqliteStorage::backlogFile() {
1421   return Quassel::configDirPath() + "quassel-storage.sqlite";
1422 }
1423
1424 bool SqliteStorage::safeExec(QSqlQuery &query, int retryCount) {
1425   query.exec();
1426
1427   if(!query.lastError().isValid())
1428     return true;
1429
1430   switch(query.lastError().number()) {
1431   case 5: // SQLITE_BUSY         5   /* The database file is locked */
1432   case 6: // SQLITE_LOCKED       6   /* A table in the database is locked */
1433     if(retryCount < _maxRetryCount)
1434       return safeExec(query, retryCount + 1);
1435   default:
1436     return false;
1437   }
1438 }
1439
1440
1441 // ========================================
1442 //  SqliteMigration
1443 // ========================================
1444 SqliteMigrationReader::SqliteMigrationReader()
1445   : SqliteStorage(),
1446     _maxId(0)
1447 {
1448 }
1449
1450 void SqliteMigrationReader::setMaxId(MigrationObject mo) {
1451   QString queryString;
1452   switch(mo) {
1453   case Sender:
1454     queryString = "SELECT max(senderid) FROM sender";
1455     break;
1456   case Backlog:
1457     queryString = "SELECT max(messageid) FROM backlog";
1458     break;
1459   default:
1460     _maxId = 0;
1461     return;
1462   }
1463   QSqlQuery query = logDb().exec(queryString);
1464   query.first();
1465   _maxId = query.value(0).toInt();
1466 }
1467
1468 bool SqliteMigrationReader::prepareQuery(MigrationObject mo) {
1469   setMaxId(mo);
1470
1471   switch(mo) {
1472   case QuasselUser:
1473     newQuery(queryString("migrate_read_quasseluser"), logDb());
1474     break;
1475   case Identity:
1476     newQuery(queryString("migrate_read_identity"), logDb());
1477     break;
1478   case IdentityNick:
1479     newQuery(queryString("migrate_read_identity_nick"), logDb());
1480     break;
1481   case Network:
1482     newQuery(queryString("migrate_read_network"), logDb());
1483     break;
1484   case Buffer:
1485     newQuery(queryString("migrate_read_buffer"), logDb());
1486     break;
1487   case Sender:
1488     newQuery(queryString("migrate_read_sender"), logDb());
1489     bindValue(0, 0);
1490     bindValue(1, stepSize());
1491     break;
1492   case Backlog:
1493     newQuery(queryString("migrate_read_backlog"), logDb());
1494     bindValue(0, 0);
1495     bindValue(1, stepSize());
1496     break;
1497   case IrcServer:
1498     newQuery(queryString("migrate_read_ircserver"), logDb());
1499     break;
1500   case UserSetting:
1501     newQuery(queryString("migrate_read_usersetting"), logDb());
1502     break;
1503   }
1504   return exec();
1505 }
1506
1507 bool SqliteMigrationReader::readMo(QuasselUserMO &user) {
1508   if(!next())
1509     return false;
1510
1511   user.id = value(0).toInt();
1512   user.username = value(1).toString();
1513   user.password = value(2).toString();
1514   return true;
1515 }
1516
1517 bool SqliteMigrationReader::readMo(IdentityMO &identity) {
1518   if(!next())
1519     return false;
1520
1521   identity.id = value(0).toInt();
1522   identity.userid = value(1).toInt();
1523   identity.identityname = value(2).toString();
1524   identity.realname = value(3).toString();
1525   identity.awayNick = value(4).toString();
1526   identity.awayNickEnabled = value(5).toInt() == 1 ? true : false;
1527   identity.awayReason = value(6).toString();
1528   identity.awayReasonEnabled = value(7).toInt() == 1 ? true : false;
1529   identity.autoAwayEnabled = value(8).toInt() == 1 ? true : false;
1530   identity.autoAwayTime = value(9).toInt();
1531   identity.autoAwayReason = value(10).toString();
1532   identity.autoAwayReasonEnabled = value(11).toInt() == 1 ? true : false;
1533   identity.detachAwayEnabled = value(12).toInt() == 1 ? true : false;
1534   identity.detachAwayReason = value(13).toString();
1535   identity.detchAwayReasonEnabled = value(14).toInt() == 1 ? true : false;
1536   identity.ident = value(15).toString();
1537   identity.kickReason = value(16).toString();
1538   identity.partReason = value(17).toString();
1539   identity.quitReason = value(18).toString();
1540   identity.sslCert = value(19).toByteArray();
1541   identity.sslKey = value(20).toByteArray();
1542   return true;
1543 }
1544
1545 bool SqliteMigrationReader::readMo(IdentityNickMO &identityNick) {
1546   if(!next())
1547     return false;
1548
1549   identityNick.nickid = value(0).toInt();
1550   identityNick.identityId = value(1).toInt();
1551   identityNick.nick = value(2).toString();
1552   return true;
1553 }
1554
1555 bool SqliteMigrationReader::readMo(NetworkMO &network) {
1556   if(!next())
1557     return false;
1558
1559   network.networkid = value(0).toInt();
1560   network.userid = value(1).toInt();
1561   network.networkname = value(2).toString();
1562   network.identityid = value(3).toInt();
1563   network.encodingcodec = value(4).toString();
1564   network.decodingcodec = value(5).toString();
1565   network.servercodec = value(6).toString();
1566   network.userandomserver = value(7).toInt() == 1 ? true : false;
1567   network.perform = value(8).toString();
1568   network.useautoidentify = value(9).toInt() == 1 ? true : false;
1569   network.autoidentifyservice = value(10).toString();
1570   network.autoidentifypassword = value(11).toString();
1571   network.useautoreconnect = value(12).toInt() == 1 ? true : false;
1572   network.autoreconnectinterval = value(13).toInt();
1573   network.autoreconnectretries = value(14).toInt();
1574   network.unlimitedconnectretries = value(15).toInt() == 1 ? true : false;
1575   network.rejoinchannels = value(16).toInt() == 1 ? true : false;
1576   network.connected = value(17).toInt() == 1 ? true : false;
1577   network.usermode = value(18).toString();
1578   network.awaymessage = value(19).toString();
1579   network.attachperform = value(20).toString();
1580   network.detachperform = value(21).toString();
1581   return true;
1582 }
1583
1584 bool SqliteMigrationReader::readMo(BufferMO &buffer) {
1585   if(!next())
1586     return false;
1587
1588   buffer.bufferid = value(0).toInt();
1589   buffer.userid = value(1).toInt();
1590   buffer.groupid = value(2).toInt();
1591   buffer.networkid = value(3).toInt();
1592   buffer.buffername = value(4).toString();
1593   buffer.buffercname = value(5).toString();
1594   buffer.buffertype = value(6).toInt();
1595   buffer.lastseenmsgid = value(7).toInt();
1596   buffer.key = value(8).toString();
1597   buffer.joined = value(9).toInt() == 1 ? true : false;
1598   return true;
1599 }
1600
1601 bool SqliteMigrationReader::readMo(SenderMO &sender) {
1602   int skipSteps = 0;
1603   while(!next()) {
1604     if(sender.senderId < _maxId) {
1605       bindValue(0, sender.senderId + (skipSteps * stepSize()));
1606       bindValue(1, sender.senderId + ((skipSteps + 1) * stepSize()));
1607       skipSteps++;
1608       if(!exec())
1609         return false;
1610     } else {
1611       return false;
1612     }
1613   }
1614
1615   sender.senderId = value(0).toInt();
1616   sender.sender = value(1).toString();
1617   return true;
1618 }
1619
1620 bool SqliteMigrationReader::readMo(BacklogMO &backlog) {
1621   int skipSteps = 0;
1622   while(!next()) {
1623     if(backlog.messageid < _maxId) {
1624       bindValue(0, backlog.messageid.toInt() + (skipSteps * stepSize()));
1625       bindValue(1, backlog.messageid.toInt() + ((skipSteps + 1) * stepSize()));
1626       skipSteps++;
1627       if(!exec())
1628         return false;
1629     } else {
1630       return false;
1631     }
1632   }
1633
1634   backlog.messageid = value(0).toInt();
1635   backlog.time = QDateTime::fromTime_t(value(1).toInt()).toUTC();
1636   backlog.bufferid = value(2).toInt();
1637   backlog.type = value(3).toInt();
1638   backlog.flags = value(4).toInt();
1639   backlog.senderid = value(5).toInt();
1640   backlog.message = value(6).toString();
1641   return true;
1642 }
1643
1644 bool SqliteMigrationReader::readMo(IrcServerMO &ircserver) {
1645   if(!next())
1646     return false;
1647
1648   ircserver.serverid = value(0).toInt();
1649   ircserver.userid = value(1).toInt();
1650   ircserver.networkid = value(2).toInt();
1651   ircserver.hostname = value(3).toString();
1652   ircserver.port = value(4).toInt();
1653   ircserver.password = value(5).toString();
1654   ircserver.ssl = value(6).toInt() == 1 ? true : false;
1655   ircserver.sslversion = value(7).toInt();
1656   ircserver.useproxy = value(8).toInt() == 1 ? true : false;
1657   ircserver.proxytype = value(9).toInt();
1658   ircserver.proxyhost = value(10).toString();
1659   ircserver.proxyport = value(11).toInt();
1660   ircserver.proxyuser = value(12).toString();
1661   ircserver.proxypass = value(13).toString();
1662   return true;
1663 }
1664
1665 bool SqliteMigrationReader::readMo(UserSettingMO &userSetting) {
1666   if(!next())
1667     return false;
1668
1669   userSetting.userid = value(0).toInt();
1670   userSetting.settingname = value(1).toString();
1671   userSetting.settingvalue = value(2).toByteArray();
1672
1673   return true;
1674 }