diff --git a/include/transport/ConversationManager.h b/include/transport/ConversationManager.h index 1bc04718..e3b08847 100644 --- a/include/transport/ConversationManager.h +++ b/include/transport/ConversationManager.h @@ -24,6 +24,7 @@ #include #include +#include "StorageBackend.h" #include "Swiften/Elements/Message.h" namespace Transport { @@ -40,7 +41,7 @@ class ConversationManager { /// \param user User associated with this ConversationManager. /// \param component Transport instance associated with this /// ConversationManager. - ConversationManager(User *user, Component *component); + ConversationManager(User *user, Component *component, StorageBackend *storageBackend); /// Destructor. virtual ~ConversationManager(); @@ -88,6 +89,8 @@ class ConversationManager { return m_convs; } + StorageBackend *m_storageBackend; + private: void handleMessageReceived(Swift::Message::ref message); diff --git a/include/transport/PQXXBackend.h b/include/transport/PQXXBackend.h index d6518d32..d35f60b5 100644 --- a/include/transport/PQXXBackend.h +++ b/include/transport/PQXXBackend.h @@ -26,6 +26,7 @@ #include #include +#include "Swiften/Elements/Delay.h" #include "transport/Config.h" #include "transport/StorageBackend.h" @@ -104,6 +105,7 @@ class PQXXBackend : public StorageBackend { void updateUserSetting(long userId, const std::string &variable, const std::string &value); void addMucName(long userId, const std::string &mucId, const std::string &mucName); std::string getMucName(long userId, const std::string &mucId); + void storeMUCHistory(long userid, const std::string &mucId, const Swift::Message &message); void beginTransaction(); void commitTransaction(); diff --git a/include/transport/SQLite3Backend.h b/include/transport/SQLite3Backend.h index 78f8c44f..2ee69b05 100644 --- a/include/transport/SQLite3Backend.h +++ b/include/transport/SQLite3Backend.h @@ -101,6 +101,8 @@ class SQLite3Backend : public StorageBackend { void addMucName(long userId, const std::string &mucId, const std::string &mucName); std::string getMucName(long userId, const std::string &mucId); + void storeMUCHistory(long userid, const std::string &mucId, const Swift::Message &message); + void beginTransaction(); void commitTransaction(); diff --git a/include/transport/StorageBackend.h b/include/transport/StorageBackend.h index 434b87ec..b37480d8 100644 --- a/include/transport/StorageBackend.h +++ b/include/transport/StorageBackend.h @@ -20,6 +20,7 @@ #pragma once +#include "Swiften/Elements/Message.h" #include #include #include @@ -142,6 +143,8 @@ class StorageBackend { virtual void addMucName(long userId, const std::string &mucId, const std::string &mucName) = 0; virtual std::string getMucName(long userId, const std::string &mucId) = 0; + virtual void storeMUCHistory(long userid, const std::string &mucId, const Swift::Message &message) = 0; + /// onStorageError // boost::signal onStorageError; diff --git a/include/transport/User.h b/include/transport/User.h index 4f8ce1c4..af8968c8 100644 --- a/include/transport/User.h +++ b/include/transport/User.h @@ -172,6 +172,10 @@ class User { void leaveRoom(const std::string &room); + long getUserId() { + return m_userInfo.id; + } + boost::signals2::signal onReadyToConnect; boost::signals2::signal onPresenceChanged; boost::signals2::signal onRawPresenceReceived; diff --git a/libtransport/Conversation.cpp b/libtransport/Conversation.cpp index c86ca982..aa854dcb 100644 --- a/libtransport/Conversation.cpp +++ b/libtransport/Conversation.cpp @@ -161,6 +161,11 @@ void Conversation::handleRawMessage(std::shared_ptr &message) { std::string hashId = generateMessageId(message); if (hashId != "") { message->setID(hashId); + if (message->getType() == Swift::Message::Groupchat) { + long uid = m_conversationManager->getUser()->getUserId(); + std::string mucJid = m_jid.toString(); + m_conversationManager->m_storageBackend->storeMUCHistory(uid, mucJid, *message); + } } if (message->getType() != Swift::Message::Groupchat) { m_conversationManager->getComponent()->getFrontend()->sendMessage(message); diff --git a/libtransport/ConversationManager.cpp b/libtransport/ConversationManager.cpp index 48742c2a..a8fd832c 100644 --- a/libtransport/ConversationManager.cpp +++ b/libtransport/ConversationManager.cpp @@ -34,9 +34,10 @@ namespace Transport { DEFINE_LOGGER(logger, "ConversationManager"); -ConversationManager::ConversationManager(User *user, Component *component) { +ConversationManager::ConversationManager(User *user, Component *component, StorageBackend *storageBackend) { m_user = user; m_component = component; + m_storageBackend = storageBackend; } ConversationManager::~ConversationManager() { diff --git a/libtransport/PQXXBackend.cpp b/libtransport/PQXXBackend.cpp index fd827ab2..53ed6981 100644 --- a/libtransport/PQXXBackend.cpp +++ b/libtransport/PQXXBackend.cpp @@ -26,6 +26,9 @@ #include "log4cxx/logger.h" #include "transport/Util.h" +#include +#include +#include using namespace log4cxx; @@ -133,6 +136,32 @@ bool PQXXBackend::createDatabase() { "UNIQUE(user_id, muc_id)" ");"); + exec("CREATE TABLE IF NOT EXISTS " + m_prefix + + "muc_history (" + "user_id INTEGER NOT NULL," + "muc_id VARCHAR NOT NULL," + "message_id VARCHAR NOT NULL," + "timestamp TIMESTAMP NOT NULL," + "jid VARCHAR NOT NULL," + "body VARCHAR NOT NULL" + ");"); + + exec("CREATE INDEX IF NOT EXISTS " + m_prefix + + "muc_history_idx " + "ON " + + m_prefix + + "muc_history" + "(user_id, muc_id, timestamp);"); + + exec("CREATE TABLE IF NOT EXISTS " + m_prefix + + "muc_history_pointers (" + "user_id INTEGER NOT NULL," + "muc_id VARCHAR NOT NULL," + "resource VARCHAR NOT NULL," + "last_timestamp TIMESTAMP NOT NULL," + "UNIQUE(user_id, muc_id, resource)" + ");"); + return true; } @@ -439,6 +468,37 @@ std::string PQXXBackend::getMucName(long userId, const std::string &mucId) { } } +long epoch(boost::posix_time::ptime ts) { + boost::posix_time::ptime time_t_epoch(boost::gregorian::date(1970, 1, 1)); + boost::posix_time::time_duration diff = ts - time_t_epoch; + return diff.total_seconds(); +} + +void PQXXBackend::storeMUCHistory(long userid, const std::string &mucId, const Swift::Message &message) { + try { + const std::shared_ptr delay = message.getPayload(); + const std::string from = message.getFrom().toString(); + std::string body = message.getBody().get_value_or(""); + std::string messageId = message.getID(); + boost::posix_time::ptime timestamp = boost::posix_time::second_clock::universal_time(); + if (delay.get() != NULL) { + timestamp = delay.get()->getStamp(); + } + if (body == "" || messageId == "") { + LOG4CXX_WARN(logger, "Attempted to store MUC history with incomplete message!"); + return; + } + pqxx::nontransaction txn(*m_conn); + txn.exec_params("INSERT INTO " + m_prefix + + "muc_history (user_id, muc_id, message_id, timestamp, jid, body) VALUES ($1, $2, $3, " + "to_timestamp($4), $5, $6)", + userid, mucId, messageId, epoch(timestamp), from, body); + } catch (std::exception &e) { + LOG4CXX_ERROR(logger, e.what()); + connect(); + } +} + void PQXXBackend::beginTransaction() { exec("BEGIN;"); } diff --git a/libtransport/SQLite3Backend.cpp b/libtransport/SQLite3Backend.cpp index 8b37a02c..4da42d4b 100644 --- a/libtransport/SQLite3Backend.cpp +++ b/libtransport/SQLite3Backend.cpp @@ -596,6 +596,10 @@ std::string SQLite3Backend::getMucName(long userId, const std::string &mucId) { LOG4CXX_ERROR(logger, "getMucName() not implemented in sqlite3 backend yet"); return ""; } +void SQLite3Backend::storeMUCHistory(long userid, const std::string &mucId, const Swift::Message &message) { + LOG4CXX_ERROR(logger, "storeMUCHistory() not implemented in sqlite3 backend yet"); + return; +} void SQLite3Backend::beginTransaction() { exec("BEGIN TRANSACTION;"); diff --git a/libtransport/User.cpp b/libtransport/User.cpp index 1152f5d0..c4d6613a 100644 --- a/libtransport/User.cpp +++ b/libtransport/User.cpp @@ -68,7 +68,7 @@ User::User(const Swift::JID &jid, UserInfo &userInfo, Component *component, User m_reconnectTimer->onTick.connect(boost::bind(&User::onConnectingTimeout, this)); m_rosterManager = component->getFrontend()->createRosterManager(this, m_component); - m_conversationManager = new ConversationManager(this, m_component); + m_conversationManager = new ConversationManager(this, m_component, userManager->m_storageBackend); LOG4CXX_INFO(logger, m_jid.toString() << ": Created"); updateLastActivity(); diff --git a/src/frontends/xmpp/XMPPUser.h b/src/frontends/xmpp/XMPPUser.h index fb3c732b..dff63c75 100644 --- a/src/frontends/xmpp/XMPPUser.h +++ b/src/frontends/xmpp/XMPPUser.h @@ -84,10 +84,6 @@ class XMPPUser : public User { } } - long getUserId() { - return m_userInfo.id; - } - private: void onConnectingTimeout(); void handleVCardReceived(std::shared_ptr vcard, Swift::ErrorPayload::ref error,