Changeset - 88865c1234e3
[Not reviewed]
0 7 0
HanzZ - 15 years ago 2011-03-20 23:04:20
hanzz.k@gmail.com
RosterManager
7 files changed with 46 insertions and 5 deletions:
0 comments (0 inline, 0 general)
include/transport/abstractbuddy.h
Show inline comments
 
@@ -10,89 +10,97 @@
 
 *
 
 * 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 <string>
 
#include <algorithm>
 
#include "transport/transport.h"
 

	
 
#include "Swiften/Swiften.h"
 

	
 
typedef enum { 	SPECTRUM_BUDDY_NO_FLAG = 0,
 
				SPECTRUM_BUDDY_JID_ESCAPING = 2,
 
				SPECTRUM_BUDDY_IGNORE = 4
 
			} SpectrumBuddyFlag;
 

	
 
using namespace Transport;
 
namespace Transport {
 

	
 
class RosterManager;
 

	
 
// Wrapper for PurpleBuddy.
 
class AbstractBuddy {
 
	public:
 
		AbstractBuddy(long id);
 
		virtual ~AbstractBuddy();
 
		
 
		// Sets/gets ID used to identify this buddy for example by storage backend.
 
		void setId(long id);
 
		long getId();
 

	
 
		// Returns full JID.
 
		Swift::JID getJID(const std::string &hostname);
 

	
 
		// Generates whole <presence> stanza without "to" attribute. That attribute
 
		// has to be added manually.
 
		// only_new - if the stanza is the same as previous generated one, returns NULL.
 
		Swift::Presence::ref generatePresenceStanza(int features, bool only_new = false);
 

	
 
		// Sets online/offline state information.
 
		void setOnline();
 
		void setOffline();
 

	
 
		// Returns true if online.
 
		bool isOnline();
 

	
 
		// Sets/gets current subscription.
 
		// TODO: rewrite me to use SpectrumSubscriptionType!
 
		void setSubscription(const std::string &subscription);
 
		const std::string &getSubscription();
 

	
 
		// Sets SpectrumBuddyFlags.
 
		void setFlags(int flags);
 

	
 
		// Returns flags.
 
		int getFlags();
 

	
 
		void setRosterManager(RosterManager *rosterManager) { m_rosterManager = rosterManager; }
 
		RosterManager *getRosterManager() { return m_rosterManager; }
 

	
 
		// Returns buddy's name (so for example UIN for ICQ, JID for XMPP...).
 
		virtual std::string getName() = 0;
 

	
 
		// Returns buddy's alias (nickname).
 
		virtual std::string getAlias() = 0;
 

	
 
		// Returns buddy's group name.
 
		virtual std::vector<std::string> getGroups() = 0;
 

	
 
		// Returns name which doesn't contain unsafe characters, so it can be used.
 
		// in JIDs.
 
		virtual std::string getSafeName() = 0;
 

	
 
		// Stores current status in `status` and current status message in `statusMessage`.
 
		// Returns true if data can be stored.
 
		virtual bool getStatus(Swift::StatusShow &status, std::string &statusMessage) = 0;
 

	
 
		// Returns SHA-1 hash of buddy icon (avatar) or empty string if there is no avatar.
 
		virtual std::string getIconHash() = 0;
 

	
 
	private:
 
		long m_id;
 
		bool m_online;
 
		std::string m_subscription;
 
		Swift::Presence::ref m_lastPresence;
 
		int m_flags;
 
		RosterManager *m_rosterManager;
 
};
 

	
 
}
include/transport/logger.h
Show inline comments
 
@@ -11,69 +11,79 @@
 
 * 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 <string>
 
#include <map>
 
#include "Swiften/Swiften.h"
 

	
 
namespace Transport {
 

	
 
struct UserInfo;
 
class User;
 
class UserManager;
 
class Component;
 
class StorageBackend;
 
class UserRegistration;
 
class RosterManager;
 
class AbstractBuddy;
 

	
 
/// Basic logging class which logs various data into std::out (standard output).
 
class Logger
 
{
 
