Changeset - c8006a0ebab6
[Not reviewed]
0 11 1
HanzZ - 15 years ago 2011-04-02 21:51:51
hanzz.k@gmail.com
Working message forwarding in both sides :)
12 files changed with 102 insertions and 6 deletions:
0 comments (0 inline, 0 general)
examples/usermanager/main.cpp
Show inline comments
 
#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 "Swiften/EventLoop/SimpleEventLoop.h"
 
 
using namespace Transport;
 
 
int main(void)
 
{
 
	Config config;
 
	if (!config.load("sample.cfg")) {
 
		std::cout << "Can't open sample.cfg configuration file.\n";
 
		return 1;
 
	}
 
 
	Swift::SimpleEventLoop eventLoop;
 
	Component transport(&eventLoop, &config);
 
	Component transport(&eventLoop, &config, NULL);
 
	Logger logger(&transport);
 
 
	SQLite3Backend sql(&config);
 
	logger.setStorageBackend(&sql);
 
	if (!sql.connect()) {
 
		std::cout << "Can't connect to database.\n";
 
	}
 
 
	UserManager userManager(&transport, &sql);
 
	UserRegistration userRegistration(&transport, &userManager, &sql);
 
	logger.setUserRegistration(&userRegistration);
 
	logger.setUserManager(&userManager);
 
 
	transport.connect();
 
	eventLoop.run();
 
}
include/transport/conversationmanager.h
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
 
 */
 

	
 
#pragma once
 

	
 
#include <string>
 
#include <algorithm>
 
#include <map>
 
#include "Swiften/Swiften.h"
 

	
 
namespace Transport {
 

	
 
class AbstractConversation;
 
class User;
 
class Component;
 

	
 
class ConversationManager {
 
	public:
 
		/// Creates new ConversationManager.
 
		/// \param user User associated with this ConversationManager.
 
		/// \param component Transport instance associated with this roster.
 
		ConversationManager(User *user, Component *component);
 

	
 
		/// Destructor.
 
		virtual ~ConversationManager();
 

	
 
		/// Returns user associated with this manager.
 
		/// \return User
 
		User *getUser() { return m_user; }
 

	
 
		Component *getComponent() { return m_component; }
 

	
 
		void setConversation(AbstractConversation *conv);
 

	
 
		void unsetConversation(AbstractConversation *conv);
 

	
 
	private:
 
		void handleMessageReceived(Swift::Message::ref message);
 

	
 
		Component *m_component;
 
		User *m_user;
 

	
 
		std::map<std::string, AbstractConversation *> m_convs;
 
		friend class UserManager;
 
};
 

	
 
}
include/transport/factory.h
Show inline comments
 
new file 100644
 
/**
 
 * 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
 
 */
 

	
 
#pragma once
 

	
 
#include <string>
 
#include <algorithm>
 
#include "transport/transport.h"
 

	
 
#include "Swiften/Swiften.h"
 
#include "Swiften/Elements/Message.h"
 
#include "transport/abstractconversation.h"
 

	
 
namespace Transport {
 

	
 
class AbstractConversation;
 
class ConversationManager;
 

	
 
class Factory {
 
	public:
 
		
 
		virtual AbstractConversation *createConversation(ConversationManager *conversationManager, const std::string &legacyName) = 0;
 
};
 

	
 
}
include/transport/transport.h
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
 
 */
 

	
 
#pragma once
 

	
 
#include <vector>
 
#include "Swiften/Swiften.h"
 
#include "Swiften/Server/Server.h"
 
#include "Swiften/Disco/GetDiscoInfoRequest.h"
 
#include "Swiften/Disco/EntityCapsManager.h"
 
#include "Swiften/Disco/CapsManager.h"
 
#include "Swiften/Disco/CapsMemoryStorage.h"
 
#include "Swiften/Presence/PresenceOracle.h"
 
#include "Swiften/Network/BoostTimerFactory.h"
 
#include "Swiften/Network/BoostIOServiceThread.h"
 
#include "Swiften/Server/UserRegistry.h"
 
#include <boost/bind.hpp>
 
#include "transport/config.h"
 
#include "transport/factory.h"
 

	
 
#define tr(lang,STRING)    (STRING)
 
#define _(STRING)    (STRING)
 

	
 
namespace Transport {
 
	// typedef enum { 	CLIENT_FEATURE_ROSTERX = 2,
 
	// 				CLIENT_FEATURE_XHTML_IM = 4,
 
	// 				CLIENT_FEATURE_FILETRANSFER = 8,
 
	// 				CLIENT_FEATURE_CHATSTATES = 16
 
	// 				} SpectrumImportantFeatures;
 
	// 
 
	class StorageBackend;
 
	class DiscoInfoResponder;
 
	class DiscoItemsResponder;
 
	class RosterResponder;
 
	class Factory;
 

	
 
	/// Represents one transport instance.
 

	
 
	/// It's used to connect
 
	/// the Jabber server and provides transaction layer between Jabber server
 
	/// and other classes.
 
	class Component {
 
		public:
 
			/// Creates new Component instance.
 
			/// \param loop main event loop 
 
			/// \param config cofiguration, this class uses following Config values:
 
			/// 	- service.jid
 
			/// 	- service.password
 
			/// 	- service.server
 
			/// 	- service.port
 
			Component(Swift::EventLoop *loop, Config *config);
 
			Component(Swift::EventLoop *loop, Config *config, Factory *factory);
 

	
 
			/// 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::StanzaChannel *getStanzaChannel();
 

	
 
			Swift::IQRouter *getIQRouter() { return m_iqRouter; }
 

	
 
			/// 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();
 

	
 
			bool inServerMode() { return m_server != NULL; }
 
			const std::string &getUserRegistryPassword(const std::string &barejid);
 

	
 
			/// Connects the Jabber server.
 
			/// \see Component()
 
			void connect();
 

	
 
			/// Sets disco#info features which are sent as answer to
 
			/// disco#info IQ-get. This sets features of transport contact (For example "j2j.domain.tld").
 
