From 7a46b1ddf4193c2f4ca789ef86b099f9d70842f9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?C=C4=83t=C4=83lin=20Badea?= <catalin.badea392@gmail.com>
Date: Sun, 19 Aug 2012 21:34:48 +0300
Subject: Use appropriate folder for storing the history file.


diff --git a/Swift/Controllers/HistoryController.cpp b/Swift/Controllers/HistoryController.cpp
index 6ab1235..d730236 100644
--- a/Swift/Controllers/HistoryController.cpp
+++ b/Swift/Controllers/HistoryController.cpp
@@ -5,19 +5,16 @@
  */
 
 #include <Swift/Controllers/HistoryController.h>
-#include <Swiften/History/SQLiteHistoryManager.h>
+#include <Swiften/History/HistoryStorage.h>
 #include <Swiften/History/HistoryMessage.h>
 #include <boost/date_time/c_local_time_adjustor.hpp>
 
 namespace Swift {
 
-HistoryController::HistoryController() : remoteArchiveSupported_(false) {
-	std::string file("testDB.db");
-	localHistory_ = new SQLiteHistoryManager(file);
+HistoryController::HistoryController(HistoryStorage* localHistoryStorage) : localHistory_(localHistoryStorage) {
 }
 
 HistoryController::~HistoryController() {
-	delete localHistory_;
 }
 
 void HistoryController::addMessage(const std::string& message, const JID& fromJID, const JID& toJID, HistoryMessage::Type type, const boost::posix_time::ptime& timeStamp) {
diff --git a/Swift/Controllers/HistoryController.h b/Swift/Controllers/HistoryController.h
index f231724..8c86409 100644
--- a/Swift/Controllers/HistoryController.h
+++ b/Swift/Controllers/HistoryController.h
@@ -12,14 +12,14 @@
 #include <set>
 #include <Swiften/Base/boost_bsignals.h>
 #include <Swiften/History/HistoryMessage.h>
-#include <Swiften/History/HistoryManager.h>
+#include <Swiften/History/HistoryStorage.h>
 
 namespace Swift {
 	class JID;
 
 	class HistoryController {
 		public:
-			HistoryController();
+			HistoryController(HistoryStorage* localHistoryStorage);
 			~HistoryController();
 
 			void addMessage(const std::string& message, const JID& fromJID, const JID& toJID, HistoryMessage::Type type, const boost::posix_time::ptime& timeStamp);
@@ -34,7 +34,7 @@ namespace Swift {
 			boost::signal<void (const HistoryMessage&)> onNewMessage;
 
 		private:
-			HistoryManager* localHistory_;
+			HistoryStorage* localHistory_;
 			bool remoteArchiveSupported_;
 	};
 }
diff --git a/Swift/Controllers/HistoryViewController.h b/Swift/Controllers/HistoryViewController.h
index 283254d..f44c968 100644
--- a/Swift/Controllers/HistoryViewController.h
+++ b/Swift/Controllers/HistoryViewController.h
@@ -11,9 +11,9 @@
 #include <boost/shared_ptr.hpp>
 
 #include <Swift/Controllers/UIEvents/UIEventStream.h>
-#include <Swiften/History/HistoryManager.h>
 #include <Swiften/JID/JID.h>
 #include <Swiften/Presence/PresenceOracle.h>
+#include <Swiften/History/HistoryStorage.h>
 #include <set>
 
 namespace Swift {
@@ -25,7 +25,6 @@ namespace Swift {
 	class HistoryController;
 	class NickResolver;
 	class AvatarManager;
-	class HistoryMessage;
 
 	class HistoryViewController {
 		public:
diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp
index 9ac97f4..2955cee 100644
--- a/Swift/Controllers/MainController.cpp
+++ b/Swift/Controllers/MainController.cpp
@@ -172,7 +172,6 @@ MainController::MainController(
 	idleDetector_->onIdleChanged.connect(boost::bind(&MainController::handleInputIdleChanged, this, _1));
 
 	xmlConsoleController_ = new XMLConsoleController(uiEventStream_, uiFactory_);
-	historyController_ = new HistoryController();
 
 	fileTransferListController_ = new FileTransferListController(uiEventStream_, uiFactory_);
 
@@ -197,7 +196,6 @@ MainController::~MainController() {
 	resetClient();
 	delete fileTransferListController_;
 	delete xmlConsoleController_;
-	delete historyController_;
 	delete xmppURIController_;
 	delete soundEventController_;
 	delete systemTrayController_;
@@ -223,6 +221,8 @@ void MainController::resetClient() {
 	eventWindowController_ = NULL;
 	delete chatsManager_;
 	chatsManager_ = NULL;
+	delete historyController_;
+	historyController_ = NULL;
 	delete historyViewController_;
 	historyViewController_ = NULL;
 	delete ftOverview_;
@@ -301,9 +301,9 @@ void MainController::handleConnected() {
 		 * want to have the user's nick available and this means it will
 		 * be before they receive stanzas that need it (e.g. bookmarks).*/
 		client_->getVCardManager()->requestOwnVCard();
+		historyController_ = new HistoryController(storages_->getHistoryStorage());
 
 		chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager(), uiFactory_, profileSettings_, ftOverview_, client_->getRoster(), !settings_->getSetting(SettingConstants::REMEMBER_RECENT_CHATS), settings_, historyController_);
-
 		historyViewController_ = new HistoryViewController(jid_, uiEventStream_, historyController_, client_->getNickResolver(), client_->getAvatarManager(), client_->getPresenceOracle(), uiFactory_);
 		
 		client_->onMessageReceived.connect(boost::bind(&ChatsManager::handleIncomingMessage, chatsManager_, _1));
diff --git a/Swift/Controllers/Storages/FileStorages.cpp b/Swift/Controllers/Storages/FileStorages.cpp
index 6447099..27c245d 100644
--- a/Swift/Controllers/Storages/FileStorages.cpp
+++ b/Swift/Controllers/Storages/FileStorages.cpp
@@ -9,6 +9,7 @@
 #include "Swift/Controllers/Storages/AvatarFileStorage.h"
 #include "Swift/Controllers/Storages/CapsFileStorage.h"
 #include "Swift/Controllers/Storages/RosterFileStorage.h"
+#include <Swiften/History/SQLiteHistoryStorage.h>
 
 namespace Swift {
 
@@ -18,6 +19,7 @@ FileStorages::FileStorages(const boost::filesystem::path& baseDir, const JID& ji
 	capsStorage = new CapsFileStorage(baseDir / "caps");
 	avatarStorage = new AvatarFileStorage(baseDir / "avatars", baseDir / profile / "avatars");
 	rosterStorage = new RosterFileStorage(baseDir / profile / "roster.xml");
+	historyStorage = new SQLiteHistoryStorage((baseDir / "history.db").string());
 }
 
 FileStorages::~FileStorages() {
@@ -25,6 +27,7 @@ FileStorages::~FileStorages() {
 	delete avatarStorage;
 	delete capsStorage;
 	delete vcardStorage;
+	delete historyStorage;
 }
 
 VCardStorage* FileStorages::getVCardStorage() const {
@@ -43,4 +46,8 @@ RosterStorage* FileStorages::getRosterStorage() const {
 	return rosterStorage;
 }
 
+HistoryStorage* FileStorages::getHistoryStorage() const {
+	return historyStorage;
+}
+
 }
diff --git a/Swift/Controllers/Storages/FileStorages.h b/Swift/Controllers/Storages/FileStorages.h
index 28df314..5e89db8 100644
--- a/Swift/Controllers/Storages/FileStorages.h
+++ b/Swift/Controllers/Storages/FileStorages.h
@@ -15,6 +15,7 @@ namespace Swift {
 	class AvatarFileStorage;
 	class CapsFileStorage;
 	class RosterFileStorage;
+	class HistoryStorage;
 	class JID;
 
 	/**
@@ -43,11 +44,13 @@ namespace Swift {
 			virtual AvatarStorage* getAvatarStorage() const;
 			virtual CapsStorage* getCapsStorage() const;
 			virtual RosterStorage* getRosterStorage() const;
+			virtual HistoryStorage* getHistoryStorage() const;
 
 		private:
 			VCardFileStorage* vcardStorage;
 			AvatarFileStorage* avatarStorage;
 			CapsFileStorage* capsStorage;
 			RosterFileStorage* rosterStorage;
+			HistoryStorage* historyStorage;
 	};
 }
diff --git a/Swiften/Client/MemoryStorages.cpp b/Swiften/Client/MemoryStorages.cpp
index fe171f7..9bae4e3 100644
--- a/Swiften/Client/MemoryStorages.cpp
+++ b/Swiften/Client/MemoryStorages.cpp
@@ -9,6 +9,7 @@
 #include <Swiften/Avatars/AvatarMemoryStorage.h>
 #include <Swiften/Disco/CapsMemoryStorage.h>
 #include <Swiften/Roster/RosterMemoryStorage.h>
+#include <Swiften/History/SQLiteHistoryStorage.h>
 
 namespace Swift {
 
@@ -17,6 +18,7 @@ MemoryStorages::MemoryStorages() {
 	capsStorage = new CapsMemoryStorage();
 	avatarStorage = new AvatarMemoryStorage();
 	rosterStorage = new RosterMemoryStorage();
+	historyStorage = new SQLiteHistoryStorage(":memory:");
 }
 
 MemoryStorages::~MemoryStorages() {
@@ -24,6 +26,7 @@ MemoryStorages::~MemoryStorages() {
 	delete avatarStorage;
 	delete capsStorage;
 	delete vcardStorage;
+	delete historyStorage;
 }
 
 VCardStorage* MemoryStorages::getVCardStorage() const {
@@ -42,5 +45,9 @@ RosterStorage* MemoryStorages::getRosterStorage() const {
 	return rosterStorage;
 }
 
+HistoryStorage* MemoryStorages::getHistoryStorage() const {
+	return historyStorage;
+}
+
 
 }
diff --git a/Swiften/Client/MemoryStorages.h b/Swiften/Client/MemoryStorages.h
index ca01a7a..403a89a 100644
--- a/Swiften/Client/MemoryStorages.h
+++ b/Swiften/Client/MemoryStorages.h
@@ -24,11 +24,13 @@ namespace Swift {
 			virtual AvatarStorage* getAvatarStorage() const;
 			virtual CapsStorage* getCapsStorage() const;
 			virtual RosterStorage* getRosterStorage() const;
+			virtual HistoryStorage* getHistoryStorage() const;
 
 		private:
 			VCardMemoryStorage* vcardStorage;
 			AvatarStorage* avatarStorage;
 			CapsStorage* capsStorage;
 			RosterStorage* rosterStorage;
+			HistoryStorage* historyStorage;
 	};
 }
diff --git a/Swiften/Client/Storages.h b/Swiften/Client/Storages.h
index 89b770c..76650a6 100644
--- a/Swiften/Client/Storages.h
+++ b/Swiften/Client/Storages.h
@@ -13,6 +13,7 @@ namespace Swift {
 	class AvatarStorage;
 	class CapsStorage;
 	class RosterStorage;
+	class HistoryStorage;
 
 	/**
 	 * An interface to hold storage classes for different
@@ -26,5 +27,6 @@ namespace Swift {
 			virtual AvatarStorage* getAvatarStorage() const = 0;
 			virtual CapsStorage* getCapsStorage() const = 0;
 			virtual RosterStorage* getRosterStorage() const = 0;
+			virtual HistoryStorage* getHistoryStorage() const = 0;
 	};
 }
diff --git a/Swiften/History/HistoryManager.cpp b/Swiften/History/HistoryManager.cpp
deleted file mode 100644
index 7eb66ab..0000000
--- a/Swiften/History/HistoryManager.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * Copyright (c) 2010 Remko Tronçon
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
- */
-
-#include <Swiften/History/HistoryManager.h>
-
-namespace Swift {
-
-HistoryManager::~HistoryManager() {
-}
-
-}
diff --git a/Swiften/History/HistoryManager.h b/Swiften/History/HistoryManager.h
deleted file mode 100644
index 33e9143..0000000
--- a/Swiften/History/HistoryManager.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2010 Remko Tronçon
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
- */
-
-#pragma once
-
-#include <set>
-#include <map>
-#include <vector>
-#include <Swiften/JID/JID.h>
-#include <Swiften/History/HistoryMessage.h>
-#include <boost/date_time/gregorian/gregorian_types.hpp>
-
-namespace Swift {
-	typedef std::map<JID, std::set<boost::gregorian::date> > ContactsMap;
-
-	class HistoryManager {
-		/**
-		 * Messages are stored using localtime timestamps.
-		 */
-		public:
-			virtual ~HistoryManager();
-
-			virtual void addMessage(const HistoryMessage& message) = 0;
-
-			virtual std::vector<HistoryMessage> getMessagesFromDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const = 0;
-			virtual std::vector<HistoryMessage> getMessagesFromNextDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const = 0;
-			virtual std::vector<HistoryMessage> getMessagesFromPreviousDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const = 0;
-			virtual ContactsMap getContacts(const JID& selfJID, HistoryMessage::Type type, const std::string& keyword) const = 0;
-			virtual boost::posix_time::ptime getLastTimeStampFromMUC(const JID& selfJID, const JID& mucJID) const = 0;
-	};
-}
diff --git a/Swiften/History/HistoryStorage.h b/Swiften/History/HistoryStorage.h
new file mode 100644
index 0000000..fcf28b5
--- /dev/null
+++ b/Swiften/History/HistoryStorage.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <set>
+#include <map>
+#include <vector>
+#include <Swiften/JID/JID.h>
+#include <Swiften/History/HistoryMessage.h>
+#include <boost/date_time/gregorian/gregorian_types.hpp>
+
+namespace Swift {
+	typedef std::map<JID, std::set<boost::gregorian::date> > ContactsMap;
+
+	class HistoryStorage {
+		/**
+		 * Messages are stored using localtime timestamps.
+		 */
+		public:
+			virtual ~HistoryStorage() {};
+
+			virtual void addMessage(const HistoryMessage& message) = 0;
+			virtual std::vector<HistoryMessage> getMessagesFromDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const = 0;
+			virtual std::vector<HistoryMessage> getMessagesFromNextDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const = 0;
+			virtual std::vector<HistoryMessage> getMessagesFromPreviousDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const = 0;
+			virtual ContactsMap getContacts(const JID& selfJID, HistoryMessage::Type type, const std::string& keyword) const = 0;
+			virtual boost::posix_time::ptime getLastTimeStampFromMUC(const JID& selfJID, const JID& mucJID) const = 0;
+	};
+}
diff --git a/Swiften/History/SConscript b/Swiften/History/SConscript
index 975f839..bc0d64c 100644
--- a/Swiften/History/SConscript
+++ b/Swiften/History/SConscript
@@ -5,7 +5,6 @@ if myenv["target"] == "native":
    myenv.MergeFlags(swiften_env.get("SQLITE_FLAGS", {}))
 
 objects = myenv.SwiftenObject([
-			"HistoryManager.cpp",
-			"SQLiteHistoryManager.cpp",
+			"SQLiteHistoryStorage.cpp",
 		])
 swiften_env.Append(SWIFTEN_OBJECTS = [objects])
diff --git a/Swiften/History/SQLiteHistoryManager.cpp b/Swiften/History/SQLiteHistoryManager.cpp
deleted file mode 100644
index e385b1e..0000000
--- a/Swiften/History/SQLiteHistoryManager.cpp
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * Copyright (c) 2010 Remko Tronçon
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
- */
-
-#include <iostream>
-#include <boost/lexical_cast.hpp>
-
-#include <sqlite3.h>
-#include <Swiften/History/SQLiteHistoryManager.h>
-#include <boost/date_time/gregorian/gregorian.hpp>
-
-inline std::string getEscapedString(const std::string& s) {
-	std::string result(s);
-
-	size_t pos = result.find('\'');
-	while (pos != std::string::npos) {
-		result.insert(pos, "'");
-		pos = result.find('\'', pos + 2);
-	}
-	return result;
-}
-
-namespace Swift {
-
-SQLiteHistoryManager::SQLiteHistoryManager(const std::string& file) : db_(0) {
-	sqlite3_open(file.c_str(), &db_);
-	if (!db_) {
-		std::cerr << "Error opening database " << file << std::endl; // FIXME
-	}
-
-	char* errorMessage;
-	int result = sqlite3_exec(db_, "CREATE TABLE IF NOT EXISTS messages('message' STRING, 'fromBare' INTEGER, 'fromResource' STRING, 'toBare' INTEGER, 'toResource' STRING, 'type' INTEGER, 'time' INTEGER, 'offset' INTEGER)", 0, 0, &errorMessage);
-	if (result != SQLITE_OK) {
-		std::cerr << "SQL Error: " << errorMessage << std::endl;
-		sqlite3_free(errorMessage);
-	}
-
-	result = sqlite3_exec(db_, "CREATE TABLE IF NOT EXISTS jids('id' INTEGER PRIMARY KEY ASC AUTOINCREMENT, 'jid' STRING UNIQUE NOT NULL)", 0, 0, &errorMessage);
-	if (result != SQLITE_OK) {
-		std::cerr << "SQL Error: " << errorMessage << std::endl;
-		sqlite3_free(errorMessage);
-	}
-}
-
-SQLiteHistoryManager::~SQLiteHistoryManager() {
-	sqlite3_close(db_);
-}
-
-void SQLiteHistoryManager::addMessage(const HistoryMessage& message) {
-	int secondsSinceEpoch = (message.getTime() - boost::posix_time::ptime(boost::gregorian::date(1970, 1, 1))).total_seconds();
-
-	std::string statement = std::string("INSERT INTO messages('message', 'fromBare', 'fromResource', 'toBare', 'toResource', 'type', 'time', 'offset') VALUES(") +
-					"'" + getEscapedString(message.getMessage()) + "', " +
-					boost::lexical_cast<std::string>(getIDForJID(message.getFromJID().toBare())) + ", '" +
-					getEscapedString(message.getFromJID().getResource()) + "', " +
-					boost::lexical_cast<std::string>(getIDForJID(message.getToJID().toBare())) + ", '" +
-					getEscapedString(message.getToJID().getResource()) + "', " +
-					boost::lexical_cast<std::string>(message.getType()) + ", " +
-					boost::lexical_cast<std::string>(secondsSinceEpoch) + ", " +
-					boost::lexical_cast<std::string>(message.getOffset()) + ")";
-	char* errorMessage;
-	int result = sqlite3_exec(db_, statement.c_str(), 0, 0, &errorMessage);
-	if (result != SQLITE_OK) {
-		std::cerr << "SQL Error: " << errorMessage << std::endl;
-		sqlite3_free(errorMessage);
-	}
-}
-
-std::vector<HistoryMessage> SQLiteHistoryManager::getMessagesFromDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const {
-	sqlite3_stmt* selectStatement;
-
-	boost::optional<int> selfID = getIDFromJID(selfJID.toBare());
-	boost::optional<int> contactID = getIDFromJID(contactJID.toBare());
-
-	if (!selfID || !contactID) {
-		// JIDs missing from the database
-		return std::vector<HistoryMessage>();
-	}
-
-	std::string selectQuery = "SELECT * FROM messages WHERE (type=" + boost::lexical_cast<std::string>(type);
-	if (contactJID.isBare()) {
-		// match only bare jid
-		selectQuery += " AND ((fromBare=" + boost::lexical_cast<std::string>(*selfID) + " AND toBare=" +
-				boost::lexical_cast<std::string>(*contactID) + ") OR (fromBare=" +
-				boost::lexical_cast<std::string>(*contactID) + " AND toBare=" + boost::lexical_cast<std::string>(*selfID) + ")))";
-	}
-	else {
-		// match resource too
-		selectQuery += " AND ((fromBare=" + boost::lexical_cast<std::string>(*selfID) + " AND (toBare=" +
-				boost::lexical_cast<std::string>(*contactID) +" AND toResource='" +
-				getEscapedString(contactJID.getResource()) + "')) OR ((fromBare=" +
-				boost::lexical_cast<std::string>(*contactID) + " AND fromResource='" +
-				getEscapedString(contactJID.getResource()) + "') AND toBare=" +
-				boost::lexical_cast<std::string>(*selfID) + ")))";
-	}
-
-	if (!date.is_not_a_date()) {
-		int lowerBound = (boost::posix_time::ptime(date) - boost::posix_time::ptime(boost::gregorian::date(1970, 1, 1))).total_seconds();
-		int upperBound = lowerBound + 86400;
-
-		selectQuery += " AND (time>=" + boost::lexical_cast<std::string>(lowerBound) +
-				" AND time<" + boost::lexical_cast<std::string>(upperBound) + ")";
-	}
-
-	int r = sqlite3_prepare(db_, selectQuery.c_str(), selectQuery.size(), &selectStatement, NULL);
-	if (r != SQLITE_OK) {
-		std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl;
-	}
-	r = sqlite3_step(selectStatement);
-
-	// Retrieve result
-	std::vector<HistoryMessage> result;
-	while (r == SQLITE_ROW) {
-		std::string message(reinterpret_cast<const char*>(sqlite3_column_text(selectStatement, 0)));
-
-		// fromJID
-		boost::optional<JID> fromJID(getJIDFromID(sqlite3_column_int(selectStatement, 1)));
-		std::string fromResource(reinterpret_cast<const char*>(sqlite3_column_text(selectStatement, 2)));
-		if (fromJID) {
-			fromJID = boost::optional<JID>(JID(fromJID->getNode(), fromJID->getDomain(), fromResource));
-		}
-
-		// toJID
-		boost::optional<JID> toJID(getJIDFromID(sqlite3_column_int(selectStatement, 3)));
-		std::string toResource(reinterpret_cast<const char*>(sqlite3_column_text(selectStatement, 4)));
-		if (toJID) {
-			toJID = boost::optional<JID>(JID(toJID->getNode(), toJID->getDomain(), toResource));
-		}
-
-		// message type
-		HistoryMessage::Type type = static_cast<HistoryMessage::Type>(sqlite3_column_int(selectStatement, 5));
-
-		// timestamp
-		int secondsSinceEpoch(sqlite3_column_int(selectStatement, 6));
-		boost::posix_time::ptime time(boost::gregorian::date(1970, 1, 1), boost::posix_time::seconds(secondsSinceEpoch));
-
-		// offset from utc
-		int offset = sqlite3_column_int(selectStatement, 7);
-
-		result.push_back(HistoryMessage(message, (fromJID ? *fromJID : JID()), (toJID ? *toJID : JID()), type, time, offset));
-		r = sqlite3_step(selectStatement);
-	}
-	if (r != SQLITE_DONE) {
-		std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl;
-	}
-	sqlite3_finalize(selectStatement);
-
-	return result;
-}
-
-int SQLiteHistoryManager::getIDForJID(const JID& jid) {
-	boost::optional<int> id = getIDFromJID(jid);
-	if (id) {
-		return *id;
-	}
-	else {
-		return addJID(jid);
-	}
-}
-
-int SQLiteHistoryManager::addJID(const JID& jid) {
-	std::string statement = std::string("INSERT INTO jids('jid') VALUES('") + getEscapedString(jid.toString()) + "')";
-	char* errorMessage;
-	int result = sqlite3_exec(db_, statement.c_str(), 0, 0, &errorMessage);
-	if (result != SQLITE_OK) {
-		std::cerr << "SQL Error: " << errorMessage << std::endl;
-		sqlite3_free(errorMessage);
-	}
-	return sqlite3_last_insert_rowid(db_);
-}
-
-boost::optional<JID> SQLiteHistoryManager::getJIDFromID(int id) const {
-	boost::optional<JID> result;
-	sqlite3_stmt* selectStatement;
-	std::string selectQuery("SELECT jid FROM jids WHERE id=" + boost::lexical_cast<std::string>(id));
-	int r = sqlite3_prepare(db_, selectQuery.c_str(), selectQuery.size(), &selectStatement, NULL);
-	if (r != SQLITE_OK) {
-		std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl;
-	}
-	r = sqlite3_step(selectStatement);
-	if (r == SQLITE_ROW) {
-		result = boost::optional<JID>(reinterpret_cast<const char*>(sqlite3_column_text(selectStatement, 0)));
-	}
-	sqlite3_finalize(selectStatement);
-	return result;
-}
-
-boost::optional<int> SQLiteHistoryManager::getIDFromJID(const JID& jid) const {
-	boost::optional<int> result;
-	sqlite3_stmt* selectStatement;
-	std::string selectQuery("SELECT id FROM jids WHERE jid='" + jid.toString() + "'");
-	int r = sqlite3_prepare(db_, selectQuery.c_str(), selectQuery.size(), &selectStatement, NULL);
-	if (r != SQLITE_OK) {
-		std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl;
-	}
-	r = sqlite3_step(selectStatement);
-	if (r == SQLITE_ROW) {
-		result = boost::optional<int>(sqlite3_column_int(selectStatement, 0));
-	}
-	sqlite3_finalize(selectStatement);
-	return result;
-}
-
-ContactsMap SQLiteHistoryManager::getContacts(const JID& selfJID, HistoryMessage::Type type, const std::string& keyword) const {
-	ContactsMap result;
-	sqlite3_stmt* selectStatement;
-
-	// get id
-	boost::optional<int> id = getIDFromJID(selfJID);
-	if (!id) {
-		return result;
-	}
-
-	// get contacts
-	std::string query = "SELECT DISTINCT messages.'fromBare', messages.'fromResource', messages.'toBare', messages.'toResource', messages.'time' "
-		"FROM messages WHERE (type="
-		+ boost::lexical_cast<std::string>(type) + " AND (toBare="
-		+ boost::lexical_cast<std::string>(*id) + " OR fromBare=" + boost::lexical_cast<std::string>(*id) + "))";
-
-	// match keyword
-	if (getEscapedString(keyword).length()) {
-		query += " AND message LIKE '%" + getEscapedString(keyword) + "%'";
-	}
-
-	int r = sqlite3_prepare(db_, query.c_str(), query.size(), &selectStatement, NULL);
-	if (r != SQLITE_OK) {
-		std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl;
-	}
-
-	r = sqlite3_step(selectStatement);
-	while (r == SQLITE_ROW) {
-		int fromBareID = sqlite3_column_int(selectStatement, 0);
-		std::string fromResource(reinterpret_cast<const char*>(sqlite3_column_text(selectStatement, 1)));
-		int toBareID = sqlite3_column_int(selectStatement, 2);
-		std::string toResource(reinterpret_cast<const char*>(sqlite3_column_text(selectStatement, 3)));
-		std::string resource;
-
-		int secondsSinceEpoch(sqlite3_column_int(selectStatement, 4));
-		boost::posix_time::ptime time(boost::gregorian::date(1970, 1, 1), boost::posix_time::seconds(secondsSinceEpoch));
-
-		boost::optional<JID> contactJID;
-
-		if (fromBareID == *id) {
-			contactJID = getJIDFromID(toBareID);
-			resource = toResource;
-		}
-		else {
-			contactJID = getJIDFromID(fromBareID);
-			resource = fromResource;
-		}
-
-		// check if it is a MUC contact (from a private conversation)
-		if (type == HistoryMessage::PrivateMessage) {
-			contactJID = boost::optional<JID>(JID(contactJID->getNode(), contactJID->getDomain(), resource));
-		}
-
-		if (contactJID) {
-			result[*contactJID].insert(time.date());
-		}
-
-		r = sqlite3_step(selectStatement);
-	}
-
-	if (r != SQLITE_DONE) {
-		std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl;
-	}
-	sqlite3_finalize(selectStatement);
-
-	return result;
-}
-
-boost::gregorian::date SQLiteHistoryManager::getNextDateWithLogs(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date, bool reverseOrder) const {
-	sqlite3_stmt* selectStatement;
-	boost::optional<int> selfID = getIDFromJID(selfJID.toBare());
-	boost::optional<int> contactID = getIDFromJID(contactJID.toBare());
-
-	if (!selfID || !contactID) {
-		// JIDs missing from the database
-		return boost::gregorian::date(boost::gregorian::not_a_date_time);
-	}
-
-	std::string selectQuery = "SELECT time FROM messages WHERE (type=" + boost::lexical_cast<std::string>(type);
-	if (contactJID.isBare()) {
-		// match only bare jid
-		selectQuery += " AND ((fromBare=" + boost::lexical_cast<std::string>(*selfID) + " AND toBare=" +
-				boost::lexical_cast<std::string>(*contactID) + ") OR (fromBare=" +
-				boost::lexical_cast<std::string>(*contactID) + " AND toBare=" + boost::lexical_cast<std::string>(*selfID) + ")))";
-	}
-	else {
-		// match resource too
-		selectQuery += " AND ((fromBare=" + boost::lexical_cast<std::string>(*selfID) + " AND (toBare=" +
-				boost::lexical_cast<std::string>(*contactID) +" AND toResource='" +
-				getEscapedString(contactJID.getResource()) + "')) OR ((fromBare=" +
-				boost::lexical_cast<std::string>(*contactID) + " AND fromResource='" +
-				getEscapedString(contactJID.getResource()) + "') AND toBare=" +
-				boost::lexical_cast<std::string>(*selfID) + ")))";
-	}
-
-	int timeStamp = (boost::posix_time::ptime(date) - boost::posix_time::ptime(boost::gregorian::date(1970, 1, 1))).total_seconds() + (reverseOrder ? 0 : 86400);
-
-	selectQuery += " AND time" + (reverseOrder ? std::string("<") : std::string(">")) + boost::lexical_cast<std::string>(timeStamp);
-	selectQuery += " ORDER BY time " + (reverseOrder ? std::string("DESC") : std::string("ASC")) + " LIMIT 1";
-
-	int r = sqlite3_prepare(db_, selectQuery.c_str(), selectQuery.size(), &selectStatement, NULL);
-	if (r != SQLITE_OK) {
-		std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl;
-	}
-
-	r = sqlite3_step(selectStatement);
-	if (r == SQLITE_ROW) {
-		int secondsSinceEpoch(sqlite3_column_int(selectStatement, 0));
-		boost::posix_time::ptime time(boost::gregorian::date(1970, 1, 1), boost::posix_time::seconds(secondsSinceEpoch));
-		std::cout << "next day is: " << time.date() << "\n";
-		return time.date();
-	}
-
-	return boost::gregorian::date(boost::gregorian::not_a_date_time);
-}
-
-std::vector<HistoryMessage> SQLiteHistoryManager::getMessagesFromNextDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const {
-	boost::gregorian::date nextDate = getNextDateWithLogs(selfJID, contactJID, type, date, false);
-
-	if (nextDate.is_not_a_date()) {
-		return std::vector<HistoryMessage>();
-	}
-
-	return getMessagesFromDate(selfJID, contactJID, type, nextDate);
-}
-
-std::vector<HistoryMessage> SQLiteHistoryManager::getMessagesFromPreviousDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const {
-	boost::gregorian::date previousDate = getNextDateWithLogs(selfJID, contactJID, type, date, true);
-
-	if (previousDate.is_not_a_date()) {
-		return std::vector<HistoryMessage>();
-	}
-
-	return getMessagesFromDate(selfJID, contactJID, type, previousDate);
-}
-
-boost::posix_time::ptime SQLiteHistoryManager::getLastTimeStampFromMUC(const JID& selfJID, const JID& mucJID) const {
-	boost::optional<int> selfID = getIDFromJID(selfJID.toBare());
-	boost::optional<int> mucID = getIDFromJID(mucJID.toBare());
-
-	if (!selfID || !mucID) {
-		// JIDs missing from the database
-		return boost::posix_time::ptime(boost::posix_time::not_a_date_time);
-	}
-
-
-	sqlite3_stmt* selectStatement;
-	std::string selectQuery = "SELECT messages.'time', messages.'offset' from messages WHERE type=1 AND (toBare=" +
-				boost::lexical_cast<std::string>(*selfID) + " AND fromBare=" +
-				boost::lexical_cast<std::string>(*mucID) + ") ORDER BY time DESC LIMIT 1";
-
-	int r = sqlite3_prepare(db_, selectQuery.c_str(), selectQuery.size(), &selectStatement, NULL);
-	if (r != SQLITE_OK) {
-		std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl;
-	}
-
-	r = sqlite3_step(selectStatement);
-	if (r == SQLITE_ROW) {
-		int secondsSinceEpoch(sqlite3_column_int(selectStatement, 0));
-		boost::posix_time::ptime time(boost::gregorian::date(1970, 1, 1), boost::posix_time::seconds(secondsSinceEpoch));
-		int offset = sqlite3_column_int(selectStatement, 1);
-
-		return time - boost::posix_time::hours(offset);
-	}
-
-	return boost::posix_time::ptime(boost::posix_time::not_a_date_time);
-}
-
-}
diff --git a/Swiften/History/SQLiteHistoryManager.h b/Swiften/History/SQLiteHistoryManager.h
deleted file mode 100644
index b74fbde..0000000
--- a/Swiften/History/SQLiteHistoryManager.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2010 Remko Tronçon
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
- */
-
-#pragma once
-
-#include <boost/optional.hpp>
-
-#include <Swiften/History/HistoryManager.h>
-
-struct sqlite3;
-
-namespace Swift {
-	class SQLiteHistoryManager : public HistoryManager {
-		public:
-			SQLiteHistoryManager(const std::string& file);
-			~SQLiteHistoryManager();
-
-			void addMessage(const HistoryMessage& message);
-			ContactsMap getContacts(const JID& selfJID, HistoryMessage::Type type, const std::string& keyword) const;
-			std::vector<HistoryMessage> getMessagesFromDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const;
-			std::vector<HistoryMessage> getMessagesFromNextDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const;
-			std::vector<HistoryMessage> getMessagesFromPreviousDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const;
-			boost::posix_time::ptime getLastTimeStampFromMUC(const JID& selfJID, const JID& mucJID) const;
-
-		private:
-			boost::gregorian::date getNextDateWithLogs(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date, bool reverseOrder) const;
-			int getIDForJID(const JID&);
-			int addJID(const JID&);
-
-			boost::optional<JID> getJIDFromID(int id) const;
-			boost::optional<int> getIDFromJID(const JID& jid) const;
-
-			sqlite3* db_;
-	};
-}
diff --git a/Swiften/History/SQLiteHistoryStorage.cpp b/Swiften/History/SQLiteHistoryStorage.cpp
new file mode 100644
index 0000000..5e3148b
--- /dev/null
+++ b/Swiften/History/SQLiteHistoryStorage.cpp
@@ -0,0 +1,374 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <iostream>
+#include <boost/lexical_cast.hpp>
+
+#include <sqlite3.h>
+#include <Swiften/History/SQLiteHistoryStorage.h>
+#include <boost/date_time/gregorian/gregorian.hpp>
+
+inline std::string getEscapedString(const std::string& s) {
+	std::string result(s);
+
+	size_t pos = result.find('\'');
+	while (pos != std::string::npos) {
+		result.insert(pos, "'");
+		pos = result.find('\'', pos + 2);
+	}
+	return result;
+}
+
+namespace Swift {
+
+SQLiteHistoryStorage::SQLiteHistoryStorage(const std::string& file) : db_(0) {
+	sqlite3_open(file.c_str(), &db_);
+	if (!db_) {
+		std::cerr << "Error opening database " << file << std::endl;
+	}
+
+	char* errorMessage;
+	int result = sqlite3_exec(db_, "CREATE TABLE IF NOT EXISTS messages('message' STRING, 'fromBare' INTEGER, 'fromResource' STRING, 'toBare' INTEGER, 'toResource' STRING, 'type' INTEGER, 'time' INTEGER, 'offset' INTEGER)", 0, 0, &errorMessage);
+	if (result != SQLITE_OK) {
+		std::cerr << "SQL Error: " << errorMessage << std::endl;
+		sqlite3_free(errorMessage);
+	}
+
+	result = sqlite3_exec(db_, "CREATE TABLE IF NOT EXISTS jids('id' INTEGER PRIMARY KEY ASC AUTOINCREMENT, 'jid' STRING UNIQUE NOT NULL)", 0, 0, &errorMessage);
+	if (result != SQLITE_OK) {
+		std::cerr << "SQL Error: " << errorMessage << std::endl;
+		sqlite3_free(errorMessage);
+	}
+}
+
+SQLiteHistoryStorage::~SQLiteHistoryStorage() {
+	sqlite3_close(db_);
+}
+
+void SQLiteHistoryStorage::addMessage(const HistoryMessage& message) {
+	int secondsSinceEpoch = (message.getTime() - boost::posix_time::ptime(boost::gregorian::date(1970, 1, 1))).total_seconds();
+
+	std::string statement = std::string("INSERT INTO messages('message', 'fromBare', 'fromResource', 'toBare', 'toResource', 'type', 'time', 'offset') VALUES(") +
+					"'" + getEscapedString(message.getMessage()) + "', " +
+					boost::lexical_cast<std::string>(getIDForJID(message.getFromJID().toBare())) + ", '" +
+					getEscapedString(message.getFromJID().getResource()) + "', " +
+					boost::lexical_cast<std::string>(getIDForJID(message.getToJID().toBare())) + ", '" +
+					getEscapedString(message.getToJID().getResource()) + "', " +
+					boost::lexical_cast<std::string>(message.getType()) + ", " +
+					boost::lexical_cast<std::string>(secondsSinceEpoch) + ", " +
+					boost::lexical_cast<std::string>(message.getOffset()) + ")";
+	char* errorMessage;
+	int result = sqlite3_exec(db_, statement.c_str(), 0, 0, &errorMessage);
+	if (result != SQLITE_OK) {
+		std::cerr << "SQL Error: " << errorMessage << std::endl;
+		sqlite3_free(errorMessage);
+	}
+}
+
+std::vector<HistoryMessage> SQLiteHistoryStorage::getMessagesFromDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const {
+	sqlite3_stmt* selectStatement;
+
+	boost::optional<int> selfID = getIDFromJID(selfJID.toBare());
+	boost::optional<int> contactID = getIDFromJID(contactJID.toBare());
+
+	if (!selfID || !contactID) {
+		// JIDs missing from the database
+		return std::vector<HistoryMessage>();
+	}
+
+	std::string selectQuery = "SELECT * FROM messages WHERE (type=" + boost::lexical_cast<std::string>(type);
+	if (contactJID.isBare()) {
+		// match only bare jid
+		selectQuery += " AND ((fromBare=" + boost::lexical_cast<std::string>(*selfID) + " AND toBare=" +
+				boost::lexical_cast<std::string>(*contactID) + ") OR (fromBare=" +
+				boost::lexical_cast<std::string>(*contactID) + " AND toBare=" + boost::lexical_cast<std::string>(*selfID) + ")))";
+	}
+	else {
+		// match resource too
+		selectQuery += " AND ((fromBare=" + boost::lexical_cast<std::string>(*selfID) + " AND (toBare=" +
+				boost::lexical_cast<std::string>(*contactID) +" AND toResource='" +
+				getEscapedString(contactJID.getResource()) + "')) OR ((fromBare=" +
+				boost::lexical_cast<std::string>(*contactID) + " AND fromResource='" +
+				getEscapedString(contactJID.getResource()) + "') AND toBare=" +
+				boost::lexical_cast<std::string>(*selfID) + ")))";
+	}
+
+	if (!date.is_not_a_date()) {
+		int lowerBound = (boost::posix_time::ptime(date) - boost::posix_time::ptime(boost::gregorian::date(1970, 1, 1))).total_seconds();
+		int upperBound = lowerBound + 86400;
+
+		selectQuery += " AND (time>=" + boost::lexical_cast<std::string>(lowerBound) +
+				" AND time<" + boost::lexical_cast<std::string>(upperBound) + ")";
+	}
+
+	int r = sqlite3_prepare(db_, selectQuery.c_str(), selectQuery.size(), &selectStatement, NULL);
+	if (r != SQLITE_OK) {
+		std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl;
+	}
+	r = sqlite3_step(selectStatement);
+
+	// Retrieve result
+	std::vector<HistoryMessage> result;
+	while (r == SQLITE_ROW) {
+		std::string message(reinterpret_cast<const char*>(sqlite3_column_text(selectStatement, 0)));
+
+		// fromJID
+		boost::optional<JID> fromJID(getJIDFromID(sqlite3_column_int(selectStatement, 1)));
+		std::string fromResource(reinterpret_cast<const char*>(sqlite3_column_text(selectStatement, 2)));
+		if (fromJID) {
+			fromJID = boost::optional<JID>(JID(fromJID->getNode(), fromJID->getDomain(), fromResource));
+		}
+
+		// toJID
+		boost::optional<JID> toJID(getJIDFromID(sqlite3_column_int(selectStatement, 3)));
+		std::string toResource(reinterpret_cast<const char*>(sqlite3_column_text(selectStatement, 4)));
+		if (toJID) {
+			toJID = boost::optional<JID>(JID(toJID->getNode(), toJID->getDomain(), toResource));
+		}
+
+		// message type
+		HistoryMessage::Type type = static_cast<HistoryMessage::Type>(sqlite3_column_int(selectStatement, 5));
+
+		// timestamp
+		int secondsSinceEpoch(sqlite3_column_int(selectStatement, 6));
+		boost::posix_time::ptime time(boost::gregorian::date(1970, 1, 1), boost::posix_time::seconds(secondsSinceEpoch));
+
+		// offset from utc
+		int offset = sqlite3_column_int(selectStatement, 7);
+
+		result.push_back(HistoryMessage(message, (fromJID ? *fromJID : JID()), (toJID ? *toJID : JID()), type, time, offset));
+		r = sqlite3_step(selectStatement);
+	}
+	if (r != SQLITE_DONE) {
+		std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl;
+	}
+	sqlite3_finalize(selectStatement);
+
+	return result;
+}
+
+int SQLiteHistoryStorage::getIDForJID(const JID& jid) {
+	boost::optional<int> id = getIDFromJID(jid);
+	if (id) {
+		return *id;
+	}
+	else {
+		return addJID(jid);
+	}
+}
+
+int SQLiteHistoryStorage::addJID(const JID& jid) {
+	std::string statement = std::string("INSERT INTO jids('jid') VALUES('") + getEscapedString(jid.toString()) + "')";
+	char* errorMessage;
+	int result = sqlite3_exec(db_, statement.c_str(), 0, 0, &errorMessage);
+	if (result != SQLITE_OK) {
+		std::cerr << "SQL Error: " << errorMessage << std::endl;
+		sqlite3_free(errorMessage);
+	}
+	return sqlite3_last_insert_rowid(db_);
+}
+
+boost::optional<JID> SQLiteHistoryStorage::getJIDFromID(int id) const {
+	boost::optional<JID> result;
+	sqlite3_stmt* selectStatement;
+	std::string selectQuery("SELECT jid FROM jids WHERE id=" + boost::lexical_cast<std::string>(id));
+	int r = sqlite3_prepare(db_, selectQuery.c_str(), selectQuery.size(), &selectStatement, NULL);
+	if (r != SQLITE_OK) {
+		std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl;
+	}
+	r = sqlite3_step(selectStatement);
+	if (r == SQLITE_ROW) {
+		result = boost::optional<JID>(reinterpret_cast<const char*>(sqlite3_column_text(selectStatement, 0)));
+	}
+	sqlite3_finalize(selectStatement);
+	return result;
+}
+
+boost::optional<int> SQLiteHistoryStorage::getIDFromJID(const JID& jid) const {
+	boost::optional<int> result;
+	sqlite3_stmt* selectStatement;
+	std::string selectQuery("SELECT id FROM jids WHERE jid='" + jid.toString() + "'");
+	int r = sqlite3_prepare(db_, selectQuery.c_str(), selectQuery.size(), &selectStatement, NULL);
+	if (r != SQLITE_OK) {
+		std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl;
+	}
+	r = sqlite3_step(selectStatement);
+	if (r == SQLITE_ROW) {
+		result = boost::optional<int>(sqlite3_column_int(selectStatement, 0));
+	}
+	sqlite3_finalize(selectStatement);
+	return result;
+}
+
+ContactsMap SQLiteHistoryStorage::getContacts(const JID& selfJID, HistoryMessage::Type type, const std::string& keyword) const {
+	ContactsMap result;
+	sqlite3_stmt* selectStatement;
+
+	// get id
+	boost::optional<int> id = getIDFromJID(selfJID);
+	if (!id) {
+		return result;
+	}
+
+	// get contacts
+	std::string query = "SELECT DISTINCT messages.'fromBare', messages.'fromResource', messages.'toBare', messages.'toResource', messages.'time' "
+		"FROM messages WHERE (type="
+		+ boost::lexical_cast<std::string>(type) + " AND (toBare="
+		+ boost::lexical_cast<std::string>(*id) + " OR fromBare=" + boost::lexical_cast<std::string>(*id) + "))";
+
+	// match keyword
+	if (getEscapedString(keyword).length()) {
+		query += " AND message LIKE '%" + getEscapedString(keyword) + "%'";
+	}
+
+	int r = sqlite3_prepare(db_, query.c_str(), query.size(), &selectStatement, NULL);
+	if (r != SQLITE_OK) {
+		std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl;
+	}
+
+	r = sqlite3_step(selectStatement);
+	while (r == SQLITE_ROW) {
+		int fromBareID = sqlite3_column_int(selectStatement, 0);
+		std::string fromResource(reinterpret_cast<const char*>(sqlite3_column_text(selectStatement, 1)));
+		int toBareID = sqlite3_column_int(selectStatement, 2);
+		std::string toResource(reinterpret_cast<const char*>(sqlite3_column_text(selectStatement, 3)));
+		std::string resource;
+
+		int secondsSinceEpoch(sqlite3_column_int(selectStatement, 4));
+		boost::posix_time::ptime time(boost::gregorian::date(1970, 1, 1), boost::posix_time::seconds(secondsSinceEpoch));
+
+		boost::optional<JID> contactJID;
+
+		if (fromBareID == *id) {
+			contactJID = getJIDFromID(toBareID);
+			resource = toResource;
+		}
+		else {
+			contactJID = getJIDFromID(fromBareID);
+			resource = fromResource;
+		}
+
+		// check if it is a MUC contact (from a private conversation)
+		if (type == HistoryMessage::PrivateMessage) {
+			contactJID = boost::optional<JID>(JID(contactJID->getNode(), contactJID->getDomain(), resource));
+		}
+
+		if (contactJID) {
+			result[*contactJID].insert(time.date());
+		}
+
+		r = sqlite3_step(selectStatement);
+	}
+
+	if (r != SQLITE_DONE) {
+		std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl;
+	}
+	sqlite3_finalize(selectStatement);
+
+	return result;
+}
+
+boost::gregorian::date SQLiteHistoryStorage::getNextDateWithLogs(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date, bool reverseOrder) const {
+	sqlite3_stmt* selectStatement;
+	boost::optional<int> selfID = getIDFromJID(selfJID.toBare());
+	boost::optional<int> contactID = getIDFromJID(contactJID.toBare());
+
+	if (!selfID || !contactID) {
+		// JIDs missing from the database
+		return boost::gregorian::date(boost::gregorian::not_a_date_time);
+	}
+
+	std::string selectQuery = "SELECT time FROM messages WHERE (type=" + boost::lexical_cast<std::string>(type);
+	if (contactJID.isBare()) {
+		// match only bare jid
+		selectQuery += " AND ((fromBare=" + boost::lexical_cast<std::string>(*selfID) + " AND toBare=" +
+				boost::lexical_cast<std::string>(*contactID) + ") OR (fromBare=" +
+				boost::lexical_cast<std::string>(*contactID) + " AND toBare=" + boost::lexical_cast<std::string>(*selfID) + ")))";
+	}
+	else {
+		// match resource too
+		selectQuery += " AND ((fromBare=" + boost::lexical_cast<std::string>(*selfID) + " AND (toBare=" +
+				boost::lexical_cast<std::string>(*contactID) +" AND toResource='" +
+				getEscapedString(contactJID.getResource()) + "')) OR ((fromBare=" +
+				boost::lexical_cast<std::string>(*contactID) + " AND fromResource='" +
+				getEscapedString(contactJID.getResource()) + "') AND toBare=" +
+				boost::lexical_cast<std::string>(*selfID) + ")))";
+	}
+
+	int timeStamp = (boost::posix_time::ptime(date) - boost::posix_time::ptime(boost::gregorian::date(1970, 1, 1))).total_seconds() + (reverseOrder ? 0 : 86400);
+
+	selectQuery += " AND time" + (reverseOrder ? std::string("<") : std::string(">")) + boost::lexical_cast<std::string>(timeStamp);
+	selectQuery += " ORDER BY time " + (reverseOrder ? std::string("DESC") : std::string("ASC")) + " LIMIT 1";
+
+	int r = sqlite3_prepare(db_, selectQuery.c_str(), selectQuery.size(), &selectStatement, NULL);
+	if (r != SQLITE_OK) {
+		std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl;
+	}
+
+	r = sqlite3_step(selectStatement);
+	if (r == SQLITE_ROW) {
+		int secondsSinceEpoch(sqlite3_column_int(selectStatement, 0));
+		boost::posix_time::ptime time(boost::gregorian::date(1970, 1, 1), boost::posix_time::seconds(secondsSinceEpoch));
+		std::cout << "next day is: " << time.date() << "\n";
+		return time.date();
+	}
+
+	return boost::gregorian::date(boost::gregorian::not_a_date_time);
+}
+
+std::vector<HistoryMessage> SQLiteHistoryStorage::getMessagesFromNextDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const {
+	boost::gregorian::date nextDate = getNextDateWithLogs(selfJID, contactJID, type, date, false);
+
+	if (nextDate.is_not_a_date()) {
+		return std::vector<HistoryMessage>();
+	}
+
+	return getMessagesFromDate(selfJID, contactJID, type, nextDate);
+}
+
+std::vector<HistoryMessage> SQLiteHistoryStorage::getMessagesFromPreviousDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const {
+	boost::gregorian::date previousDate = getNextDateWithLogs(selfJID, contactJID, type, date, true);
+
+	if (previousDate.is_not_a_date()) {
+		return std::vector<HistoryMessage>();
+	}
+
+	return getMessagesFromDate(selfJID, contactJID, type, previousDate);
+}
+
+boost::posix_time::ptime SQLiteHistoryStorage::getLastTimeStampFromMUC(const JID& selfJID, const JID& mucJID) const {
+	boost::optional<int> selfID = getIDFromJID(selfJID.toBare());
+	boost::optional<int> mucID = getIDFromJID(mucJID.toBare());
+
+	if (!selfID || !mucID) {
+		// JIDs missing from the database
+		return boost::posix_time::ptime(boost::posix_time::not_a_date_time);
+	}
+
+
+	sqlite3_stmt* selectStatement;
+	std::string selectQuery = "SELECT messages.'time', messages.'offset' from messages WHERE type=1 AND (toBare=" +
+				boost::lexical_cast<std::string>(*selfID) + " AND fromBare=" +
+				boost::lexical_cast<std::string>(*mucID) + ") ORDER BY time DESC LIMIT 1";
+
+	int r = sqlite3_prepare(db_, selectQuery.c_str(), selectQuery.size(), &selectStatement, NULL);
+	if (r != SQLITE_OK) {
+		std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl;
+	}
+
+	r = sqlite3_step(selectStatement);
+	if (r == SQLITE_ROW) {
+		int secondsSinceEpoch(sqlite3_column_int(selectStatement, 0));
+		boost::posix_time::ptime time(boost::gregorian::date(1970, 1, 1), boost::posix_time::seconds(secondsSinceEpoch));
+		int offset = sqlite3_column_int(selectStatement, 1);
+
+		return time - boost::posix_time::hours(offset);
+	}
+
+	return boost::posix_time::ptime(boost::posix_time::not_a_date_time);
+}
+
+}
diff --git a/Swiften/History/SQLiteHistoryStorage.h b/Swiften/History/SQLiteHistoryStorage.h
new file mode 100644
index 0000000..aae6db8
--- /dev/null
+++ b/Swiften/History/SQLiteHistoryStorage.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/optional.hpp>
+
+#include <Swiften/History/HistoryStorage.h>
+
+struct sqlite3;
+
+namespace Swift {
+	class SQLiteHistoryStorage : public HistoryStorage {
+		public:
+			SQLiteHistoryStorage(const std::string& file);
+			~SQLiteHistoryStorage();
+
+			void addMessage(const HistoryMessage& message);
+			ContactsMap getContacts(const JID& selfJID, HistoryMessage::Type type, const std::string& keyword) const;
+			std::vector<HistoryMessage> getMessagesFromDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const;
+			std::vector<HistoryMessage> getMessagesFromNextDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const;
+			std::vector<HistoryMessage> getMessagesFromPreviousDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const;
+			boost::posix_time::ptime getLastTimeStampFromMUC(const JID& selfJID, const JID& mucJID) const;
+
+		private:
+			boost::gregorian::date getNextDateWithLogs(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date, bool reverseOrder) const;
+			int getIDForJID(const JID&);
+			int addJID(const JID&);
+
+			boost::optional<JID> getJIDFromID(int id) const;
+			boost::optional<int> getIDFromJID(const JID& jid) const;
+
+			sqlite3* db_;
+	};
+}
-- 
cgit v0.10.2-6-g49f6