	public:
 
		/// Creates new Logger class instance.
 
		/// \param component component instance
 
		Logger(Component *component);
 

	
 
		/// Logger destructor.
 
		~Logger();
 

	
 
		/// Starts logging data related to StorageBackend class.
 
		/// \param storage storage class
 
		void setStorageBackend(StorageBackend *storage);
 

	
 
		/// Starts logging data related to UserRegistration class.
 
		/// \param userRegistration userRegistration class
 
		void setUserRegistration(UserRegistration *userRegistration);
 

	
 
		/// Starts logging data related to UserManager class.
 
		/// \param userManager userManager class
 
		void setUserManager(UserManager *userManager);
 

	
 
		/// Starts logging data related to RosterManager class.
 
		/// \param rosterManager rosterManager class
 
		void setRosterManager(RosterManager *rosterManager);
 

	
 
	private:
 
		// Component
 
		void handleConnected();
 
		void handleConnectionError(const Swift::ComponentError &error);
 
		void handleXMLIn(const std::string &data);
 
		void handleXMLOut(const std::string &data);
 

	
 
		// StorageBackend
 
		void handleStorageError(const std::string &statement, const std::string &error);
 

	
 
		// UserRegistration
 
		void handleUserRegistered(const UserInfo &user);
 
		void handleUserUnregistered(const UserInfo &user);
 
		void handleUserUpdated(const UserInfo &user);
 

	
 
		// UserManager
 
		void handleUserCreated(User *user);
 
		void handleUserDestroyed(User *user);
 

	
 
		// RosterManager
 
		void handleBuddyAdded(AbstractBuddy *buddy);
 
		void handleBuddyRemoved(AbstractBuddy *buddy);
 
};
 

	
 
}
include/transport/user.h
Show inline comments
 
@@ -8,75 +8,79 @@
 
 * 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 <time.h>
 
#include "Swiften/Swiften.h"
 
#include "Swiften/Presence/PresenceOracle.h"
 
#include "Swiften/Disco/EntityCapsManager.h"
 
#include "storagebackend.h"
 

	
 
namespace Transport {
 

	
 
class Component;
 
class RosterManager;
 
struct UserInfo;
 

	
 
/// Represents online XMPP user.
 
class User {
 
	public:
 
		/// 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; }
 

	
 
		RosterManager *getRosterManager() { return m_rosterManager; }
 

	
 
		void setData(void *data) { m_data = data; }
 
		void *getData() { return m_data; }
 

	
 
		/// 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"; }
 

	
 
		boost::signal<void ()> onReadyToConnect;
 

	
 
	private:
 
		void onConnectingTimeout();
 

	
 
		Swift::JID m_jid;
 
		Component *m_component;		
 
		Component *m_component;
 
		RosterManager *m_rosterManager;
 
		Swift::EntityCapsManager *m_entityCapsManager;
 
		Swift::PresenceOracle *m_presenceOracle;
 
		UserInfo m_userInfo;
 
		void *m_data;
 
		bool m_connected;
 
		bool m_readyForConnect;
 
		Swift::Timer::ref m_reconnectTimer;
 
};
 

	
 
}
spectrum/src/main.cpp
Show inline comments
 
#include "glib.h"
 
#include "purple.h"
 
#include <iostream>
 

	
 
#include "transport/config.h"
 
#include "transport/transport.h"
 
#include "transport/usermanager.h"
 
#include "transport/logger.h"
 
#include "transport/sqlite3backend.h"
 
#include "transport/userregistration.h"
 
#include "transport/user.h"
 
#include "transport/storagebackend.h"
 
#include "transport/rostermanager.h"
 
#include "spectrumeventloop.h"
 
#include "spectrumbuddy.h"
 
#include "geventloop.h"
 

	
 
#define Log(X, STRING) std::cout << "[SPECTRUM] " << X << " " << STRING << "\n";
 

	
 

	
 