			/// \param features list of features as sent in disco#info response
 
			void setTransportFeatures(std::list<std::string> &features);
 

	
 
			/// Sets disco#info features which are sent as answer to
 
			/// disco#info IQ-get. This sets features of legacy network buddies (For example "me\40gmail.com@j2j.domain.tld").
 
			/// \param features list of features as sent in disco#info response
 
			void setBuddyFeatures(std::list<std::string> &features);
 

	
 
			/// Returns Jabber ID of this transport.
 
			/// \return Jabber ID of this transport
 
			Swift::JID &getJID() { return m_jid; }
 

	
 
			Swift::BoostNetworkFactories *getFactories() { return m_factories; }
 

	
 
			Factory *getFactory() { return m_factory; }
 

	
 
			/// This signal is emitted when server disconnects the transport because of some error.
 
			/// \param error disconnection error
 
			boost::signal<void (const Swift::ComponentError &error)> onConnectionError;
 

	
 
			/// This signal is emitted when transport successfully connects the server.
 
			boost::signal<void ()> onConnected;
 

	
 
			/// This signal is emitted when XML stanza is sent to server.
 
			/// \param xml xml stanza
 
			boost::signal<void (const std::string &xml)> onXMLOut;
 

	
 
			/// This signal is emitted when XML stanza is received from server.
 
			/// \param xml xml stanza
 
			boost::signal<void (const std::string &xml)> onXMLIn;
 

	
 
			/// This signal is emitted when presence from XMPP user (for example "user@domain.tld")
 
			/// is received. It's emitted only for presences addressed to transport itself
 
			/// (for example to="j2j.domain.tld").
 
			/// \param presence presence data
 
			boost::signal<void (Swift::Presence::ref presence)> onUserPresenceReceived;
 

	
 
// 			boost::signal<void (boost::shared_ptr<Swift::DiscoInfo> info, Swift::ErrorPayload::ref error, const Swift::JID& jid)> onDiscoInfoResponse;
 

	
 
		private:
 
			void handleConnected();
 
			void handleConnectionError(const Swift::ComponentError &error);
 
			void handlePresenceReceived(Swift::Presence::ref presence);
 
// 			void handleMessageReceived(Swift::Message::ref message);
 
			void handlePresence(Swift::Presence::ref presence);
 
			void handleSubscription(Swift::Presence::ref presence);
 
			void handleProbePresence(Swift::Presence::ref presence);
 
			void handleDataRead(const std::string &data);
 
			void handleDataWritten(const std::string &data);
 

	
 
// 			void handleDiscoInfoResponse(boost::shared_ptr<Swift::DiscoInfo> info, Swift::ErrorPayload::ref error, const Swift::JID& jid);
 
			void handleCapsChanged(const Swift::JID& jid);
 

	
 
			Swift::BoostNetworkFactories *m_factories;
 
			Swift::Component *m_component;
 
			Swift::Server *m_server;
 
			Swift::Timer::ref m_reconnectTimer;
 
			Swift::BoostIOServiceThread m_boostIOServiceThread;
 
			Swift::EntityCapsManager *m_entityCapsManager;
 
			Swift::CapsManager *m_capsManager;
 
			Swift::CapsMemoryStorage *m_capsMemoryStorage;
 
			Swift::PresenceOracle *m_presenceOracle;
 
			Swift::StanzaChannel *m_stanzaChannel;
 
			Swift::IQRouter *m_iqRouter;
 
			Swift::UserRegistry *m_userRegistry;
 
			StorageBackend *m_storageBackend;
 
 			DiscoInfoResponder *m_discoInfoResponder;
 
			DiscoItemsResponder *m_discoItemsResponder;
 
			RosterResponder *m_rosterResponder;
 
			int m_reconnectCount;
 
			Config* m_config;
 
			std::string m_protocol;
 
			Swift::JID m_jid;
 
			Factory *m_factory;
 

	
 
		friend class User;
 
		friend class UserRegistration;
 
	};
 
}
include/transport/usermanager.h
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
 
 */
 

	
 
#pragma once
 

	
 
#include <string>
 
#include <map>
 
#include "Swiften/Swiften.h"
 

	
 
namespace Transport {
 

	
 
class User;
 
class Component;
 
class StorageBackend;
 

	
 
/// 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:
 
		/// 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();
 

	
 
		/// 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 number of online users.
 
		/// \return number of online users
 
		int getUserCount();
 

	
 
		/// 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<void (User *user)> onUserCreated;
 

	
 
		/// Called when User class is going to be removed
 
		/// \param user removed User class
 
		boost::signal<void (User *user)> onUserDestroyed;
 

	
 
	private:
 
		void handlePresence(Swift::Presence::ref presence);
 
		void handleMessageReceived(Swift::Message::ref message);
 
// 		void handleDiscoInfoResponse(boost::shared_ptr<Swift::DiscoInfo> info, Swift::ErrorPayload::ref error, const Swift::JID& jid);
 
		void addUser(User *user);
 

	
 
		long m_onlineBuddies;
 
		User *m_cachedUser;
 
		std::map<std::string, User *> m_users;
 
		Component *m_component;
 
		StorageBackend *m_storageBackend;
 
};
 

	
 
}
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 "transport/abstractconversation.h"
 
#include "spectrumeventloop.h"
 
#include "spectrumbuddy.h"
 
#include "spectrumconversation.h"
 
#include "geventloop.h"
 

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

	
 

	
 
using namespace Transport;
 

	
 
Logger *_logger;
 

	
 
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 },
 
	{ "check-db-GlooxMessageHandler::version", 'c', 0, G_OPTION_ARG_NONE, &check_db_version, "Checks Spectrum database version", NULL },
 
	{ NULL, 0, 0, G_OPTION_ARG_NONE, NULL, "", NULL }
 
};
 

	
 
