diff --git a/include/transport/buddy.h b/include/transport/buddy.h index fd728915..c52f30fc 100644 --- a/include/transport/buddy.h +++ b/include/transport/buddy.h @@ -39,7 +39,7 @@ typedef enum { BUDDY_NO_FLAG = 0, class Buddy { public: /// Constructor. - Buddy(RosterManager *rosterManager, long id); + Buddy(RosterManager *rosterManager, long id = -1); /// Destructor virtual ~Buddy(); diff --git a/include/transport/rostermanager.h b/include/transport/rostermanager.h index d31d2fca..ce5bcb6c 100644 --- a/include/transport/rostermanager.h +++ b/include/transport/rostermanager.h @@ -31,6 +31,8 @@ namespace Transport { class Buddy; class User; class Component; +class StorageBackend; +class RosterStorage; /// Manages roster of one XMPP user. class RosterManager { @@ -56,6 +58,8 @@ class RosterManager { Buddy *getBuddy(const std::string &name); + void setStorageBackend(StorageBackend *storageBackend); + /// Returns user associated with this roster. /// \return User User *getUser() { return m_user; } @@ -80,6 +84,7 @@ class RosterManager { std::map m_buddies; Component *m_component; + RosterStorage *m_rosterStorage; User *m_user; Swift::Timer::ref m_setBuddyTimer; Swift::Timer::ref m_RIETimer; diff --git a/include/transport/rosterstorage.h b/include/transport/rosterstorage.h new file mode 100644 index 00000000..bd5cc7db --- /dev/null +++ b/include/transport/rosterstorage.h @@ -0,0 +1,57 @@ +/** + * XMPP - libpurple transport + * + * Copyright (C) 2009, Jan Kaluza + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#pragma once + +#include +#include +#include "Swiften/Swiften.h" + +namespace Transport { + +class User; +class StorageBackend; +class Buddy; + +// Stores buddies into DB Backend. +class RosterStorage { + public: + RosterStorage(User *user, StorageBackend *storageBackend); + virtual ~RosterStorage(); + + // Add buddy to store queue and store it in future. Nothing + // will happen if buddy is already added. + void storeBuddy(Buddy *buddy); + + // Store all buddies from queue immediately. Returns true + // if some buddies were stored. + bool storeBuddies(); + + // Remove buddy from storage queue. + void removeBuddyFromQueue(Buddy *buddy); + + private: + User *m_user; + StorageBackend *m_storageBackend; + std::map m_buddies; + Swift::Timer::ref m_storageTimer; +}; + +} diff --git a/include/transport/sqlite3backend.h b/include/transport/sqlite3backend.h index 3c2b80af..87852022 100644 --- a/include/transport/sqlite3backend.h +++ b/include/transport/sqlite3backend.h @@ -79,6 +79,13 @@ class SQLite3Backend : public StorageBackend /// \return true if user has been found in database and roster has been fetched bool getBuddies(long id, std::list &roster); + long addBuddy(long userId, const BuddyInfo &buddyInfo) { return 0; } + void updateBuddy(long userId, const BuddyInfo &buddyInfo) {} + void removeBuddy(long id) {} + + void beginTransaction() {} + void commitTransaction() {} + private: bool exec(const std::string &query); diff --git a/include/transport/storagebackend.h b/include/transport/storagebackend.h index 130a2a43..0ca1a67c 100644 --- a/include/transport/storagebackend.h +++ b/include/transport/storagebackend.h @@ -36,6 +36,15 @@ struct UserInfo { bool vip; ///< true if user is VIP }; +struct BuddyInfo { + long id; + std::string alias; + std::string legacyName; + std::string subscription; + std::vector groups; + int flags; +}; + /// Abstract class defining storage backends. class StorageBackend { @@ -64,6 +73,13 @@ class StorageBackend /// getBuddies virtual bool getBuddies(long id, std::list &roster) = 0; + virtual long addBuddy(long userId, const BuddyInfo &buddyInfo) = 0; + virtual void updateBuddy(long userId, const BuddyInfo &buddyInfo) = 0; + virtual void removeBuddy(long id) = 0; + + virtual void beginTransaction() = 0; + virtual void commitTransaction() = 0; + /// onStorageError boost::signal onStorageError; diff --git a/include/transport/user.h b/include/transport/user.h index 126e5a92..87e80f99 100644 --- a/include/transport/user.h +++ b/include/transport/user.h @@ -59,7 +59,6 @@ class User { ConversationManager *getConversationManager() { return m_conversationManager; } - Component *getComponent() { return m_component; } void setData(void *data) { m_data = data; } diff --git a/src/rostermanager.cpp b/src/rostermanager.cpp index 7c8f912e..f7ff0679 100644 --- a/src/rostermanager.cpp +++ b/src/rostermanager.cpp @@ -19,6 +19,8 @@ */ #include "transport/rostermanager.h" +#include "transport/rosterstorage.h" +#include "transport/storagebackend.h" #include "transport/buddy.h" #include "transport/usermanager.h" #include "transport/buddy.h" @@ -31,6 +33,7 @@ namespace Transport { RosterManager::RosterManager(User *user, Component *component){ + m_rosterStorage = NULL; m_user = user; m_component = component; m_setBuddyTimer = m_component->getFactories()->getTimerFactory()->createTimer(1000); @@ -41,6 +44,8 @@ RosterManager::RosterManager(User *user, Component *component){ RosterManager::~RosterManager() { m_setBuddyTimer->stop(); m_RIETimer->stop(); + if (m_rosterStorage) + delete m_rosterStorage; } void RosterManager::setBuddy(Buddy *buddy) { @@ -87,6 +92,8 @@ void RosterManager::setBuddyCallback(Buddy *buddy) { void RosterManager::unsetBuddy(Buddy *buddy) { m_buddies.erase(buddy->getName()); + if (m_rosterStorage) + m_rosterStorage->removeBuddyFromQueue(buddy); onBuddyUnset(buddy); } @@ -121,6 +128,15 @@ void RosterManager::sendRIE() { void RosterManager::handleSubscription(Swift::Presence::ref presence) { std::string legacyName = Buddy::JIDToLegacyName(presence->getTo()); + +} + +void RosterManager::setStorageBackend(StorageBackend *storageBackend) { + if (m_rosterStorage) { + m_rosterStorage->storeBuddies(); + delete m_rosterStorage; + } + m_rosterStorage = new RosterStorage(m_user, storageBackend); } } diff --git a/src/rosterstorage.cpp b/src/rosterstorage.cpp new file mode 100644 index 00000000..a3659079 --- /dev/null +++ b/src/rosterstorage.cpp @@ -0,0 +1,137 @@ +/** + * XMPP - libpurple transport + * + * Copyright (C) 2009, Jan Kaluza + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#include "transport/rosterstorage.h" +#include "transport/buddy.h" +#include "transport/user.h" +#include "transport/storagebackend.h" + +namespace Transport { + +// static void save_settings(gpointer k, gpointer v, gpointer data) { +// PurpleValue *value = (PurpleValue *) v; +// std::string key((char *) k); +// SaveData *s = (SaveData *) data; +// AbstractUser *user = s->user; +// long id = s->id; +// if (purple_value_get_type(value) == PURPLE_TYPE_BOOLEAN) { +// if (purple_value_get_boolean(value)) +// Transport::instance()->sql()->addBuddySetting(user->storageId(), id, key, "1", purple_value_get_type(value)); +// else +// Transport::instance()->sql()->addBuddySetting(user->storageId(), id, key, "0", purple_value_get_type(value)); +// } +// else if (purple_value_get_type(value) == PURPLE_TYPE_STRING) { +// const char *str = purple_value_get_string(value); +// Transport::instance()->sql()->addBuddySetting(user->storageId(), id, key, str ? str : "", purple_value_get_type(value)); +// } +// } +// +// static gboolean storeAbstractSpectrumBuddy(gpointer key, gpointer v, gpointer data) { +// AbstractUser *user = (AbstractUser *) data; +// AbstractSpectrumBuddy *s_buddy = (AbstractSpectrumBuddy *) v; +// if (s_buddy->getFlags() & SPECTRUM_BUDDY_IGNORE) +// return TRUE; +// +// // save PurpleBuddy +// std::string alias = s_buddy->getAlias(); +// std::string name = s_buddy->getName(); +// long id = s_buddy->getId(); +// +// // Buddy is not in DB +// if (id != -1) { +// Transport::instance()->sql()->addBuddy(user->storageId(), name, s_buddy->getSubscription(), s_buddy->getGroup(), alias, s_buddy->getFlags()); +// } +// else { +// id = Transport::instance()->sql()->addBuddy(user->storageId(), name, s_buddy->getSubscription(), s_buddy->getGroup(), alias, s_buddy->getFlags()); +// s_buddy->setId(id); +// } +// Log("buddyListSaveNode", id << " " << name << " " << alias << " " << s_buddy->getSubscription()); +// if (s_buddy->getBuddy() && id != -1) { +// PurpleBuddy *buddy = s_buddy->getBuddy(); +// SaveData *s = new SaveData; +// s->user = user; +// s->id = id; +// g_hash_table_foreach(buddy->node.settings, save_settings, s); +// delete s; +// } +// return TRUE; +// } + +RosterStorage::RosterStorage(User *user, StorageBackend *storageBackend) { + m_user = user; + m_storageBackend = storageBackend; + m_storageTimer = m_user->getComponent()->getFactories()->getTimerFactory()->createTimer(5000); +} + +RosterStorage::~RosterStorage() { + m_storageTimer->stop(); +} + +void RosterStorage::storeBuddy(Buddy *buddy) { + m_buddies[buddy->getName()] = buddy; + m_storageTimer->start(); +} + +bool RosterStorage::storeBuddies() { + if (m_buddies.size() == 0) { + return false; + } + + m_storageBackend->beginTransaction(); + + for (std::map::const_iterator it = m_buddies.begin(); it != m_buddies.end(); it++) { + Buddy *buddy = (*it).second; + BuddyInfo buddyInfo; + buddyInfo.alias = buddy->getAlias(); + buddyInfo.legacyName = buddy->getName(); + buddyInfo.groups = buddy->getGroups(); + buddyInfo.subscription = buddy->getSubscription(); + buddyInfo.id = buddy->getID(); + buddyInfo.flags = buddy->getFlags(); + + // Buddy is in DB + if (buddyInfo.id != -1) { + m_storageBackend->updateBuddy(m_user->getUserInfo().id, buddyInfo); + } + else { + buddyInfo.id = m_storageBackend->addBuddy(m_user->getUserInfo().id, buddyInfo); + buddy->setID(buddyInfo.id); + } + +// Log("buddyListSaveNode", id << " " << name << " " << alias << " " << s_buddy->getSubscription()); +// if (s_buddy->getBuddy() && id != -1) { +// PurpleBuddy *buddy = s_buddy->getBuddy(); +// SaveData *s = new SaveData; +// s->user = user; +// s->id = id; +// g_hash_table_foreach(buddy->node.settings, save_settings, s); +// delete s; +// } + } + + m_storageBackend->commitTransaction(); + return true; +} + +void RosterStorage::removeBuddyFromQueue(Buddy *buddy) { + m_buddies.erase(buddy->getName()); +} + +}