using namespace Transport;
 

	
 
static gboolean nodaemon = FALSE;
 
static gchar *logfile = NULL;
 
static gchar *lock_file = NULL;
 
static gboolean ver = FALSE;
 
static gboolean upgrade_db = FALSE;
 
static gboolean check_db_version = FALSE;
 
static gboolean list_purple_settings = FALSE;
 

	
 
static GOptionEntry options_entries[] = {
 
	{ "nodaemon", 'n', 0, G_OPTION_ARG_NONE, &nodaemon, "Disable background daemon mode", NULL },
 
	{ "logfile", 'l', 0, G_OPTION_ARG_STRING, &logfile, "Set file to log", NULL },
 
	{ "pidfile", 'p', 0, G_OPTION_ARG_STRING, &lock_file, "File where to write transport PID", NULL },
 
	{ "version", 'v', 0, G_OPTION_ARG_NONE, &ver, "Shows Spectrum version", NULL },
 
	{ "list-purple-settings", 's', 0, G_OPTION_ARG_NONE, &list_purple_settings, "Lists purple settings which can be used in config file", NULL },
 
	{ "upgrade-db", 'u', 0, G_OPTION_ARG_NONE, &upgrade_db, "Upgrades Spectrum database", NULL },
 
@@ -44,65 +45,66 @@ static void buddyListNewNode(PurpleBlistNode *node) {
 
	PurpleBuddy *buddy = (PurpleBuddy *) node;
 
	PurpleAccount *account = purple_buddy_get_account(buddy);
 
	User *user = (User *) account->ui_data;
 

	
 
	if (!user)
 
		return;
 

	
 
	SpectrumBuddy *s_buddy = NULL;
 
	GSList *list = purple_find_buddies(account, purple_buddy_get_name(buddy));
 
	while (list) {
 
		PurpleBuddy *b = (PurpleBuddy *) list->data;
 
		if (b->node.ui_data)
 
			s_buddy = (SpectrumBuddy *) b->node.ui_data;
 
		list = g_slist_delete_link(list, list);
 
	}
 

	
 
	if (s_buddy) {
 
		buddy->node.ui_data = s_buddy;
 
		s_buddy->addBuddy(buddy);
 
	}
 
	else {
 
		buddy->node.ui_data = (void *) new SpectrumBuddy(-1, buddy);
 
		SpectrumBuddy *s_buddy = (SpectrumBuddy *) buddy->node.ui_data;
 
		s_buddy->setFlags(SPECTRUM_BUDDY_JID_ESCAPING);
 
		// TODO: add buddy to RosterManager
 

	
 
		user->getRosterManager()->addBuddy(s_buddy);
 
	}
 
}
 

	
 
static void NodeRemoved(PurpleBlistNode *node, void *data) {
 
	if (!PURPLE_BLIST_NODE_IS_BUDDY(node))
 
		return;
 
	PurpleBuddy *buddy = (PurpleBuddy *) node;
 
	
 
	PurpleAccount *account = purple_buddy_get_account(buddy);
 
	User *user = (User *) account->ui_data;
 
	if (buddy->node.ui_data) {
 
		SpectrumBuddy *s_buddy = (SpectrumBuddy *) buddy->node.ui_data;
 
		s_buddy->removeBuddy(buddy);
 
		buddy->node.ui_data = NULL;
 
		if (s_buddy->getBuddiesCount() == 0) {
 
			// TODO: remove buddy from RosterManager
 
			user->getRosterManager()->removeBuddy(s_buddy);
 
			delete s_buddy;
 
		}
 
	}
 
}
 

	
 
static PurpleBlistUiOps blistUiOps =
 
{
 
	NULL,
 
	buddyListNewNode,
 
	NULL,
 
	NULL, // buddyListUpdate,
 
	NULL, //NodeRemoved,
 
	NULL,
 
	NULL,
 
	NULL, // buddyListAddBuddy,
 
	NULL,
 
	NULL,
 
	NULL, //buddyListSaveNode,
 
	NULL, //buddyListRemoveNode,
 
	NULL, //buddyListSaveAccount,
 
	NULL
 
};
 

	
 
static void transport_core_ui_init(void)
src/abstractbuddy.cpp
Show inline comments
 
/**
 
 * XMPP - libpurple transport
 
 *
 
 * Copyright (C) 2009, Jan Kaluza <hanzz@soc.pidgin.im>
 
 *
 
 * 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/abstractbuddy.h"
 

	
 
namespace Transport {
 

	
 
AbstractBuddy::AbstractBuddy(long id) : m_id(id), m_online(false), m_subscription("ask"), m_flags(0) {
 
}
 

	
 
AbstractBuddy::~AbstractBuddy() {
 
}
 

	
 
void AbstractBuddy::setId(long id) {
 
	m_id = id;
 
}
 

	
 
long AbstractBuddy::getId() {
 
	return m_id;
 
}
 

	
 
void AbstractBuddy::setFlags(int flags) {
 
	m_flags = flags;
 
}
 

	
 
int AbstractBuddy::getFlags() {
 
	return m_flags;
 
}
 

	
 
Swift::JID AbstractBuddy::getJID(const std::string &hostname) {
 
 	return Swift::JID(getSafeName(), hostname, "bot");
 
@@ -86,24 +88,26 @@ Swift::Presence::ref AbstractBuddy::generatePresenceStanza(int features, bool on
 
	if (s.getType() == Swift::StatusShow::None)
 
		presence->setType(Swift::Presence::Unavailable);
 
	presence->setShow(s.getType());
 

	
 
	if (presence->getType() != Swift::Presence::Unavailable) {
 
		// caps
 
// 		presence->addPayload(boost::shared_ptr<Swift::Payload>(new Swift::CapsInfo (CONFIG().caps)));
 

	
 
		if (features & 0/*TRANSPORT_FEATURE_AVATARS*/) {
 
			presence->addPayload(boost::shared_ptr<Swift::Payload>(new Swift::VCardUpdate (getIconHash())));
 
		}
 
	}
 

	
 
	if (only_new) {
 
		if (m_lastPresence)
 
			m_lastPresence->setTo(Swift::JID(""));
 
		if (m_lastPresence == presence) {
 
			return Swift::Presence::ref();
 
		}
 
		m_lastPresence = presence;
 
	}
 

	
 
	return presence;
 
}
 

	
 
}
src/logger.cpp
Show inline comments
 