static void buddyListNewNode(PurpleBlistNode *node) {
 
	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 (!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(user->getRosterManager(), -1, buddy);
 
		SpectrumBuddy *s_buddy = (SpectrumBuddy *) buddy->node.ui_data;
 
		s_buddy->setFlags(BUDDY_JID_ESCAPING);
 
	}
 
}
 

	
 
static void buddyStatusChanged(PurpleBuddy *buddy, PurpleStatus *status, PurpleStatus *old_status) {
 
	SpectrumBuddy *s_buddy = (SpectrumBuddy *) buddy->node.ui_data;
 
	PurpleAccount *account = purple_buddy_get_account(buddy);
 
	User *user = (User *) account->ui_data;
 

	
 
	if (!user || !s_buddy)
 
		return;
 

	
 
	s_buddy->buddyChanged();
 
}
 

	
 
static void buddySignedOn(PurpleBuddy *buddy) {
 
	SpectrumBuddy *s_buddy = (SpectrumBuddy *) buddy->node.ui_data;
 
	PurpleAccount *account = purple_buddy_get_account(buddy);
 
	User *user = (User *) account->ui_data;
 

	
 
	if (!user || !s_buddy)
 
		return;
 

	
 
	s_buddy->buddyChanged();
 
}
 

	
 
static void buddySignedOff(PurpleBuddy *buddy) {
 
	SpectrumBuddy *s_buddy = (SpectrumBuddy *) buddy->node.ui_data;
 
	PurpleAccount *account = purple_buddy_get_account(buddy);
 
	User *user = (User *) account->ui_data;
 

	
 
	if (!user || !s_buddy)
 
		return;
 

	
 
	s_buddy->buddyChanged();
 
}
 

	
 
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) {
 
			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 conv_new(PurpleConversation *conv) {
 
	PurpleAccount *account = purple_conversation_get_account(conv);
 
	User *user = (User *) account->ui_data;
 

	
 
	if (!user)
 
		return;
 

	
 
	std::string name = purple_conversation_get_name(conv);
 
	size_t pos = name.find("/");
 
	if (pos != std::string::npos)
 
		name.erase((int) pos, name.length() - (int) pos);
 

	
 
	SpectrumConversation *s_conv = new SpectrumConversation(user->getConversationManager(), name, conv);
 
	conv->ui_data = s_conv;
 
}
 

	
 
static void conv_destroy(PurpleConversation *conv) {
 
	SpectrumConversation *s_conv = (SpectrumConversation *) conv->ui_data;
 
	if (s_conv) {
 
		delete s_conv;
 
	}
 
}
 

	
 
static void conv_write_im(PurpleConversation *conv, const char *who, const char *message, PurpleMessageFlags flags, time_t mtime) {
 
	// Don't forwards our own messages.
 
	if (flags & PURPLE_MESSAGE_SEND || flags & PURPLE_MESSAGE_SYSTEM)
 
		return;
 
	SpectrumConversation *s_conv = (SpectrumConversation *) conv->ui_data;
 
	if (!s_conv)
 
		return;
 

	
 
	boost::shared_ptr<Swift::Message> msg(new Swift::Message());
 
	msg->setBody(message);
 

	
 
	s_conv->handleMessage(msg);
 
}
 

	
 
static PurpleConversationUiOps conversation_ui_ops =
 
{
 
	conv_new,
 
	conv_destroy,
 
	NULL,//conv_write_chat,                              /* write_chat           */
 
	conv_write_im,             /* write_im             */
 
	NULL,//conv_write_conv,           /* write_conv           */
 
	NULL,//conv_chat_add_users,       /* chat_add_users       */
 
	NULL,//conv_chat_rename_user,     /* chat_rename_user     */
 
	NULL,//conv_chat_remove_users,    /* chat_remove_users    */
 
	NULL,//pidgin_conv_chat_update_user,     /* chat_update_user     */
 
	NULL,//pidgin_conv_present_conversation, /* present              */
 
	NULL,//pidgin_conv_has_focus,            /* has_focus            */
 
	NULL,//pidgin_conv_custom_smiley_add,    /* custom_smiley_add    */
 
	NULL,//pidgin_conv_custom_smiley_write,  /* custom_smiley_write  */
 
	NULL,//pidgin_conv_custom_smiley_close,  /* custom_smiley_close  */
 
	NULL,//pidgin_conv_send_confirm,         /* send_confirm         */
 
	NULL,
 
	NULL,
 
	NULL,
 
	NULL
 
};
 

	
 
static void transport_core_ui_init(void)
 
{
 
	purple_blist_set_ui_ops(&blistUiOps);
 
// 	purple_accounts_set_ui_ops(&accountUiOps);
 
// 	purple_notify_set_ui_ops(&notifyUiOps);
 
// 	purple_request_set_ui_ops(&requestUiOps);
 
// 	purple_xfers_set_ui_ops(getXferUiOps());
 
// 	purple_connections_set_ui_ops(&conn_ui_ops);
 
	purple_conversations_set_ui_ops(&conversation_ui_ops);
 
// #ifndef WIN32
 
// 	purple_dnsquery_set_ui_ops(getDNSUiOps());
 
// #endif
 
}
 

	
 
static PurpleCoreUiOps coreUiOps =
 
{
 
	NULL,
 
// 	debug_init,
 
	NULL,
 
	transport_core_ui_init,
 
	NULL,
 
	NULL,
 
	NULL,
 
	NULL,
 
	NULL
 
};
 

	
 
static void printDebug(PurpleDebugLevel level, const char *category, const char *arg_s) {
 
	std::string c("[LIBPURPLE");
 

	
 
	if (category) {
 
		c.push_back('/');
 
		c.append(category);
 
	}
 

	
 
	c.push_back(']');
 

	
 
	std::cout << c << " " << arg_s;
 
}
 

	
 
/*
 
 * Ops....
 
 */
 
static PurpleDebugUiOps debugUiOps =
 
{
 
	printDebug,
 
	NULL,
 
	NULL,
 
	NULL,
 
	NULL,
 
	NULL
 
};
 

	
 
static bool initPurple(Config &cfg) {
 
	bool ret;
 

	
 
	purple_util_set_user_dir("./");
 
	remove("./accounts.xml");
 
	remove("./blist.xml");
 

	
 
// 	if (m_configuration.logAreas & LOG_AREA_PURPLE)
 
		purple_debug_set_ui_ops(&debugUiOps);
 

	
 
	purple_core_set_ui_ops(&coreUiOps);
 
	purple_eventloop_set_ui_ops(getEventLoopUiOps());
 

	
 
	ret = purple_core_init("spectrum");
 
	if (ret) {
 
		static int conversation_handle;
 
		static int conn_handle;
 
		static int blist_handle;
 

	
 
		purple_set_blist(purple_blist_new());
 
		purple_blist_load();
 

	
 
		purple_prefs_load();
 

	
 
		/* Good default preferences */
 
		/* The combination of these two settings mean that libpurple will never
 
		 * (of its own accord) set all the user accounts idle.
 
		 */
 
		purple_prefs_set_bool("/purple/away/away_when_idle", false);
 
		/*
 
		 * This must be set to something not "none" for idle reporting to work
 
		 * for, e.g., the OSCAR prpl. We don't implement the UI ops, so this is
 
		 * okay for now.
 
		 */
 
		purple_prefs_set_string("/purple/away/idle_reporting", "system");
 

	
 
		/* Disable all logging */
 
		purple_prefs_set_bool("/purple/logging/log_ims", false);
 
		purple_prefs_set_bool("/purple/logging/log_chats", false);
 
		purple_prefs_set_bool("/purple/logging/log_system", false);
 

	
 

	
 
// 		purple_signal_connect(purple_conversations_get_handle(), "received-im-msg", &conversation_handle, PURPLE_CALLBACK(newMessageReceived), NULL);
 
// 		purple_signal_connect(purple_conversations_get_handle(), "buddy-typing", &conversation_handle, PURPLE_CALLBACK(buddyTyping), NULL);
 
// 		purple_signal_connect(purple_conversations_get_handle(), "buddy-typed", &conversation_handle, PURPLE_CALLBACK(buddyTyped), NULL);
 
// 		purple_signal_connect(purple_conversations_get_handle(), "buddy-typing-stopped", &conversation_handle, PURPLE_CALLBACK(buddyTypingStopped), NULL);
 
// 		purple_signal_connect(purple_connections_get_handle(), "signed-on", &conn_handle,PURPLE_CALLBACK(signed_on), NULL);
 
// 		purple_signal_connect(purple_blist_get_handle(), "buddy-removed", &blist_handle,PURPLE_CALLBACK(buddyRemoved), NULL);
 
		purple_signal_connect(purple_blist_get_handle(), "buddy-signed-on", &blist_handle,PURPLE_CALLBACK(buddySignedOn), NULL);
 
		purple_signal_connect(purple_blist_get_handle(), "buddy-signed-off", &blist_handle,PURPLE_CALLBACK(buddySignedOff), NULL);
 
		purple_signal_connect(purple_blist_get_handle(), "buddy-status-changed", &blist_handle,PURPLE_CALLBACK(buddyStatusChanged), NULL);
 
		purple_signal_connect(purple_blist_get_handle(), "blist-node-removed", &blist_handle,PURPLE_CALLBACK(NodeRemoved), NULL);
 
// 		purple_signal_connect(purple_conversations_get_handle(), "chat-topic-changed", &conversation_handle, PURPLE_CALLBACK(conv_chat_topic_changed), NULL);
 
// 
 
// 		purple_commands_init();
 

	
 
	}
 
	return ret;
 
}
 

	
 
static void handleUserReadyToConnect(User *user) {
 
	PurpleAccount *account = (PurpleAccount *) user->getData();
 
	purple_account_set_enabled(account, "spectrum", TRUE);
 
	
 
	const PurpleStatusType *status_type = purple_account_get_status_type_with_primitive(account, PURPLE_STATUS_AVAILABLE);
 
	if (status_type != NULL) {
 
		purple_account_set_status(account, purple_status_type_get_id(status_type), TRUE, NULL);
 
	}
 
}
 

	
 
static void handleUserCreated(User *user, UserManager *userManager, Config *config) {
 
	UserInfo userInfo = user->getUserInfo();
 
	PurpleAccount *account = NULL;
 
	const char *protocol = CONFIG_STRING(config, "service.protocol").c_str();
 
	if (purple_accounts_find(userInfo.uin.c_str(), protocol) != NULL){
 
		Log(userInfo.jid, "this account already exists");
 
		account = purple_accounts_find(userInfo.uin.c_str(), protocol);
 
		User *u = (User *) account->ui_data;
 
		if (u && u != user) {
 
			Log(userInfo.jid, "This account is already connected by another jid " << user->getJID());
 
			return;
 
		}
 
	}
 
	else {
 
		Log(userInfo.jid, "creating new account");
 
		account = purple_account_new(userInfo.uin.c_str(), protocol);
 

	
 
		purple_accounts_add(account);
 
	}
 
// 	Transport::instance()->collector()->stopCollecting(m_account);
 

	
 
// 	PurplePlugin *plugin = purple_find_prpl(protocol);
 
// 	PurplePluginProtocolInfo *prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(plugin);
 
// 	for (GList *l = prpl_info->protocol_options; l != NULL; l = l->next) {
 
// 		PurpleAccountOption *option = (PurpleAccountOption *) l->data;
 
// 		purple_account_remove_setting(account, purple_account_option_get_setting(option));
 
// 	}
 
// 
 
// 	std::map <std::string, PurpleAccountSettingValue> &settings = Transport::instance()->getConfiguration().purple_account_settings;
 
// 	for (std::map <std::string, PurpleAccountSettingValue>::iterator it = settings.begin(); it != settings.end(); it++) {
 
// 		PurpleAccountSettingValue v = (*it).second;
 
// 		std::string key((*it).first);
 
// 		switch (v.type) {
 
// 			case PURPLE_PREF_BOOLEAN:
 
// 				purple_account_set_bool(m_account, key.c_str(), v.b);
 
// 				break;
 
// 
 
// 			case PURPLE_PREF_INT:
 
// 				purple_account_set_int(m_account, key.c_str(), v.i);
 
// 				break;
 
// 
 
// 			case PURPLE_PREF_STRING:
 
// 				if (v.str)
 
// 					purple_account_set_string(m_account, key.c_str(), v.str);
 
// 				else
 
// 					purple_account_remove_setting(m_account, key.c_str());
 
// 				break;
 
// 
 
// 			case PURPLE_PREF_STRING_LIST:
 
// 				// TODO:
 
// 				break;
 
// 
 
// 			default:
 
// 				continue;
 
// 		}
 
// 	}
 

	
 
	purple_account_set_string(account, "encoding", userInfo.encoding.empty() ? CONFIG_STRING(config, "registration.encoding").c_str() : userInfo.encoding.c_str());
 
	purple_account_set_bool(account, "use_clientlogin", false);
 
// 	purple_account_set_bool(account, "require_tls",  Transport::instance()->getConfiguration().require_tls);
 
// 	purple_account_set_bool(account, "use_ssl",  Transport::instance()->getConfiguration().require_tls);
 
	purple_account_set_bool(account, "direct_connect", false);
 
// 	purple_account_set_bool(account, "check-mail", purple_value_get_boolean(getSetting("enable_notify_email")));
 

	
 
	account->ui_data = user;
 
	user->setData(account);
 

	
 
	user->onReadyToConnect.connect(boost::bind(&handleUserReadyToConnect, user));
 
	_logger->setRosterManager(user->getRosterManager());
 
	
 
// 	Transport::instance()->protocol()->onPurpleAccountCreated(m_account);
 

	
 
// 	m_loadingBuddiesFromDB = true;
 
// 	loadRoster();
 
// 	m_loadingBuddiesFromDB = false;
 

	
 
// 	m_connectionStart = time(NULL);
 
// 	m_readyForConnect = false;
 
	purple_account_set_password(account, userInfo.password.c_str());
 
// 	Log(m_jid, "UIN:" << m_username << " USER_ID:" << m_userID);
 
}
 

	
 
static void handleUserDestroyed(User *user, UserManager *userManager, Config *config) {
 
	PurpleAccount *account = (PurpleAccount *) user->getData();
 
	if (account) {
 
		purple_account_set_enabled(account, "spectrum", FALSE);
 

	
 
		// Remove conversations.
 
		// This has to be called before m_account->ui_data = NULL;, because it uses
 
		// ui_data to call SpectrumMessageHandler::purpleConversationDestroyed() callback.
 
		GList *iter;
 
		for (iter = purple_get_conversations(); iter; ) {
 
			PurpleConversation *conv = (PurpleConversation*) iter->data;
 
			iter = iter->next;
 
			if (purple_conversation_get_account(conv) == account)
 
				purple_conversation_destroy(conv);
 
		}
 

	
 
		account->ui_data = NULL;
 
// 		Transport::instance()->collector()->collect(m_account);
 
	}
 
}
 

	
 
class SpectrumFactory : public Factory {
 
	public:
 
		AbstractConversation *createConversation(ConversationManager *conversationManager, const std::string &legacyName) {
 
			PurpleConversation *conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, (PurpleAccount *) conversationManager->getUser()->getData() , legacyName.c_str());
 
			return (AbstractConversation *) conv->ui_data;
 
		}
 
};
 

	
 
