From 2ae880ff94b589410f6b8c75b5bbf14407f95119 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Thu, 17 Mar 2011 20:31:00 +0100 Subject: [PATCH] Basic User and UserManager classes --- examples/usermanager/main.cpp | 3 +- include/transport/config.h | 1 + include/transport/logger.h | 8 ++ include/transport/transport.h | 10 ++ include/transport/user.h | 28 ++++- include/transport/usermanager.h | 43 ++++++-- include/transport/userregistration.h | 32 +++++- src/logger.cpp | 12 ++ src/transport.cpp | 8 ++ src/user.cpp | 25 ++++- src/usermanager.cpp | 157 +++++++++++---------------- src/userregistration.cpp | 2 +- 12 files changed, 213 insertions(+), 116 deletions(-) diff --git a/examples/usermanager/main.cpp b/examples/usermanager/main.cpp index 8856a497..a3391a75 100644 --- a/examples/usermanager/main.cpp +++ b/examples/usermanager/main.cpp @@ -26,9 +26,10 @@ int main(void) std::cout << "Can't connect to database.\n"; } - UserManager userManager(&transport); + UserManager userManager(&transport, &sql); UserRegistration userRegistration(&transport, &userManager, &sql); logger.setUserRegistration(&userRegistration); + logger.setUserManager(&userManager); transport.connect(); eventLoop.run(); diff --git a/include/transport/config.h b/include/transport/config.h index b79cb44b..fe4ddfa4 100644 --- a/include/transport/config.h +++ b/include/transport/config.h @@ -36,6 +36,7 @@ namespace Transport { +/// Represents variable:value pairs. typedef boost::program_options::variables_map Variables; /// Represents config file. diff --git a/include/transport/logger.h b/include/transport/logger.h index ac2cd843..0a9f3d96 100644 --- a/include/transport/logger.h +++ b/include/transport/logger.h @@ -52,6 +52,10 @@ class Logger /// \param userRegistration userRegistration class void setUserRegistration(UserRegistration *userRegistration); + /// Starts logging data related to UserManager class. + /// \param userManager userManager class + void setUserManager(UserManager *userManager); + private: // Component void handleConnected(); @@ -66,6 +70,10 @@ class Logger void handleUserRegistered(const UserInfo &user); void handleUserUnregistered(const UserInfo &user); void handleUserUpdated(const UserInfo &user); + + // UserManager + void handleUserCreated(User *user); + void handleUserDestroyed(User *user); }; } diff --git a/include/transport/transport.h b/include/transport/transport.h index c305bce7..5c702753 100644 --- a/include/transport/transport.h +++ b/include/transport/transport.h @@ -65,6 +65,16 @@ namespace Transport { /// Component destructor. ~Component(); + /// Returns Swift::Component associated with this Transport::Component. + /// You can use it to send presences and other stanzas. + /// \return Swift::Component associated with this Transport::Component + Swift::Component *getComponent(); + + /// Returns Swift::PresenceOracle associated with this Transport::Component. + /// You can use it to check current resource connected for particular user. + /// \return Swift::PresenceOracle associated with this Transport::Component + Swift::PresenceOracle *getPresenceOracle(); + /// Connects the Jabber server. /// \see Component() void connect(); diff --git a/include/transport/user.h b/include/transport/user.h index 2c4f6f65..3475e078 100644 --- a/include/transport/user.h +++ b/include/transport/user.h @@ -24,26 +24,48 @@ #include "Swiften/Swiften.h" #include "Swiften/Presence/PresenceOracle.h" #include "Swiften/Disco/EntityCapsManager.h" +#include "storagebackend.h" namespace Transport { class Component; +struct UserInfo; -// Representation of XMPP User +/// Represents online XMPP user. class User { public: - User(const Swift::JID &jid, const std::string &username, const std::string &password, Component * component); + /// Creates new User class. + /// \param jid XMPP JID associated with this user + /// \param userInfo UserInfo struct with informations needed to connect + /// this user to legacy network + /// \param component Component associated with this user + User(const Swift::JID &jid, UserInfo &userInfo, Component * component); + + /// Destroyes User. virtual ~User(); + /// Returns JID of XMPP user who is currently connected using this User class. + /// \return full JID const Swift::JID &getJID(); + /// Returns UserInfo struct with informations needed to connect the legacy network. + /// \return UserInfo struct + UserInfo &getUserInfo() { return m_userInfo; } + + /// Handles presence from XMPP JID associated with this user. + /// \param presence Swift::Presence. + void handlePresence(Swift::Presence::ref presence); + + /// Returns language. + /// \return language const char *getLang() { return "en"; } private: Swift::JID m_jid; - Swift::Component *m_component; + Component *m_component; Swift::EntityCapsManager *m_entityCapsManager; Swift::PresenceOracle *m_presenceOracle; + UserInfo m_userInfo; }; } diff --git a/include/transport/usermanager.h b/include/transport/usermanager.h index 7c072e76..79108133 100644 --- a/include/transport/usermanager.h +++ b/include/transport/usermanager.h @@ -28,28 +28,53 @@ namespace Transport { class User; class Component; +class StorageBackend; -// Class for managing online XMPP users. -class UserManager -{ +/// Manages online XMPP Users. + +/// This class handles presences and creates User classes when new user connects. +/// It also removes the User class once the last user's resource disconnected. +class UserManager { public: - UserManager(Component *component); + /// Creates new UserManager. + /// \param component Component which's presence will be handled + /// \param storageBackend Storage backend used to fetch UserInfos + UserManager(Component *component, StorageBackend *storageBackend); + + /// Destroys UserManager. ~UserManager(); - // User * - User *getUserByJID(const std::string &barejid); + /// Returns user according to his bare JID. + /// \param barejid bare JID of user + /// \return User class associated with this user + User *getUser(const std::string &barejid); - // Returns count of online users; - int userCount(); + /// Returns number of online users. + /// \return number of online users + int getUserCount(); - void removeUser(User *user) {} + /// Removes user. This function disconnects user and safely removes + /// User class. This does *not* remove user from database. + /// \param user User class to remove + void removeUser(User *user); + + /// Called when new User class is created. + /// \param user newly created User class + boost::signal onUserCreated; + + /// Called when User class is going to be removed + /// \param user removed User class + boost::signal onUserDestroyed; private: void handlePresence(Swift::Presence::ref presence); + void addUser(User *user); long m_onlineBuddies; User *m_cachedUser; std::map m_users; + Component *m_component; + StorageBackend *m_storageBackend; }; } diff --git a/include/transport/userregistration.h b/include/transport/userregistration.h index ca5069e3..6a5d2327 100644 --- a/include/transport/userregistration.h +++ b/include/transport/userregistration.h @@ -33,20 +33,40 @@ class StorageBackend; class UserManager; class Config; +/// Allows users to register the transport using service discovery. class UserRegistration : Swift::GetResponder, Swift::SetResponder { public: + /// Creates new UserRegistration handler. + /// \param component Component associated with this class + /// \param userManager UserManager associated with this class + /// \param storageBackend StorageBackend where the registered users will be stored UserRegistration(Component *component, UserManager *userManager, StorageBackend *storageBackend); + + /// Destroys UserRegistration. ~UserRegistration(); - // Registers new user, returns false if user was already registered. - bool registerUser(const UserInfo &user); + /// Registers new user. This function stores user into database and subscribe user to transport. + /// \param userInfo UserInfo struct with informations about registered user + /// \return false if user is already registered + bool registerUser(const UserInfo &userInfo); - // Unregisters user, returns true if user was successfully unregistered. + /// Unregisters user. This function removes all data about user from databa, unsubscribe all buddies + /// managed by this transport and disconnects user if he's connected. + /// \param barejid bare JID of user to unregister + /// \return false if there is no such user registered bool unregisterUser(const std::string &barejid); - boost::signal onUserRegistered; - boost::signal onUserUnregistered; - boost::signal onUserUpdated; + /// Called when new user has been registered. + /// \param userInfo UserInfo struct with informations about user + boost::signal onUserRegistered; + + /// Called when user has been unregistered. + /// \param userInfo UserInfo struct with informations about user + boost::signal onUserUnregistered; + + /// Called when user's registration has been updated. + /// \param userInfo UserInfo struct with informations about user + boost::signal onUserUpdated; private: bool handleGetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr payload); diff --git a/src/logger.cpp b/src/logger.cpp index dedb9278..440b18b4 100644 --- a/src/logger.cpp +++ b/src/logger.cpp @@ -50,6 +50,10 @@ void Logger::setUserRegistration(UserRegistration *userRegistration) { userRegistration->onUserUpdated.connect(bind(&Logger::handleUserUpdated, this, _1)); } +void Logger::setUserManager(UserManager *userManager) { + userManager->onUserCreated.connect(bind(&Logger::handleUserCreated, this, _1)); + userManager->onUserDestroyed.connect(bind(&Logger::handleUserDestroyed, this, _1)); +} void Logger::handleConnected() { std::cout << "[COMPONENT] Connected to Jabber Server!\n"; @@ -92,4 +96,12 @@ void Logger::handleUserUpdated(const UserInfo &user) { std::cout << "[REGISTRATION] User \"" << user.jid << "\" updated \"" << user.uin << "\"\n"; } +void Logger::handleUserCreated(User *user) { + std::cout << "[USERMANAGER] User \"" << user->getJID().toString() << "\" (UIN: \"" << user->getUserInfo().uin << "\") connected and User class has been created\n"; +} + +void Logger::handleUserDestroyed(User *user) { + std::cout << "[USERMANAGER] User \"" << user->getJID().toBare().toString() << "\" (UIN: \"" << user->getUserInfo().uin << "\") disconnected and User class is going to be destroyed\n"; +} + } diff --git a/src/transport.cpp b/src/transport.cpp index 25d6f494..2860b65b 100644 --- a/src/transport.cpp +++ b/src/transport.cpp @@ -78,6 +78,14 @@ Component::~Component() { delete m_factories; } +Swift::Component *Component::getComponent() { + return m_component; +} + +Swift::PresenceOracle *Component::getPresenceOracle() { + return m_presenceOracle; +} + void Component::setTransportFeatures(std::list &features) { m_discoInfoResponder->setTransportFeatures(features); } diff --git a/src/user.cpp b/src/user.cpp index c7bd18ce..a4949f8f 100644 --- a/src/user.cpp +++ b/src/user.cpp @@ -20,19 +20,20 @@ #include "transport/user.h" #include "transport/transport.h" +#include "transport/storagebackend.h" #include "Swiften/Swiften.h" namespace Transport { -User::User(const Swift::JID &jid, const std::string &username, const std::string &password, Component *component) { +User::User(const Swift::JID &jid, UserInfo &userInfo, Component *component) { m_jid = jid; - m_component = component->m_component; + m_component = component; m_presenceOracle = component->m_presenceOracle; m_entityCapsManager = component->m_entityCapsManager; -// m_activeResource = m_jid.getResource(); - + m_userInfo = userInfo; } + User::~User(){ } @@ -41,4 +42,20 @@ const Swift::JID &User::getJID() { return m_jid; } +void User::handlePresence(Swift::Presence::ref presence) { + Swift::Presence::ref highest = m_presenceOracle->getHighestPriorityPresence(m_jid.toBare()); + if (highest) { + highest->setTo(presence->getFrom()); + highest->setFrom(m_component->getJID()); + m_component->getComponent()->sendPresence(highest); + } + else { + Swift::Presence::ref response = Swift::Presence::create(); + response->setTo(m_jid.toBare()); + response->setFrom(m_component->getJID()); + response->setType(Swift::Presence::Unavailable); + m_component->getComponent()->sendPresence(response); + } +} + } diff --git a/src/usermanager.cpp b/src/usermanager.cpp index 28c0477b..bc8e641a 100644 --- a/src/usermanager.cpp +++ b/src/usermanager.cpp @@ -21,12 +21,15 @@ #include "transport/usermanager.h" #include "transport/user.h" #include "transport/transport.h" +#include "transport/storagebackend.h" namespace Transport { -UserManager::UserManager(Component *component) { +UserManager::UserManager(Component *component, StorageBackend *storageBackend) { m_cachedUser = NULL; m_onlineBuddies = 0; + m_component = component; + m_storageBackend = storageBackend; component->onUserPresenceReceived.connect(bind(&UserManager::handlePresence, this, _1)); } @@ -34,7 +37,12 @@ UserManager::UserManager(Component *component) { UserManager::~UserManager(){ } -User *UserManager::getUserByJID(const std::string &barejid){ +void UserManager::addUser(User *user) { + m_users[user->getJID().toBare().toString()] = user; + onUserCreated(user); +} + +User *UserManager::getUser(const std::string &barejid){ if (m_cachedUser && barejid == m_cachedUser->getJID().toBare().toString()) { return m_cachedUser; } @@ -47,55 +55,49 @@ User *UserManager::getUserByJID(const std::string &barejid){ return NULL; } -int UserManager::userCount() { +void UserManager::removeUser(User *user) { + m_users.erase(user->getJID().toBare().toString()); + if (m_cachedUser == user) + m_cachedUser = NULL; + onUserDestroyed(user); + delete user; +} + +int UserManager::getUserCount() { return m_users.size(); } void UserManager::handlePresence(Swift::Presence::ref presence) { -// std::string barejid = presence->getTo().toBare().toString().getUTF8String(); -// std::string userkey = presence->getFrom().toBare().toString().getUTF8String(); -// // if (Transport::instance()->protocol()->tempAccountsAllowed()) { -// // std::string server = barejid.substr(barejid.find("%") + 1, barejid.length() - barejid.find("%")); -// // userkey += server; -// // } -// -// User *user = getUserByJID(userkey); -// if (user ) { -// user->handlePresence(presence); -// } -// else { -// // // No user, unavailable presence... nothing to do -// // if (presence->getType() == Swift::Presence::Unavailable) { -// // Swift::Presence::ref response = Swift::Presence::create(); -// // response->setTo(presence->getFrom()); -// // response->setFrom(Swift::JID(Transport::instance()->jid())); -// // response->setType(Swift::Presence::Unavailable); -// // m_component->sendPresence(response); -// // -// // // UserRow res = Transport::instance()->sql()->getUserByJid(userkey); -// // // if (res.id != -1) { -// // // Transport::instance()->sql()->setUserOnline(res.id, false); -// // // } -// // return; -// // } -// // UserRow res = Transport::instance()->sql()->getUserByJid(userkey); -// // if (res.id == -1 && !Transport::instance()->protocol()->tempAccountsAllowed()) { -// // // presence from unregistered user -// // Log(presence->getFrom().toString().getUTF8String(), "This user is not registered"); -// // return; -// // } -// // else { -// // if (res.id == -1 && Transport::instance()->protocol()->tempAccountsAllowed()) { -// // res.jid = userkey; -// // res.uin = presence->getFrom().toBare().toString().getUTF8String(); -// // res.password = ""; -// // res.language = "en"; -// // res.encoding = CONFIG().encoding; -// // res.vip = 0; -// // Transport::instance()->sql()->addUser(res); -// // res = Transport::instance()->sql()->getUserByJid(userkey); -// // } -// // + std::string barejid = presence->getTo().toBare().toString(); + std::string userkey = presence->getFrom().toBare().toString(); + + User *user = getUser(userkey); + if (!user ) { + // No user and unavailable presence -> answer with unavailable + if (presence->getType() == Swift::Presence::Unavailable) { + Swift::Presence::ref response = Swift::Presence::create(); + response->setTo(presence->getFrom()); + response->setFrom(presence->getTo()); + response->setType(Swift::Presence::Unavailable); + m_component->getComponent()->sendPresence(response); + + UserInfo res; + bool registered = m_storageBackend->getUser(userkey, res); + if (registered) { + m_storageBackend->setUserOnline(res.id, false); + } + return; + } + + UserInfo res; + bool registered = m_storageBackend->getUser(userkey, res); + + if (!registered) { + // TODO: logging + return; + } + + // TODO: isVIP // // bool isVip = res.vip; // // std::list const &x = CONFIG().allowedServers; // // if (CONFIG().onlyForVIP && !isVip && std::find(x.begin(), x.end(), presence->getFrom().getDomain().getUTF8String()) == x.end()) { @@ -103,60 +105,31 @@ void UserManager::handlePresence(Swift::Presence::ref presence) { // // return; // // } // // -// // Log(presence->getFrom().toString().getUTF8String(), "Creating new User instance"); // // -// // if (Transport::instance()->protocol()->tempAccountsAllowed()) { -// // std::string server = barejid.substr(barejid.find("%") + 1, barejid.length() - barejid.find("%")); -// // res.uin = presence->getTo().getResource().getUTF8String() + "@" + server; -// // } -// // else { -// // if (purple_accounts_find(res.uin.c_str(), Transport::instance()->protocol()->protocol().c_str()) != NULL) { -// // PurpleAccount *act = purple_accounts_find(res.uin.c_str(), Transport::instance()->protocol()->protocol().c_str()); -// // user = Transport::instance()->userManager()->getUserByAccount(act); -// // if (user) { -// // Log(presence->getFrom().toString().getUTF8String(), "This account is already connected by another jid " << user->jid()); -// // return; -// // } -// // } -// // } -// // user = (AbstractUser *) new User(res, userkey, m_component, m_presenceOracle, m_entityCapsManager); + user = new User(presence->getFrom(), res, m_component); + // TODO: handle features somehow // // user->setFeatures(isVip ? CONFIG().VIPFeatures : CONFIG().transportFeatures); // // // if (c != NULL) // // // if (Transport::instance()->hasClientCapabilities(c->findAttribute("ver"))) // // // user->setResource(stanza.from().resource(), stanza.priority(), Transport::instance()->getCapabilities(c->findAttribute("ver"))); // // // -// // Transport::instance()->userManager()->addUser(user); -// // user->receivedPresence(presence); -// // // if (protocol()->tempAccountsAllowed()) { -// // // std::string server = stanza.to().username().substr(stanza.to().username().find("%") + 1, stanza.to().username().length() - stanza.to().username().find("%")); -// // // server = stanza.from().bare() + server; -// // // purple_timeout_add_seconds(15, &connectUser, g_strdup(server.c_str())); -// // // } -// // // else -// // // purple_timeout_add_seconds(15, &connectUser, g_strdup(stanza.from().bare().c_str())); -// // // } -// // } -// // // if (stanza.presence() == Presence::Unavailable && stanza.to().username() == ""){ -// // // Log(stanza.from().full(), "User is already logged out => sending unavailable presence"); -// // // Tag *tag = new Tag("presence"); -// // // tag->addAttribute( "to", stanza.from().bare() ); -// // // tag->addAttribute( "type", "unavailable" ); -// // // tag->addAttribute( "from", jid() ); -// // // j->send( tag ); -// // // } -// } -// -// if (presence->getType() == Swift::Presence::Unavailable) { -// if (user) { -// Swift::Presence::ref highest = m_presenceOracle->getHighestPriorityPresence(presence->getFrom().toBare()); -// if (presence->getType() == Swift::Presence::Unavailable && (!highest || (highest && highest->getType() == Swift::Presence::Unavailable))) { -// Transport::instance()->userManager()->removeUser(user); -// } -// } + addUser(user); + } + user->handlePresence(presence); + + if (presence->getType() == Swift::Presence::Unavailable) { + if (user) { + Swift::Presence::ref highest = m_component->getPresenceOracle()->getHighestPriorityPresence(presence->getFrom().toBare()); + // There's no presence for this user, so disconnect + if (!highest || (highest && highest->getType() == Swift::Presence::Unavailable)) { + removeUser(user); + } + } + // TODO: HANDLE MUC SOMEHOW // else if (user && Transport::instance()->protocol()->tempAccountsAllowed() && !((User *) user)->hasOpenedMUC()) { // Transport::instance()->userManager()->removeUser(user); // } -// } + } } } diff --git a/src/userregistration.cpp b/src/userregistration.cpp index 0254df90..92e527c7 100644 --- a/src/userregistration.cpp +++ b/src/userregistration.cpp @@ -74,7 +74,7 @@ bool UserRegistration::unregisterUser(const std::string &barejid) { Swift::Presence::ref response; - User *user = m_userManager->getUserByJID(barejid); + User *user = m_userManager->getUser(barejid); // roster contains already escaped jids std::list roster;