@@ -3,48 +3,50 @@
 
 *
 
 * Copyright (C) 2011, Jan Kaluza <hanzz.k@gmail.com>
 
 *
 
 * 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/logger.h"
 
#include "transport/usermanager.h"
 
#include "transport/user.h"
 
#include "transport/transport.h"
 
#include "transport/storagebackend.h"
 
#include "transport/userregistration.h"
 
#include "transport/abstractbuddy.h"
 
#include "transport/rostermanager.h"
 
#include <boost/bind.hpp>
 

	
 
using namespace boost;
 

	
 
namespace Transport {
 

	
 
Logger::Logger(Component *component) {
 
	component->onConnected.connect(bind(&Logger::handleConnected, this));
 
	component->onConnectionError.connect(bind(&Logger::handleConnectionError, this, _1));
 
	component->onXMLIn.connect(bind(&Logger::handleXMLIn, this, _1));
 
	component->onXMLOut.connect(bind(&Logger::handleXMLOut, this, _1));
 
}
 

	
 
Logger::~Logger(){
 
}
 

	
 
void Logger::setStorageBackend(StorageBackend *storage) {
 
	storage->onStorageError.connect(bind(&Logger::handleStorageError, this, _1, _2));
 
}
 

	
 
void Logger::setUserRegistration(UserRegistration *userRegistration) {
 
	userRegistration->onUserRegistered.connect(bind(&Logger::handleUserRegistered, this, _1));
 
	userRegistration->onUserUnregistered.connect(bind(&Logger::handleUserUnregistered, this, _1));
 
	userRegistration->onUserUpdated.connect(bind(&Logger::handleUserUpdated, this, _1));
 
@@ -83,25 +85,33 @@ void Logger::handleXMLOut(const std::string &data) {
 
void Logger::handleStorageError(const std::string &statement, const std::string &error) {
 
	std::cout << "[SQL ERROR] \"" << error << "\" during statement \"" << statement << "\"\n";
 
}
 

	
 
void Logger::handleUserRegistered(const UserInfo &user) {
 
	std::cout << "[REGISTRATION] User \"" << user.jid << "\" registered as \"" << user.uin << "\"\n";
 
}
 

	
 
void Logger::handleUserUnregistered(const UserInfo &user) {
 
	std::cout << "[REGISTRATION] User \"" << user.jid << "\" unregistered \"" << user.uin << "\"\n";
 
}
 

	
 
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";
 
}
 

	
 
void Logger::handleBuddyAdded(AbstractBuddy *buddy) {
 
	std::cout << "[ROSTERMANAGER] \"" << buddy->getRosterManager()->getUser()->getJID().toBare().toString() << "\": Buddy \"" << buddy->getSafeName() << "\" (ALIAS: \"" << buddy->getAlias() << "\") has been bound with this user's roster.\n";
 
}
 

	
 
void Logger::handleBuddyRemoved(AbstractBuddy *buddy) {
 
	std::cout << "[ROSTERMANAGER] \"" << buddy->getRosterManager()->getUser()->getJID().toBare().toString() << "\": Buddy \"" << buddy->getSafeName() << "\" (ALIAS: \"" << buddy->getAlias() << "\") has been unbound with this user's roster.\n";
 
}
 

	
 
}
src/user.cpp
Show inline comments
 
/**
 
 * libtransport -- C++ library for easy XMPP Transports development
 
 *
 
 * Copyright (C) 2011, Jan Kaluza <hanzz.k@gmail.com>
 
 *
 
 * 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/user.h"
 
#include "transport/transport.h"
 
#include "transport/storagebackend.h"
 
#include "transport/rostermanager.h"
 
#include "Swiften/Swiften.h"
 

	
 
namespace Transport {
 

	
 
User::User(const Swift::JID &jid, UserInfo &userInfo, Component *component) {
 
	m_jid = jid;
 

	
 
	m_component = component;
 
	m_presenceOracle = component->m_presenceOracle;
 
	m_entityCapsManager = component->m_entityCapsManager;
 
	m_userInfo = userInfo;
 
	m_connected = false;
 
	m_readyForConnect = false;
 

	
 
	m_reconnectTimer = m_component->getFactories()->getTimerFactory()->createTimer(10000);
 
	m_reconnectTimer->onTick.connect(boost::bind(&User::onConnectingTimeout, this)); 
 

	
 
	m_rosterManager = new RosterManager(this, m_component);
 
}
 

	
 
User::~User(){
 

	
 
	delete m_rosterManager;
 
}
 

	
 
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 (!m_connected) {
 
		// we are not connected to legacy network, so we should do it when disco#info arrive :)
 
		if (m_readyForConnect == false) {
 
			
 
			// Forward status message to legacy network, but only if it's sent from active resource
 
// 					if (m_activeResource == presence->getFrom().getResource().getUTF8String()) {
 
// 						forwardStatus(presenceShow, stanzaStatus);
 
// 					}
 
			boost::shared_ptr<Swift::CapsInfo> capsInfo = presence->getPayload<Swift::CapsInfo>();
 
			if (capsInfo && capsInfo->getHash() == "sha-1") {
 
				if (m_entityCapsManager->getCaps(presence->getFrom()) != Swift::DiscoInfo::ref()) {
 
					m_readyForConnect = true;
 
					onReadyToConnect();
 
				}
 
			}
0 comments (0 inline, 0 general)