int main(int argc, char **argv) {
 
	GError *error = NULL;
 
	GOptionContext *context;
 
	context = g_option_context_new("config_file_name or profile name");
 
	g_option_context_add_main_entries(context, options_entries, "");
 
	if (!g_option_context_parse (context, &argc, &argv, &error)) {
 
		std::cout << "option parsing failed: " << error->message << "\n";
 
		return -1;
 
	}
 

	
 
	if (ver) {
 
// 		std::cout << VERSION << "\n";
 
		std::cout << "verze\n";
 
		g_option_context_free(context);
 
		return 0;
 
	}
 

	
 
	if (argc != 2) {
 
#ifdef WIN32
 
		std::cout << "Usage: spectrum.exe <configuration_file.cfg>\n";
 
#else
 

	
 
#if GLIB_CHECK_VERSION(2,14,0)
 
	std::cout << g_option_context_get_help(context, FALSE, NULL);
 
#else
 
	std::cout << "Usage: spectrum <configuration_file.cfg>\n";
 
	std::cout << "See \"man spectrum\" for more info.\n";
 
#endif
 
		
 
#endif
 
	}
 
	else {
 
#ifndef WIN32
 
// 		signal(SIGPIPE, SIG_IGN);
 
// 
 
// 		if (signal(SIGCHLD, spectrum_sigchld_handler) == SIG_ERR) {
 
// 			std::cout << "SIGCHLD handler can't be set\n";
 
// 			g_option_context_free(context);
 
// 			return -1;
 
// 		}
 
// 
 
// 		if (signal(SIGINT, spectrum_sigint_handler) == SIG_ERR) {
 
// 			std::cout << "SIGINT handler can't be set\n";
 
// 			g_option_context_free(context);
 
// 			return -1;
 
// 		}
 
// 
 
// 		if (signal(SIGTERM, spectrum_sigterm_handler) == SIG_ERR) {
 
// 			std::cout << "SIGTERM handler can't be set\n";
 
// 			g_option_context_free(context);
 
// 			return -1;
 
// 		}
 
// 
 
// 		struct sigaction sa;
 
// 		memset(&sa, 0, sizeof(sa)); 
 
// 		sa.sa_handler = spectrum_sighup_handler;
 
// 		if (sigaction(SIGHUP, &sa, NULL)) {
 
// 			std::cout << "SIGHUP handler can't be set\n";
 
// 			g_option_context_free(context);
 
// 			return -1;
 
//		}
 
#endif
 
		Config config;
 
		if (!config.load(argv[1])) {
 
			std::cout << "Can't open " << argv[1] << " configuration file.\n";
 
			return 1;
 
		}
 

	
 
		initPurple(config);
 

	
 
		SpectrumEventLoop eventLoop;
 
		Component transport(&eventLoop, &config);
 
		SpectrumFactory factory;
 
		Component transport(&eventLoop, &config, &factory);
 
		Logger logger(&transport);
 
		_logger = &logger;
 

	
 
		SQLite3Backend sql(&config);
 
		logger.setStorageBackend(&sql);
 
		if (!sql.connect()) {
 
			std::cout << "Can't connect to database.\n";
 
		}
 

	
 
		UserManager userManager(&transport, &sql);
 
		userManager.onUserCreated.connect(boost::bind(&handleUserCreated, _1, &userManager, &config));
 
		userManager.onUserDestroyed.connect(boost::bind(&handleUserDestroyed, _1, &userManager, &config));
 

	
 
		UserRegistration userRegistration(&transport, &userManager, &sql);
 
		logger.setUserRegistration(&userRegistration);
 
		logger.setUserManager(&userManager);
 

	
 
		transport.connect();
 
		eventLoop.run();
 
	}
 

	
 
	g_option_context_free(context);
 
}
spectrum/src/spectrumconversation.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 "spectrumconversation.h"
 
