first version of sqlite migration reader
[quassel.git] / src / core / sqlitestorage.cpp
index 054b389..c2c9f0c 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2005-07 by the Quassel IRC Team                         *
+ *   Copyright (C) 2005-07 by the Quassel Project                          *
  *   devel@quassel-irc.org                                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
 
 #include <QtSql>
 
-#include "network.h"
-
-#include "util.h"
 #include "logger.h"
+#include "network.h"
+#include "quassel.h"
 
 int SqliteStorage::_maxRetryCount = 150; // yes this is a large number... only other way to "handle" this is bailing out...
 
@@ -65,6 +64,34 @@ int SqliteStorage::installedSchemaVersion() {
   return AbstractSqlStorage::installedSchemaVersion();
 }
 
+bool SqliteStorage::updateSchemaVersion(int newVersion) {
+  QSqlQuery query(logDb());
+  query.prepare("UPDATE coreinfo SET value = :version WHERE key = 'schemaversion'");
+  query.bindValue(":version", newVersion);
+  query.exec();
+
+  bool success = true;
+  if(query.lastError().isValid()) {
+    qCritical() << "SqliteStorage::updateSchemaVersion(int): Updating schema version failed!";
+    success = false;
+  }
+  return success;
+}
+
+bool SqliteStorage::setupSchemaVersion(int version) {
+  QSqlQuery query(logDb());
+  query.prepare("INSERT INTO coreinfo (key, value) VALUES ('schemaversion', :version)");
+  query.bindValue(":version", version);
+  query.exec();
+
+  bool success = true;
+  if(query.lastError().isValid()) {
+    qCritical() << "SqliteStorage::setupSchemaVersion(int): Updating schema version failed!";
+    success = false;
+  }
+  return success;
+}
+
 UserId SqliteStorage::addUser(const QString &user, const QString &password) {
   QSqlQuery query(logDb());
   query.prepare(queryString("insert_quasseluser"));
@@ -214,12 +241,17 @@ IdentityId SqliteStorage::createIdentity(UserId user, CoreIdentity &identity) {
   query.bindValue(":kickreason", identity.kickReason());
   query.bindValue(":partreason", identity.partReason());
   query.bindValue(":quitreason", identity.quitReason());
+#ifdef HAVE_SSL
   query.bindValue(":sslcert", identity.sslCert().toPem());
   query.bindValue(":sslkey", identity.sslKey().toPem());
+#else
+  query.bindValue(":sslcert", QByteArray());
+  query.bindValue(":sslkey", QByteArray());
+#endif
+
   safeExec(query);
 
   identityId = query.lastInsertId().toInt();
-  qDebug() << identityId << identity.nicks();
   if(!identityId.isValid()) {
     watchQuery(query);
   } else {
@@ -269,15 +301,22 @@ bool SqliteStorage::updateIdentity(UserId user, const CoreIdentity &identity) {
   query.bindValue(":kickreason", identity.kickReason());
   query.bindValue(":partreason", identity.partReason());
   query.bindValue(":quitreason", identity.quitReason());
+#ifdef HAVE_SSL
   query.bindValue(":sslcert", identity.sslCert().toPem());
   query.bindValue(":sslkey", identity.sslKey().toPem());
+#else
+  query.bindValue(":sslcert", QByteArray());
+  query.bindValue(":sslkey", QByteArray());
+#endif
   query.bindValue(":identityid", identity.id().toInt());
   safeExec(query);
+  watchQuery(query);
 
   QSqlQuery deleteNickQuery(logDb());
   deleteNickQuery.prepare(queryString("delete_nicks"));
   deleteNickQuery.bindValue(":identityid", identity.id().toInt());
   safeExec(deleteNickQuery);
+  watchQuery(deleteNickQuery);
 
   QSqlQuery insertNickQuery(logDb());
   insertNickQuery.prepare(queryString("insert_nick"));
@@ -285,6 +324,7 @@ bool SqliteStorage::updateIdentity(UserId user, const CoreIdentity &identity) {
     insertNickQuery.bindValue(":identityid", identity.id().toInt());
     insertNickQuery.bindValue(":nick", nick);
     safeExec(insertNickQuery);
+    watchQuery(insertNickQuery);
   }
 
   return true;
@@ -344,8 +384,10 @@ QList<CoreIdentity> SqliteStorage::identities(UserId user) {
     identity.setKickReason(query.value(15).toString());
     identity.setPartReason(query.value(16).toString());
     identity.setQuitReason(query.value(17).toString());
+#ifdef HAVE_SSL
     identity.setSslCert(query.value(18).toByteArray());
     identity.setSslKey(query.value(19).toByteArray());
+#endif
 
     nickQuery.bindValue(":identityid", identity.id().toInt());
     QList<QString> nicks;
@@ -416,12 +458,19 @@ bool SqliteStorage::updateNetwork(UserId user, const NetworkInfo &info) {
   QSqlQuery insertServersQuery(logDb());
   insertServersQuery.prepare(queryString("insert_server"));
   foreach(Network::Server server, info.serverList) {
+    insertServersQuery.bindValue(":userid", user.toInt());
+    insertServersQuery.bindValue(":networkid", info.networkId.toInt());
     insertServersQuery.bindValue(":hostname", server.host);
     insertServersQuery.bindValue(":port", server.port);
     insertServersQuery.bindValue(":password", server.password);
     insertServersQuery.bindValue(":ssl", server.useSsl ? 1 : 0);
-    insertServersQuery.bindValue(":userid", user.toInt());
-    insertServersQuery.bindValue(":networkid", info.networkId.toInt());
+    insertServersQuery.bindValue(":sslversion", server.sslVersion);
+    insertServersQuery.bindValue(":useproxy", server.useProxy ? 1 : 0);
+    insertServersQuery.bindValue(":proxytype", server.proxyType);
+    insertServersQuery.bindValue(":proxyhost", server.proxyHost);
+    insertServersQuery.bindValue(":proxyport", server.proxyPort);
+    insertServersQuery.bindValue(":proxyuser", server.proxyUser);
+    insertServersQuery.bindValue(":proxypass", server.proxyPass);
 
     safeExec(insertServersQuery);
     if(!watchQuery(insertServersQuery))
@@ -533,6 +582,13 @@ QList<NetworkInfo> SqliteStorage::networks(UserId user) {
       server.port = serversQuery.value(1).toUInt();
       server.password = serversQuery.value(2).toString();
       server.useSsl = serversQuery.value(3).toInt() == 1 ? true : false;
+      server.sslVersion = serversQuery.value(4).toInt();
+      server.useProxy = serversQuery.value(5).toInt() == 1 ? true : false;
+      server.proxyType = serversQuery.value(6).toInt();
+      server.proxyHost = serversQuery.value(7).toString();
+      server.proxyPort = serversQuery.value(8).toUInt();
+      server.proxyUser = serversQuery.value(9).toString();
+      server.proxyPass = serversQuery.value(10).toString();
       servers << server;
     }
     net.serverList = servers;
@@ -648,6 +704,51 @@ void SqliteStorage::setPersistentChannelKey(UserId user, const NetworkId &networ
   watchQuery(query);
 }
 
+QString SqliteStorage::awayMessage(UserId user, NetworkId networkId) {
+  QSqlQuery query(logDb());
+  query.prepare(queryString("select_network_awaymsg"));
+  query.bindValue(":userid", user.toInt());
+  query.bindValue(":networkid", networkId.toInt());
+  safeExec(query);
+  watchQuery(query);
+  QString awayMsg;
+  if(query.first())
+    awayMsg = query.value(0).toString();
+  return awayMsg;
+}
+
+void SqliteStorage::setAwayMessage(UserId user, NetworkId networkId, const QString &awayMsg) {
+  QSqlQuery query(logDb());
+  query.prepare(queryString("update_network_set_awaymsg"));
+  query.bindValue(":userid", user.toInt());
+  query.bindValue(":networkid", networkId.toInt());
+  query.bindValue(":awaymsg", awayMsg);
+  safeExec(query);
+  watchQuery(query);
+}
+
+QString SqliteStorage::userModes(UserId user, NetworkId networkId) {
+  QSqlQuery query(logDb());
+  query.prepare(queryString("select_network_usermode"));
+  query.bindValue(":userid", user.toInt());
+  query.bindValue(":networkid", networkId.toInt());
+  safeExec(query);
+  watchQuery(query);
+  QString modes;
+  if(query.first())
+    modes = query.value(0).toString();
+  return modes;
+}
+
+void SqliteStorage::setUserModes(UserId user, NetworkId networkId, const QString &userModes) {
+  QSqlQuery query(logDb());
+  query.prepare(queryString("update_network_set_usermode"));
+  query.bindValue(":userid", user.toInt());
+  query.bindValue(":networkid", networkId.toInt());
+  query.bindValue(":usermode", userModes);
+  safeExec(query);
+  watchQuery(query);
+}
 
 void SqliteStorage::createBuffer(UserId user, const NetworkId &networkId, BufferInfo::Type type, const QString &buffer) {
   QSqlQuery query(logDb());
@@ -662,7 +763,7 @@ void SqliteStorage::createBuffer(UserId user, const NetworkId &networkId, Buffer
   watchQuery(query);
 }
 
-BufferInfo SqliteStorage::getBufferInfo(UserId user, const NetworkId &networkId, BufferInfo::Type type, const QString &buffer) {
+BufferInfo SqliteStorage::bufferInfo(UserId user, const NetworkId &networkId, BufferInfo::Type type, const QString &buffer, bool create) {
   QSqlQuery query(logDb());
   query.prepare(queryString("select_bufferByName"));
   query.bindValue(":networkid", networkId.toInt());
@@ -671,6 +772,9 @@ BufferInfo SqliteStorage::getBufferInfo(UserId user, const NetworkId &networkId,
   safeExec(query);
 
   if(!query.first()) {
+    if(!create)
+      return BufferInfo();
+
     createBuffer(user, networkId, type, buffer);
     safeExec(query);
     if(!query.first()) {
@@ -762,45 +866,45 @@ bool SqliteStorage::removeBuffer(const UserId &user, const BufferId &bufferId) {
   return true;
 }
 
-BufferId SqliteStorage::renameBuffer(const UserId &user, const NetworkId &networkId, const QString &newName, const QString &oldName) {
-  // check if such a buffer exists...
-  QSqlQuery existsQuery(logDb());
-  existsQuery.prepare(queryString("select_bufferByName"));
-  existsQuery.bindValue(":networkid", networkId.toInt());
-  existsQuery.bindValue(":userid", user.toInt());
-  existsQuery.bindValue(":buffercname", oldName.toLower());
-  safeExec(existsQuery);
-  if(!watchQuery(existsQuery))
+bool SqliteStorage::renameBuffer(const UserId &user, const BufferId &bufferId, const QString &newName) {
+  if(!isValidBuffer(user, bufferId))
     return false;
 
-  if(!existsQuery.first())
+  QSqlQuery query(logDb());
+  query.prepare(queryString("update_buffer_name"));
+  query.bindValue(":buffername", newName);
+  query.bindValue(":buffercname", newName.toLower());
+  query.bindValue(":bufferid", bufferId.toInt());
+  safeExec(query);
+  if(query.lastError().isValid()) {
+    // unexepcted error occured (19 == constraint violation)
+    if(query.lastError().number() != 19)
+      watchQuery(query);
     return false;
+  }
 
-  const int bufferid = existsQuery.value(0).toInt();
-
-  Q_ASSERT(!existsQuery.next());
+  return true;
+}
 
-  // ... and if the new name is still free.
-  existsQuery.bindValue(":networkid", networkId.toInt());
-  existsQuery.bindValue(":userid", user.toInt());
-  existsQuery.bindValue(":buffercname", newName.toLower());
-  safeExec(existsQuery);
-  if(!watchQuery(existsQuery))
+bool SqliteStorage::mergeBuffersPermanently(const UserId &user, const BufferId &bufferId1, const BufferId &bufferId2) {
+  if(!isValidBuffer(user, bufferId1) || !isValidBuffer(user, bufferId2))
     return false;
 
-  if(existsQuery.first())
+  QSqlQuery query(logDb());
+  query.prepare(queryString("update_backlog_bufferid"));
+  query.bindValue(":oldbufferid", bufferId2.toInt());
+  query.bindValue(":newbufferid", bufferId1.toInt());
+  safeExec(query);
+  if(!watchQuery(query))
     return false;
 
-  QSqlQuery renameBufferQuery(logDb());
-  renameBufferQuery.prepare(queryString("update_buffer_name"));
-  renameBufferQuery.bindValue(":buffername", newName);
-  renameBufferQuery.bindValue(":buffercname", newName.toLower());
-  renameBufferQuery.bindValue(":bufferid", bufferid);
-  safeExec(renameBufferQuery);
-  if(watchQuery(existsQuery))
-    return BufferId(bufferid);
-  else
-    return BufferId();
+  QSqlQuery delBufferQuery(logDb());
+  delBufferQuery.prepare(queryString("delete_buffer_for_bufferid"));
+  delBufferQuery.bindValue(":bufferid", bufferId2.toInt());
+  safeExec(delBufferQuery);
+  watchQuery(delBufferQuery);
+
+  return true;
 }
 
 void SqliteStorage::setBufferLastSeenMsg(UserId user, const BufferId &bufferId, const MsgId &msgId) {
@@ -829,7 +933,7 @@ QHash<BufferId, MsgId> SqliteStorage::bufferLastSeenMsgIds(UserId user) {
   return lastSeenHash;
 }
 
-MsgId SqliteStorage::logMessage(Message msg) {
+bool SqliteStorage::logMessage(Message &msg) {
   QSqlQuery logMessageQuery(logDb());
   logMessageQuery.prepare(queryString("insert_message"));
 
@@ -850,15 +954,28 @@ MsgId SqliteStorage::logMessage(Message msg) {
       safeExec(addSenderQuery);
       safeExec(logMessageQuery);
       if(!watchQuery(logMessageQuery))
-       return 0;
+       return false;
     } else {
       watchQuery(logMessageQuery);
     }
   }
 
   MsgId msgId = logMessageQuery.lastInsertId().toInt();
-  Q_ASSERT(msgId.isValid());
-  return msgId;
+  if(msgId.isValid()) {
+    msg.setMsgId(msgId);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+bool SqliteStorage::logMessages(MessageList &msgs) {
+  // FIXME: optimize!
+  for(int i = 0; i < msgs.count(); i++) {
+    if(!logMessage(msgs[i]))
+      return false;
+  }
+  return true;
 }
 
 QList<Message> SqliteStorage::requestMsgs(UserId user, BufferId bufferId, MsgId first, MsgId last, int limit) {
@@ -869,15 +986,19 @@ QList<Message> SqliteStorage::requestMsgs(UserId user, BufferId bufferId, MsgId
     return messagelist;
 
   QSqlQuery query(logDb());
-  if(last == -1) {
-    query.prepare(queryString("select_messagesNew"));
+
+  if(last == -1 && first == -1) {
+    query.prepare(queryString("select_messagesNewestK"));
+  } else if(last == -1) {
+    query.prepare(queryString("select_messagesNewerThan"));
+    query.bindValue(":firstmsg", first.toInt());
   } else {
     query.prepare(queryString("select_messages"));
     query.bindValue(":lastmsg", last.toInt());
+    query.bindValue(":firstmsg", first.toInt());
   }
 
   query.bindValue(":bufferid", bufferId.toInt());
-  query.bindValue(":firstmsg", first.toInt());
   query.bindValue(":limit", limit);
   safeExec(query);
 
@@ -933,7 +1054,7 @@ QList<Message> SqliteStorage::requestAllMsgs(UserId user, MsgId first, MsgId las
 }
 
 QString SqliteStorage::backlogFile() {
-  return quasselDir().absolutePath() + "/quassel-storage.sqlite";
+  return Quassel::configDirPath() + "quassel-storage.sqlite";
 }
 
 bool SqliteStorage::safeExec(QSqlQuery &query, int retryCount) {
@@ -951,3 +1072,207 @@ bool SqliteStorage::safeExec(QSqlQuery &query, int retryCount) {
     return false;
   }
 }
+
+
+// ========================================
+//  SqliteMigration
+// ========================================
+SqliteMigrationReader::SqliteMigrationReader()
+  : SqliteStorage()
+{
+}
+
+bool SqliteMigrationReader::prepareQuery(MigrationObject mo) {
+  QString query;
+  switch(mo) {
+  case QuasselUser:
+    query = queryString("migrate_read_quasseluser");
+    break;
+  case Sender:
+    query = queryString("migrate_read_sender");
+    break;
+  case Identity:
+    query = queryString("migrate_read_identity");
+    break;
+  case IdentityNick:
+    query = queryString("migrate_read_identity_nick");
+    break;
+  case Network:
+    query = queryString("migrate_read_network");
+    break;
+  case Buffer:
+    query = queryString("migrate_read_buffer");
+    break;
+  case Backlog:
+    query = queryString("migrate_read_backlog");
+    break;
+  case IrcServer:
+    query = queryString("migrate_read_ircserver");
+    break;
+  case UserSetting:
+    query = queryString("migrate_read_usersetting");
+    break;
+  }
+  newQuery(query, logDb());
+  return exec();
+}
+
+//bool SqliteMigrationReader::readUser(QuasselUserMO &user) {
+bool SqliteMigrationReader::readMo(QuasselUserMO &user) {
+  if(!next())
+    return false;
+
+  user.id = value(0).toInt();
+  user.username = value(1).toString();
+  user.password = value(2).toString();
+  return true;
+}
+
+//bool SqliteMigrationReader::readSender(SenderMO &sender) {
+bool SqliteMigrationReader::readMo(SenderMO &sender) {
+  if(!next())
+    return false;
+
+  sender.senderId = value(0).toInt();
+  sender.sender = value(1).toString();
+  return true;
+}
+
+//bool SqliteMigrationReader::readIdentity(IdentityMO &identity) {
+bool SqliteMigrationReader::readMo(IdentityMO &identity) {
+  if(!next())
+    return false;
+
+  identity.id = value(0).toInt();
+  identity.userid = value(1).toInt();
+  identity.identityname = value(2).toString();
+  identity.realname = value(3).toString();
+  identity.awayNick = value(4).toString();
+  identity.awayNickEnabled = value(5).toInt() == 1 ? true : false;
+  identity.awayReason = value(6).toString();
+  identity.awayReasonEnabled = value(7).toInt() == 1 ? true : false;
+  identity.autoAwayEnabled = value(8).toInt() == 1 ? true : false;
+  identity.autoAwayTime = value(9).toInt();
+  identity.autoAwayReason = value(10).toString();
+  identity.autoAwayReasonEnabled = value(11).toInt() == 1 ? true : false;
+  identity.detachAwayEnabled = value(12).toInt() == 1 ? true : false;
+  identity.detachAwayReason = value(13).toString();
+  identity.detchAwayReasonEnabled = value(14).toInt() == 1 ? true : false;
+  identity.ident = value(15).toString();
+  identity.kickReason = value(16).toString();
+  identity.partReason = value(17).toString();
+  identity.quitReason = value(18).toString();
+  identity.sslCert = value(19).toByteArray();
+  identity.sslKey = value(20).toByteArray();
+  return true;
+}
+
+//bool SqliteMigrationReader::readIdentityNick(IdentityNickMO &identityNick) {
+bool SqliteMigrationReader::readMo(IdentityNickMO &identityNick) {
+  if(!next())
+    return false;
+
+  identityNick.nickid = value(0).toInt();
+  identityNick.identityId = value(1).toInt();
+  identityNick.nick = value(2).toString();
+  return true;
+}
+
+//bool SqliteMigrationReader::readNetwork(NetworkMO &network) {
+bool SqliteMigrationReader::readMo(NetworkMO &network) {
+  if(!next())
+    return false;
+
+  network.networkid = value(0).toInt();
+  network.userid = value(1).toInt();
+  network.networkname = value(2).toString();
+  network.identityid = value(3).toInt();
+  network.encodingcodec = value(4).toString();
+  network.decodingcodec = value(5).toString();
+  network.servercodec = value(6).toString();
+  network.userandomserver = value(7).toInt() == 1 ? true : false;
+  network.perform = value(8).toString();
+  network.useautoidentify = value(9).toInt() == 1 ? true : false;
+  network.autoidentifyservice = value(10).toString();
+  network.autoidentifypassword = value(11).toString();
+  network.useautoreconnect = value(12).toInt() == 1 ? true : false;
+  network.autoreconnectinterval = value(13).toInt();
+  network.autoreconnectretries = value(14).toInt();
+  network.unlimitedconnectretries = value(15).toInt() == 1 ? true : false;
+  network.rejoinchannels = value(16).toInt() == 1 ? true : false;
+  network.connected = value(17).toInt() == 1 ? true : false;
+  network.usermode = value(18).toString();
+  network.awaymessage = value(19).toString();
+  network.attachperform = value(20).toString();
+  network.detachperform = value(21).toString();
+  return true;
+}
+
+//bool SqliteMigrationReader::readBuffer(BufferMO &buffer) {
+bool SqliteMigrationReader::readMo(BufferMO &buffer) {
+  if(!next())
+    return false;
+
+  buffer.bufferid = value(0).toInt();
+  buffer.userid = value(1).toInt();
+  buffer.groupid = value(2).toInt();
+  buffer.networkid = value(3).toInt();
+  buffer.buffername = value(4).toString();
+  buffer.buffercname = value(5).toString();
+  buffer.buffertype = value(6).toInt();
+  buffer.lastseenmsgid = value(7).toInt();
+  buffer.key = value(8).toString();
+  buffer.joined = value(9).toInt() == 1 ? true : false;
+  return true;
+}
+
+//bool SqliteMigrationReader::readBacklog(BacklogMO &backlog) {
+bool SqliteMigrationReader::readMo(BacklogMO &backlog) {
+  if(!next())
+    return false;
+
+  backlog.messageid = value(0).toInt();
+  backlog.time = QDateTime::fromTime_t(value(1).toInt());
+  backlog.bufferid = value(2).toInt();
+  backlog.type = value(3).toInt();
+  backlog.flags = value(4).toInt();
+  backlog.senderid = value(5).toInt();
+  backlog.message = value(6).toString();
+  return true;
+}
+
+//bool SqliteMigrationReader::readIrcServer(IrcServerMO &ircserver) {
+bool SqliteMigrationReader::readMo(IrcServerMO &ircserver) {
+  if(!next())
+    return false;
+
+  ircserver.serverid = value(0).toInt();
+  ircserver.userid = value(1).toInt();
+  ircserver.networkid = value(2).toInt();
+  ircserver.hostname = value(3).toString();
+  ircserver.port = value(4).toInt();
+  ircserver.password = value(5).toString();
+  ircserver.ssl = value(6).toInt() == 1 ? true : false;
+  ircserver.sslversion = value(7).toInt();
+  ircserver.useproxy = value(8).toInt() == 1 ? true : false;
+  ircserver.proxytype = value(9).toInt();
+  ircserver.proxyhost = value(10).toString();
+  ircserver.proxyport = value(11).toInt();
+  ircserver.proxyuser = value(12).toString();
+  ircserver.proxypass = value(13).toString();
+  return true;
+}
+
+//bool SqliteMigrationReader::readUserSetting(UserSettingMO &userSetting) {
+bool SqliteMigrationReader::readMo(UserSettingMO &userSetting) {
+  if(!next())
+    return false;
+
+  userSetting.userid = value(0).toInt();
+  userSetting.settingname = value(1).toString();
+  userSetting.settingvalue = value(2).toByteArray();
+
+  return true;
+}
+
+