#include "transport/user.h"
 

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

	
 
SpectrumConversation::SpectrumConversation(ConversationManager *conversationManager, const std::string &legacyName, PurpleConversation *conv) : AbstractConversation(conversationManager, legacyName), m_conv(conv) {
 
}
 

	
 
SpectrumConversation::~SpectrumConversation() {
 
}
 

	
 
void SpectrumConversation::sendMessage(boost::shared_ptr<Swift::Message> &message) {
 
	
 
	// escape and send
 
	gchar *_markup = purple_markup_escape_text(message->getBody().c_str(), -1);
 
	if (purple_conversation_get_type(m_conv) == PURPLE_CONV_TYPE_IM) {
 
		purple_conv_im_send(PURPLE_CONV_IM(m_conv), _markup);
 
	}
 
	g_free(_markup);
 
}
 

	
 

	
spectrum/src/spectrumconversation.h
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
 
 */
 

	
 
#pragma once
 

	
 
#include <string>
 
#include "purple.h"
 
#include "account.h"
 
#include "glib.h"
 
#include <algorithm>
 
#include "transport/abstractconversation.h"
 
#include "transport/conversationmanager.h"
 
#include "transport/user.h"
 

	
 
using namespace Transport;
 

	
 
// Wrapper for PurpleBuddy
 
class SpectrumConversation : public AbstractConversation {
 
	public:
 
		SpectrumConversation(ConversationManager *conversationManager, const std::string &legacyName, PurpleConversation *conv);
 
		virtual ~SpectrumConversation();
 
		
 
		PurpleConversation *getConversation() { return m_conv; }
 

	
 
		void sendMessage(boost::shared_ptr<Swift::Message> &message);
 

	
 
	private:
 
		PurpleConversation *m_conv;
 
};
 

	
src/abstractconversation.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 <iostream>
 
#include "transport/abstractconversation.h"
 
#include "transport/conversationmanager.h"
 
#include "transport/user.h"
 
#include "transport/transport.h"
 
#include "transport/abstractbuddy.h"
 
#include "transport/rostermanager.h"
 

	
 
namespace Transport {
 

	
 
AbstractConversation::AbstractConversation(ConversationManager *conversationManager, const std::string &legacyName) : m_conversationManager(conversationManager) {
 
	m_conversationManager->setConversation(this);
 
	m_legacyName = legacyName;
 
	m_conversationManager->setConversation(this);
 
}
 

	
 
AbstractConversation::~AbstractConversation() {
 
	m_conversationManager->unsetConversation(this);
 
}
 

	
 
void AbstractConversation::handleMessage(boost::shared_ptr<Swift::Message> &message) {
 
	message->setTo(m_conversationManager->getUser()->getJID().toBare());
 
	AbstractBuddy *buddy = m_conversationManager->getUser()->getRosterManager()->getBuddy(m_legacyName);
 
	if (buddy) {
 
		std::cout << m_legacyName << " 222222\n";
 
		message->setFrom(buddy->getJID());
 
	}
 
	else {
 
		std::cout << m_legacyName << " 1111111\n";
 
		// TODO: escape from and setFrom
 
	}
 
	m_conversationManager->getComponent()->getStanzaChannel()->sendMessage(message);
 
}
 

	
 
}
src/conversationmanager.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/conversationmanager.h"
 
#include "transport/abstractconversation.h"
 
#include "transport/usermanager.h"
 
#include "transport/abstractbuddy.h"
 
#include "transport/factory.h"
 
#include "transport/user.h"
 
#include "Swiften/Roster/SetRosterRequest.h"
 
#include "Swiften/Elements/RosterPayload.h"
 
#include "Swiften/Elements/RosterItemPayload.h"
 

	
 
namespace Transport {
 

	
 
ConversationManager::ConversationManager(User *user, Component *component){
 
	m_user = user;
 
	m_component = component;
 
}
 

	
 
ConversationManager::~ConversationManager() {
 
}
 

	
 
void ConversationManager::setConversation(AbstractConversation *conv) {
 
	m_convs[conv->getLegacyName()] = conv;
 
}
 

	
 
void ConversationManager::unsetConversation(AbstractConversation *conv) {
 
	m_convs.erase(conv->getLegacyName());
 
}
 

	
 
void ConversationManager::handleMessageReceived(Swift::Message::ref message) {
 
	std::string name = message->getTo().getUnescapedNode();
 
	if (name.find_last_of("%") != std::string::npos) {
 
		name.replace(name.find_last_of("%"), 1, "@");
 
	}
 

	
 
	if (!m_convs[name]) {
 
		m_convs[name] = m_component->getFactory()->createConversation(this, name);
 
	}
 
	m_convs[name]->sendMessage(message);
 
}
 

	
 
}
 
\ No newline at end of file
src/transport.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/transport.h"
 
#include <boost/bind.hpp>
 
#include "transport/storagebackend.h"
 
#include "transport/factory.h"
 
#include "discoinforesponder.h"
 
#include "discoitemsresponder.h"
 
#include "rosterresponder.h"
 

	
 
using namespace Swift;
 
using namespace boost;
 

	
 
namespace Transport {
 

	
 

	
 
class MyUserRegistry : public Swift::UserRegistry {
 
	public:
 
		MyUserRegistry() {}
 
		~MyUserRegistry() {}
 
		bool isValidUserPassword(const JID& user, const std::string& password) const {
 
			users[user.toBare().toString()] = password;
 
			return true;
 
		}
 
		mutable std::map<std::string, std::string> users;
 
};
 

	
 
Component::Component(Swift::EventLoop *loop, Config *config) {
 
Component::Component(Swift::EventLoop *loop, Config *config, Factory *factory) {
 
	m_component = NULL;
 
	m_userRegistry = NULL;
 
	m_server = NULL;
 
	m_reconnectCount = 0;
 
	m_config = config;
 
	m_factory = factory;
 

	
 
	m_jid = Swift::JID(CONFIG_STRING(m_config, "service.jid"));
 

	
 
	m_factories = new BoostNetworkFactories(loop);
 

	
 
	m_reconnectTimer = m_factories->getTimerFactory()->createTimer(1000);
 
	m_reconnectTimer->onTick.connect(bind(&Component::connect, this)); 
 

	
 
	if (CONFIG_BOOL(m_config, "service.server_mode")) {
 
		m_userRegistry = new MyUserRegistry();
 
		m_server = new Swift::Server(loop, m_factories, m_userRegistry, m_jid, CONFIG_INT(m_config, "service.port"));
 
		m_server->start();
 
		m_stanzaChannel = m_server->getStanzaChannel();
 
		m_iqRouter = m_server->getIQRouter();
 
	}
 
	else {
 
		m_component = new Swift::Component(loop, m_factories, m_jid, CONFIG_STRING(m_config, "service.password"));
 
		m_component->setSoftwareVersion("", "");
 
		m_component->onConnected.connect(bind(&Component::handleConnected, this));
 
		m_component->onError.connect(bind(&Component::handleConnectionError, this, _1));
 
		m_component->onDataRead.connect(bind(&Component::handleDataRead, this, _1));
 
		m_component->onDataWritten.connect(bind(&Component::handleDataWritten, this, _1));
 
		m_component->onPresenceReceived.connect(bind(&Component::handlePresenceReceived, this, _1));
 
// 		m_component->onMessageReceived.connect(bind(&Component::handleMessageReceived, this, _1));
 
		m_stanzaChannel = m_component->getStanzaChannel();
 
		m_iqRouter = m_component->getIQRouter();
 
	}
 

	
 
	m_capsMemoryStorage = new CapsMemoryStorage();
 
	m_capsManager = new CapsManager(m_capsMemoryStorage, m_stanzaChannel, m_iqRouter);
 
	m_entityCapsManager = new EntityCapsManager(m_capsManager, m_stanzaChannel);
 
 	m_entityCapsManager->onCapsChanged.connect(boost::bind(&Component::handleCapsChanged, this, _1));
 
	
 
	m_presenceOracle = new PresenceOracle(m_stanzaChannel);
 
	m_presenceOracle->onPresenceChange.connect(bind(&Component::handlePresence, this, _1));
 

	
 
	m_discoInfoResponder = new DiscoInfoResponder(m_iqRouter);
 
	m_discoInfoResponder->start();
 

	
 
	m_discoItemsResponder = new DiscoItemsResponder(m_iqRouter);
 
	m_discoItemsResponder->start();
 

	
 
	m_rosterResponder = new RosterResponder(m_iqRouter);
 
	m_rosterResponder->start();
 
	
 
// 
 
// 	m_registerHandler = new SpectrumRegisterHandler(m_component);
 
// 	m_registerHandler->start();
 
}
 

	
 
Component::~Component() {
 
	delete m_presenceOracle;
 
	delete m_entityCapsManager;
 
	delete m_capsManager;
 
	delete m_capsMemoryStorage;
 
	delete m_rosterResponder;
 
	delete m_discoInfoResponder;
 
	if (m_component)
 
		delete m_component;
 
	if (m_server)
 
		delete m_server;
 
	if (m_userRegistry)
 
		delete m_userRegistry;
 
	delete m_factories;
 
}
 

	
 
const std::string &Component::getUserRegistryPassword(const std::string &barejid) {
 
	MyUserRegistry *registry = dynamic_cast<MyUserRegistry *>(m_userRegistry);
 
	return registry->users[barejid];
 
}
 

	
 
Swift::StanzaChannel *Component::getStanzaChannel() {
 
	return m_stanzaChannel;
 
}
 

	
 
Swift::PresenceOracle *Component::getPresenceOracle() {
 
	return m_presenceOracle;
 
}
 

	
 
void Component::setTransportFeatures(std::list<std::string> &features) {
 
	m_discoInfoResponder->setTransportFeatures(features);
 
}
 

	
 
void Component::setBuddyFeatures(std::list<std::string> &features) {
 
	// TODO: handle caps change
 
	m_discoInfoResponder->setBuddyFeatures(features);
 
}
 

	
 
void Component::connect() {
 
	if (!m_component)
 
		return;
 
	m_reconnectCount++;
 
	m_component->connect(CONFIG_STRING(m_config, "service.server"), CONFIG_INT(m_config, "service.port"));
 
	m_reconnectTimer->stop();
 
}
 

	
 
void Component::handleConnected() {
 
	onConnected();
 
	m_reconnectCount = 0;
 
}
 

	
 
void Component::handleConnectionError(const ComponentError &error) {
 
	onConnectionError(error);
 
// 	if (m_reconnectCount == 2)
 
// 		Component::instance()->userManager()->removeAllUsers();
 

	
 
	m_reconnectTimer->start();
 
}
 

	
 
void Component::handleDataRead(const std::string &data) {
 
	onXMLIn(data);
 
}
 

	
 
void Component::handleDataWritten(const std::string &data) {
 
	onXMLOut(data);
 
}
 

	
 
void Component::handlePresenceReceived(Swift::Presence::ref presence) {
 
	switch(presence->getType()) {
 
		case Swift::Presence::Subscribe:
 
		case Swift::Presence::Subscribed:
 
		case Swift::Presence::Unsubscribe:
 
		case Swift::Presence::Unsubscribed:
 
			handleSubscription(presence);
 
			break;
 
		case Swift::Presence::Available:
 
		case Swift::Presence::Unavailable:
 
			break;
 
		case Swift::Presence::Probe:
 
			handleProbePresence(presence);
 
			break;
 
		default:
 
			break;
 
	};
 
}
 

	
 
void Component::handlePresence(Swift::Presence::ref presence) {
 
	bool isMUC = presence->getPayload<MUCPayload>() != NULL;
 

	
 
	// filter out login/logout presence spam
 
	if (!presence->getTo().getNode().empty() && isMUC == false)
 
		return;
 

	
 
	// filter out bad presences
 
	if (!presence->getFrom().isValid()) {
 
		Swift::Presence::ref response = Swift::Presence::create();
 
		response->setTo(presence->getFrom());
 
		response->setFrom(presence->getTo());
 
		response->setType(Swift::Presence::Error);
 

	
 
		response->addPayload(boost::shared_ptr<Payload>(new ErrorPayload(ErrorPayload::JIDMalformed, ErrorPayload::Modify)));
 

	
 
		m_component->sendPresence(response);
 
		return;
 
	}
 

	
 
	// check if we have this client's capabilities and ask for them
 
	bool haveFeatures = false;
 
	if (presence->getType() != Swift::Presence::Unavailable) {
 
		boost::shared_ptr<CapsInfo> capsInfo = presence->getPayload<CapsInfo>();
 
		if (capsInfo && capsInfo->getHash() == "sha-1") {
 
			haveFeatures = m_entityCapsManager->getCaps(presence->getFrom()) != DiscoInfo::ref();
 
			std::cout << "has capsInfo " << haveFeatures << "\n";
 
		}
 
// 		else {
 
// 			GetDiscoInfoRequest::ref discoInfoRequest = GetDiscoInfoRequest::create(presence->getFrom(), m_iqRouter);
 
// 			discoInfoRequest->onResponse.connect(boost::bind(&Component::handleDiscoInfoResponse, this, _1, _2, presence->getFrom()));
 
// 			discoInfoRequest->send();
 
// 		}
 
	}
 

	
 
	onUserPresenceReceived(presence);
 
}
 

	
 
void Component::handleProbePresence(Swift::Presence::ref presence) {
 
	
 
}
 

	
 
void Component::handleSubscription(Swift::Presence::ref presence) {
 
	// answer to subscibe
 
	if (presence->getType() == Swift::Presence::Subscribe && presence->getTo().getNode().empty()) {
 
// 		Log(presence->getFrom().toString().getUTF8String(), "Subscribe presence received => sending subscribed");
 
		Swift::Presence::ref response = Swift::Presence::create();
 
		response->setFrom(presence->getTo());
 
		response->setTo(presence->getFrom());
 
		response->setType(Swift::Presence::Subscribed);
 
		m_component->sendPresence(response);
 
		return;
 
	}
 

	
 
	if (m_protocol == "irc") {
 
		return;
src/usermanager.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/usermanager.h"
 
#include "transport/user.h"
 
#include "transport/transport.h"
 
#include "transport/storagebackend.h"
 
#include "transport/conversationmanager.h"
 

	
 
namespace Transport {
 

	
 
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));
 
	m_component->getStanzaChannel()->onMessageReceived.connect(bind(&UserManager::handleMessageReceived, this, _1));
 
// 	component->onDiscoInfoResponse.connect(bind(&UserManager::handleDiscoInfoResponse, this, _1, _2, _3));
 
}
 

	
 
UserManager::~UserManager(){
 
}
 

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

	
 
	if (m_users.find(barejid) != m_users.end()) {
 
		User *user = m_users[barejid];
 
		m_cachedUser = user;
 
		return user;
 
	}
 
	return NULL;
 
}
 

	
 
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();
 
	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->getStanzaChannel()->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 && m_component->inServerMode()) {
 
			res.password = m_component->getUserRegistryPassword(userkey);
 
			res.uin = presence->getFrom().getNode();
 
			res.jid = userkey;
 
			if (res.uin.find_last_of("%") != std::string::npos) {
 
				res.uin.replace(res.uin.find_last_of("%"), 1, "@");
 
			}
 
			m_storageBackend->setUser(res);
 
			registered = m_storageBackend->getUser(userkey, res);
 
		}
 

	
 
		if (!registered) {
 
			// TODO: logging
 
			return;
 
		}
 

	
 
		// TODO: isVIP
 
// // 			bool isVip = res.vip;
 
// // 			std::list<std::string> const &x = CONFIG().allowedServers;
 
// // 			if (CONFIG().onlyForVIP && !isVip && std::find(x.begin(), x.end(), presence->getFrom().getDomain().getUTF8String()) == x.end()) {
 
// // 				Log(presence->getFrom().toString().getUTF8String(), "This user is not VIP, can't login...");
 
// // 				return;
 
// // 			}
 
// // 
 
// // 
 
				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")));
 
// // // 
 
			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);
 
// 		}
 
	}
 
}
 

	
 
void UserManager::handleMessageReceived(Swift::Message::ref message) {
 
	User *user = getUser(message->getFrom().toBare().toString());
 
	if (!user ){
 
		return;
 
	}
 

	
 
	user->getConversationManager()->handleMessageReceived(message);
 
}
 

	
 
}
0 comments (0 inline, 0 general)