Changeset - 3201977efb6a
[Not reviewed]
backends/libcommuni/session.cpp
Show inline comments
 
/*
 
 * Copyright (C) 2008-2009 J-P Nurmi jpnurmi@gmail.com
 
 *
 
 * This example is free, and not covered by LGPL license. There is no
 
 * restriction applied to their modification, redistribution, using and so on.
 
 * You can study them, modify them, use them in your own program - either
 
 * completely or partially. By using it you may give me some credits in your
 
 * program, but you don't have to.
 
 */
 

	
 
#include "session.h"
 
#include <QtCore>
 
#include <iostream>
 
#include <IrcCommand>
 
#include <IrcMessage>
 

	
 
#include "ircnetworkplugin.h"
 

	
 
#define FROM_UTF8(WHAT) QString::fromUtf8((WHAT).c_str(), (WHAT).size())
 
#define TO_UTF8(WHAT) std::string((WHAT).toUtf8().data(), (WHAT).toUtf8().size())
 

	
 
#include "transport/logging.h"
 

	
 
DEFINE_LOGGER(logger, "IRCSession");
 

	
 
static bool sentList;
 

	
 
MyIrcSession::MyIrcSession(const std::string &user, IRCNetworkPlugin *np, const std::string &suffix, QObject* parent) : IrcSession(parent)
 
{
 
	this->np = np;
 
	this->user = user;
 
	this->suffix = suffix;
 
	m_connected = false;
 
	rooms = 0;
 
	connect(this, SIGNAL(disconnected()), SLOT(on_disconnected()));
 
	connect(this, SIGNAL(socketError(QAbstractSocket::SocketError)), SLOT(on_socketError(QAbstractSocket::SocketError)));
 
	connect(this, SIGNAL(connected()), SLOT(on_connected()));
 
	connect(this, SIGNAL(messageReceived(IrcMessage*)), this, SLOT(onMessageReceived(IrcMessage*)));
 
}
 

	
 
void MyIrcSession::on_connected() {
 
	m_connected = true;
 
	if (suffix.empty()) {
 
		np->handleConnected(user);
 
		if (!sentList) {
 
			sendCommand(IrcCommand::createList(""));
 
			sentList = true;
 
		}
 
	}
 

	
 
	for(AutoJoinMap::iterator it = m_autoJoin.begin(); it != m_autoJoin.end(); it++) {
 
		sendCommand(IrcCommand::createJoin(FROM_UTF8(it->second->getChannel()), FROM_UTF8(it->second->getPassword())));
 
	}
 

	
 
	if (getIdentify().find(" ") != std::string::npos) {
 
		std::string to = getIdentify().substr(0, getIdentify().find(" "));
 
		std::string what = getIdentify().substr(getIdentify().find(" ") + 1);
 
		sendCommand(IrcCommand::createMessage(FROM_UTF8(to), FROM_UTF8(what)));
 
	}
 
}
 

	
 
void MyIrcSession::on_socketError(QAbstractSocket::SocketError error) {
 
	on_disconnected();
 
}
 

	
 
void MyIrcSession::on_disconnected() {
 
	if (suffix.empty()) {
 
		np->handleDisconnected(user, 0, "");
 
		np->tryNextServer();
 
	}
 
	m_connected = false;
 
}
 

	
 
bool MyIrcSession::correctNickname(std::string &nickname) {
 
	bool flags = 0;
 
	switch(nickname.at(0)) {
 
		case '@': nickname = nickname.substr(1); flags = 1; break;
 
		case '+': nickname = nickname.substr(1); break;
 
		default: break;
 
	}
 
	return flags;
 
}
 

	
 
void MyIrcSession::on_joined(IrcMessage *message) {
 
	IrcJoinMessage *m = (IrcJoinMessage *) message;
 
	bool flags = 0;
 
	std::string nickname = TO_UTF8(m->sender().name());
 
	flags = correctNickname(nickname);
 
	np->handleParticipantChanged(user, nickname, TO_UTF8(m->channel()), (int) flags, pbnetwork::STATUS_ONLINE);
 
	LOG4CXX_INFO(logger, user << ": Joined " << TO_UTF8(m->parameters()[0]));
 
}
 

	
 

	
 
void MyIrcSession::on_parted(IrcMessage *message) {
 
	IrcPartMessage *m = (IrcPartMessage *) message;
 
	bool flags = 0;
 
	std::string nickname = TO_UTF8(m->sender().name());
 
	flags = correctNickname(nickname);
 
	LOG4CXX_INFO(logger, user << ": " << nickname << " parted " << TO_UTF8(m->channel()) + suffix);
 
	np->handleParticipantChanged(user, nickname, TO_UTF8(m->channel()) + suffix,(int) flags, pbnetwork::STATUS_NONE, TO_UTF8(m->reason()));
 
}
 

	
 
void MyIrcSession::on_quit(IrcMessage *message) {
 
	IrcQuitMessage *m = (IrcQuitMessage *) message;
 
	for(AutoJoinMap::iterator it = m_autoJoin.begin(); it != m_autoJoin.end(); it++) {
 
		bool flags = 0;
 
		std::string nickname = TO_UTF8(m->sender().name());
 
		flags = correctNickname(nickname);
 
		LOG4CXX_INFO(logger, user << ": " << nickname << " quit " << it->second->getChannel() + suffix);
 
		np->handleParticipantChanged(user, nickname, it->second->getChannel() + suffix,(int) flags, pbnetwork::STATUS_NONE, TO_UTF8(m->reason()));
 
	}
 
}
 

	
 
void MyIrcSession::on_nickChanged(IrcMessage *message) {
 
	IrcNickMessage *m = (IrcNickMessage *) message;
 

	
 
	for(AutoJoinMap::iterator it = m_autoJoin.begin(); it != m_autoJoin.end(); it++) {
 
		std::string nickname = TO_UTF8(m->sender().name());
 
		bool flags = m_modes[it->second->getChannel() + nickname];
 
		LOG4CXX_INFO(logger, user << ": " << nickname << " changed nickname to " << TO_UTF8(m->nick()));
 
		np->handleParticipantChanged(user, nickname, it->second->getChannel() + suffix,(int) flags, pbnetwork::STATUS_ONLINE, "", TO_UTF8(m->nick()));
 
	}
 
}
 

	
 
void MyIrcSession::on_modeChanged(IrcMessage *message) {
 
	IrcModeMessage *m = (IrcModeMessage *) message;
 

	
 
	// mode changed: "#testik" "HanzZ" "+o" "hanzz_k"
 
	std::string nickname = TO_UTF8(m->argument());
 
	std::string mode = TO_UTF8(m->mode());
 
	if (nickname.empty())
 
		return;
 
	LOG4CXX_INFO(logger, user << ": " << nickname << " changed mode to " << mode);
 
	for(AutoJoinMap::iterator it = m_autoJoin.begin(); it != m_autoJoin.end(); it++) {
 
		if (mode == "+o") {
 
			m_modes[it->second->getChannel() + nickname] = 1;
 
		}
 
		else {
 
			m_modes[it->second->getChannel() + nickname] = 0;
 
		}
 
		bool flags = m_modes[it->second->getChannel() + nickname];
 
		np->handleParticipantChanged(user, nickname, it->second->getChannel() + suffix,(int) flags, pbnetwork::STATUS_ONLINE, "");
 
	}
 
}
 

	
 
void MyIrcSession::on_topicChanged(IrcMessage *message) {
 
	IrcTopicMessage *m = (IrcTopicMessage *) message;
 

	
 
	bool flags = 0;
 
	std::string nickname = TO_UTF8(m->sender().name());
 
	flags = correctNickname(nickname);
 

	
 
	LOG4CXX_INFO(logger, user << ": " << nickname << " topic changed to " << TO_UTF8(m->topic()));
 
	np->handleSubject(user, TO_UTF8(m->channel()) + suffix, TO_UTF8(m->topic()), nickname);
 
}
 

	
 
void MyIrcSession::on_messageReceived(IrcMessage *message) {
 
	IrcPrivateMessage *m = (IrcPrivateMessage *) message;
 
	if (m->isRequest()) {
 
		QString request = m->message().split(" ", QString::SkipEmptyParts).value(0).toUpper();
 
		if (request == "PING" || request == "TIME" || request == "VERSION") {
 
			LOG4CXX_INFO(logger, user << ": " << TO_UTF8(request) << " received and has been answered");
 
			return;
 
		}
 
	}
 

	
 
	QString msg = m->message();
 
	if (m->isAction()) {
 
		msg = QString("/me ") + msg;
 
	}
 

	
 
	std::string target = TO_UTF8(m->target());
 
	LOG4CXX_INFO(logger, user << ": Message from " << target);
 
	if (target.find("#") == 0) {
 
		bool flags = 0;
 
		std::string nickname = TO_UTF8(m->sender().name());
 
		flags = correctNickname(nickname);
 
		np->handleMessage(user, target + suffix, TO_UTF8(msg), nickname);
 
	}
 
	else {
 
		bool flags = 0;
 
		std::string nickname = TO_UTF8(m->sender().name());
 
		flags = correctNickname(nickname);
 
		LOG4CXX_INFO(logger, nickname + suffix);
 
		np->handleMessage(user, nickname + suffix, TO_UTF8(msg));
 
	}
 
}
 

	
 
void MyIrcSession::on_numericMessageReceived(IrcMessage *message) {
 
	QString channel;
 
	QStringList members;
 

	
 
	IrcNumericMessage *m = (IrcNumericMessage *) message;
 
	switch (m->code()) {
 
		case 332:
 
			m_topicData = TO_UTF8(m->parameters().value(2));
 
			break;
 
		case 333:
 
			 np->handleSubject(user, TO_UTF8(m->parameters().value(1)) + suffix, m_topicData, TO_UTF8(m->parameters().value(2)));
 
			break;
 
		case 353:
 
			channel = m->parameters().value(2);
 
			members = m->parameters().value(3).split(" ");
 

	
 
			LOG4CXX_INFO(logger, user << ": Received members for " << TO_UTF8(channel) << suffix);
 
			for (int i = 0; i < members.size(); i++) {
 
				bool flags = 0;
 
				std::string nickname = TO_UTF8(members.at(i));
 
				flags = correctNickname(nickname);
 
				m_modes[TO_UTF8(channel) + nickname] = flags;
 
				np->handleParticipantChanged(user, nickname, TO_UTF8(channel) + suffix,(int) flags, pbnetwork::STATUS_ONLINE);
 
			}
 
			break;
 
		case 432:
 
			np->handleDisconnected(user, pbnetwork::CONNECTION_ERROR_INVALID_USERNAME, "Erroneous Nickname");
 
			break;
 
		case 321:
 
			m_rooms.clear();
 
			m_names.clear();
 
			break;
 
		case 322:
 
			m_rooms.push_back(TO_UTF8(m->parameters().value(1)));
 
			m_names.push_back(TO_UTF8(m->parameters().value(1)));
 
			break;
 
		case 323:
 
			np->handleRoomList("", m_rooms, m_names);
 
			break;
 
		default:
 
			break;
 
	}
 

	
 
	//qDebug() << "numeric message received:" << receiver() << origin << code << params;
 
}
 

	
 
void MyIrcSession::onMessageReceived(IrcMessage *message) {
 
	LOG4CXX_INFO(logger, user << ": " << TO_UTF8(message->toString()));
 
	switch (message->type()) {
 
		case IrcMessage::Join:
 
			on_joined(message);
 
			break;
 
		case IrcMessage::Part:
 
			on_parted(message);
 
			break;
 
		case IrcMessage::Quit:
 
			on_quit(message);
 
			break;
 
		case IrcMessage::Nick:
 
			on_nickChanged(message);
 
			break;
 
		case IrcMessage::Mode:
 
			on_modeChanged(message);
 
			break;
 
		case IrcMessage::Topic:
 
			on_topicChanged(message);
 
			break;
 
		case IrcMessage::Private:
 
			on_messageReceived(message);
 
			break;
 
		case IrcMessage::Numeric:
 
			on_numericMessageReceived(message);
 
			break;
 
		default:break;
 
	}
 
}
backends/libcommuni/session.h
Show inline comments
 
/*
 
 * Copyright (C) 2008-2009 J-P Nurmi jpnurmi@gmail.com
 
 *
 
 * This example is free, and not covered by LGPL license. There is no
 
 * restriction applied to their modification, redistribution, using and so on.
 
 * You can study them, modify them, use them in your own program - either
 
 * completely or partially. By using it you may give me some credits in your
 
 * program, but you don't have to.
 
 */
 

	
 
#ifndef SESSION_H
 
#define SESSION_H
 

	
 
#include <IrcSession>
 
#include <transport/networkplugin.h>
 
#include "Swiften/Swiften.h"
 
#include <boost/smart_ptr/make_shared.hpp>
 

	
 
using namespace Transport;
 

	
 
class IRCNetworkPlugin;
 

	
 
class MyIrcSession : public IrcSession
 
{
 
    Q_OBJECT
 

	
 
public:
 
	class AutoJoinChannel {
 
		public:
 
			AutoJoinChannel(const std::string &channel = "", const std::string &password = "") : m_channel(channel), m_password(password) {}
 
			virtual ~AutoJoinChannel() {}
 

	
 
			const std::string &getChannel() { return m_channel; }
 
			const std::string &getPassword() { return m_password; }
 
		private:
 
			std::string m_channel;
 
			std::string m_password;
 
	};
 

	
 
	typedef std::map<std::string, boost::shared_ptr<AutoJoinChannel> > AutoJoinMap;
 

	
 
	MyIrcSession(const std::string &user, IRCNetworkPlugin *np, const std::string &suffix = "", QObject* parent = 0);
 
	std::map<std::string, bool> m_modes;
 
	std::string suffix;
 
	int rooms;
 

	
 
	void addAutoJoinChannel(const std::string &channel, const std::string &password) {
 
		m_autoJoin[channel] = boost::make_shared<AutoJoinChannel>(channel, password);
 
	}
 

	
 
	void removeAutoJoinChannel(const std::string &channel) {
 
		m_autoJoin.erase(channel);
 
	}
 

	
 
	void setIdentify(const std::string &identify) {
 
		m_identify = identify;
 
	}
 

	
 
	const std::string  &getIdentify() {
 
		return m_identify;
 
	}
 

	
 
	bool correctNickname(std::string &nickname);
 

	
 
	void on_joined(IrcMessage *message);
 
	void on_parted(IrcMessage *message);
 
	void on_quit(IrcMessage *message);
 
	void on_nickChanged(IrcMessage *message);
 
	void on_modeChanged(IrcMessage *message);
 
	void on_topicChanged(IrcMessage *message);
 
	void on_messageReceived(IrcMessage *message);
 
	void on_numericMessageReceived(IrcMessage *message);
 

	
 
protected Q_SLOTS:
 
	void on_connected();
 
	void on_disconnected();
 
	void on_socketError(QAbstractSocket::SocketError error);
 

	
 
	void onMessageReceived(IrcMessage* message);
 

	
 
protected:
 
	IRCNetworkPlugin *np;
 
	std::string user;
 
	std::string m_identify;
 
	AutoJoinMap m_autoJoin;
 
	std::string m_topicData;
 
	bool m_connected;
 
	std::list<std::string> m_rooms;
 
	std::list<std::string> m_names;
 
};
 

	
 
//class MyIrcBuffer : public Irc::Buffer
 
//{
 
//    Q_OBJECT
 

	
 
//public:
 
//	MyIrcBuffer(const QString& receiver, const std::string &user, NetworkPlugin *np, const std::string &suffix, Irc::Session* parent);
 
//	NetworkPlugin *np;
 
//	std::string user;
 
//	MyIrcSession *p;
 
//	std::string m_topicData;
 
//		std::string suffix;
 

	
 
//protected Q_SLOTS:
 
//    void on_receiverChanged(const QString& receiver);
 
//    void on_joined(const QString& origin);
 
//    void on_parted(const QString& origin, const QString& message);
 
//    void on_quit(const QString& origin, const QString& message);
 
//    void on_nickChanged(const QString& origin, const QString& nick);
 
//    void on_modeChanged(const QString& origin, const QString& mode, const QString& args);
 
//    void on_topicChanged(const QString& origin, const QString& topic);
 
//    void on_invited(const QString& origin, const QString& receiver, const QString& channel);
 
//    void on_kicked(const QString& origin, const QString& nick, const QString& message);
 
//    void on_messageReceived(const QString& origin, const QString& message, Irc::Buffer::MessageFlags flags);
 
//    void on_noticeReceived(const QString& origin, const QString& notice, Irc::Buffer::MessageFlags flags);
 
//    void on_ctcpRequestReceived(const QString& origin, const QString& request, Irc::Buffer::MessageFlags flags);
 
//    void on_ctcpReplyReceived(const QString& origin, const QString& reply, Irc::Buffer::MessageFlags flags);
 
//    void on_ctcpActionReceived(const QString& origin, const QString& action, Irc::Buffer::MessageFlags flags);
 
//    void on_numericMessageReceived(const QString& origin, uint code, const QStringList& params);
 
//    void on_unknownMessageReceived(const QString& origin, const QStringList& params);
 

	
 
//	bool correctNickname(std::string &nickname);
 
//};
 

	
 
#endif // SESSION_H
include/transport/discoitemsresponder.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/Queries/GetResponder.h"
 
#include "Swiften/Elements/DiscoItems.h"
 

	
 
namespace Transport {
 

	
 
class Component;
 
class DiscoInfoResponder;
 

	
 
class DiscoItemsResponder : public Swift::GetResponder<Swift::DiscoItems> {
 
	public:
 
		DiscoItemsResponder(Component *component);
 
		~DiscoItemsResponder();
 

	
 
		Swift::CapsInfo &getBuddyCapsInfo();
 

	
 
		void addAdHocCommand(const std::string &node, const std::string &name);
 
// 		void removeAdHocCommand(const std::string &node);
 

	
 
		void addRoom(const std::string &node, const std::string &name);
 
		void clearRooms();
 

	
 

	
 
	private:
 
		virtual bool handleGetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<Swift::DiscoItems> payload);
 

	
 
	private:
 
		Component *m_component;
 
		boost::shared_ptr<Swift::DiscoItems> m_commands;
 
		boost::shared_ptr<Swift::DiscoItems> m_rooms;
 
		DiscoInfoResponder *m_discoInfoResponder;
 
};
 

	
 
}
 
\ No newline at end of file
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/Network/BoostTimerFactory.h"
 
#include "Swiften/Network/BoostIOServiceThread.h"
 
#include "Swiften/Server/UserRegistry.h"
 
#include "Swiften/Base/SafeByteArray.h"
 
#include "Swiften/Jingle/JingleSessionManager.h"
 

	
 
#include <boost/bind.hpp>
 
#include "transport/config.h"
 
#include "transport/factory.h"
 
#include "transport/presenceoracle.h"
 
#include <Swiften/Network/BoostConnectionServer.h>
 

	
 
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 Factory;
 
	class UserRegistry;
 

	
 
	/// Represents one transport instance.
 

	
 
	/// It's used to connect the Jabber server and provides transaction layer
 
	/// between Jabber server and other classes.
 
	///
 
	/// In server mode it represents Jabber server to which users can connect and use
 
	/// it as transport.
 
	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
 
			/// 	- service.server_mode
 
			/// \param factory Transport Abstract factory used to create basic transport structures.
 
			Component(Swift::EventLoop *loop, Swift::NetworkFactories *factories, Config *config, Factory *factory, Transport::UserRegistry *userRegistry = NULL);
 

	
 
			/// Component destructor.
 
			~Component();
 

	
 
			/// Returns Swift::StanzaChannel associated with this Transport::Component.
 

	
 
			/// It can be used to send presences and other stanzas.
 
			/// \return Swift::StanzaChannel associated with this Transport::Component.
 
			Swift::StanzaChannel *getStanzaChannel();
 

	
 
			Swift::CapsInfo &getBuddyCapsInfo();
 

	
 
			/// Returns Swift::IQRouter associated with this Component.
 

	
 
			/// \return Swift::IQRouter associated with this Component.
 
			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.
 
			PresenceOracle *getPresenceOracle();
 

	
 
			/// Returns True if the component is in server mode.
 

	
 
			/// \return True if the component is in server mode.
 
			bool inServerMode() { return m_server != NULL; }
 

	
 
			/// Connects the Jabber server.
 

	
 
			void start();
 
			void stop();
 

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

	
 
			/// Returns Swift::NetworkFactories which can be used to create new connections.
 

	
 
			/// \return Swift::NetworkFactories which can be used to create new connections.
 
			Swift::NetworkFactories *getNetworkFactories() { return m_factories; }
 

	
 
			/// Returns Transport Factory used to create basic Transport components.
 

	
 
			/// \return Transport Factory used to create basic Transport components.
 
			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;
 

	
 
			Config *getConfig() { return m_config; }
 

	
 
			/// This signal is emitted when presence from XMPP user 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 (const Swift::JID& jid, boost::shared_ptr<Swift::DiscoInfo> info)> onUserDiscoInfoReceived;
 

	
 
// 			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 handleServerStopped(boost::optional<Swift::BoostConnectionServer::Error> e);
 
			void handlePresence(Swift::Presence::ref presence);
 
			void handleDataRead(const Swift::SafeByteArray &data);
 
			void handleDataWritten(const Swift::SafeByteArray &data);
 

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

	
 
			Swift::NetworkFactories *m_factories;
 
			Swift::Component *m_component;
 
			Swift::Server *m_server;
 
			Swift::Timer::ref m_reconnectTimer;
 
			Swift::EntityCapsManager *m_entityCapsManager;
 
			Swift::CapsManager *m_capsManager;
 
			Swift::CapsMemoryStorage *m_capsMemoryStorage;
 
			PresenceOracle *m_presenceOracle;
 
			Swift::StanzaChannel *m_stanzaChannel;
 
			Swift::IQRouter *m_iqRouter;
 
			
 
			Transport::UserRegistry *m_userRegistry;
 
			StorageBackend *m_storageBackend;
 
 			DiscoInfoResponder *m_discoInfoResponder;
 
			int m_reconnectCount;
 
			Config* m_config;
 
			std::string m_protocol;
 
			Swift::JID m_jid;
 
			Factory *m_factory;
 
			Swift::EventLoop *m_loop;
 

	
 
		friend class User;
 
		friend class UserRegistration;
 
		friend class NetworkPluginServer;
 
	};
 
}
include/transport/user.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 <time.h>
 
#include "Swiften/Swiften.h"
 
#include "Swiften/Disco/EntityCapsManager.h"
 
#include "Swiften/Disco/EntityCapsProvider.h"
 
#include "storagebackend.h"
 
#include <Swiften/FileTransfer/OutgoingFileTransfer.h>
 
#include "Swiften/Elements/SpectrumErrorPayload.h"
 

	
 
namespace Transport {
 

	
 
class Component;
 
class RosterManager;
 
class ConversationManager;
 
class UserManager;
 
class PresenceOracle;
 
struct UserInfo;
 

	
 
/// Represents online XMPP user.
 
class User : public Swift::EntityCapsProvider {
 
	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, UserManager *userManager);
 

	
 
		/// 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 full JID which supports particular feature or invalid JID.
 
		/// \param feature disco#info feature.
 
		/// \return full JID which supports particular feature or invalid JID.
 
		Swift::JID getJIDWithFeature(const std::string &feature);
 

	
 
		Swift::DiscoInfo::ref getCaps(const Swift::JID &jid) const;
 

	
 
		/// Returns UserInfo struct with informations needed to connect the legacy network.
 
		/// \return UserInfo struct
 
		UserInfo &getUserInfo() { return m_userInfo; }
 

	
 
		RosterManager *getRosterManager() { return m_rosterManager; }
 

	
 
		ConversationManager *getConversationManager() { return m_conversationManager; }
 

	
 
		Component *getComponent() { return m_component; }
 

	
 
		UserManager *getUserManager() { return m_userManager; }
 

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

	
 
		void handleSubscription(Swift::Presence::ref presence);
 

	
 
		void handleDiscoInfo(const Swift::JID& jid, boost::shared_ptr<Swift::DiscoInfo> info);
 

	
 
		time_t &getLastActivity() {
 
			return m_lastActivity;
 
		}
 

	
 
		void updateLastActivity() {
 
			m_lastActivity = time(NULL);
 
		}
 

	
 
		/// Returns language.
 
		/// \return language
 
		const char *getLang() { return "en"; }
 

	
 
		void handleDisconnected(const std::string &error, Swift::SpectrumErrorPayload::Error e = Swift::SpectrumErrorPayload::CONNECTION_ERROR_OTHER_ERROR);
 

	
 
		bool isReadyToConnect() {
 
			return m_readyForConnect;
 
		}
 

	
 
		void setConnected(bool connected);
 

	
 
		void sendCurrentPresence();
 

	
 
		void setIgnoreDisconnect(bool ignoreDisconnect);
 

	
 
		bool isConnected() {
 
			return m_connected;
 
		}
 

	
 
		int getResourceCount() {
 
			return m_resources;
 
		}
 

	
 
		boost::signal<void ()> onReadyToConnect;
 
		boost::signal<void (Swift::Presence::ref presence)> onPresenceChanged;
 
		boost::signal<void (const Swift::JID &who, const std::string &room, const std::string &nickname, const std::string &password)> onRoomJoined;
 
		boost::signal<void (const std::string &room)> onRoomLeft;
 
		boost::signal<void ()> onDisconnected;
 

	
 
	private:
 
		void onConnectingTimeout();
 

	
 
		Swift::JID m_jid;
 
		Component *m_component;
 
		RosterManager *m_rosterManager;
 
		UserManager *m_userManager;
 
		ConversationManager *m_conversationManager;
 
		Swift::EntityCapsManager *m_entityCapsManager;
 
		PresenceOracle *m_presenceOracle;
 
		UserInfo m_userInfo;
 
		void *m_data;
 
		bool m_connected;
 
		bool m_readyForConnect;
 
		bool m_ignoreDisconnect;
 
		Swift::Timer::ref m_reconnectTimer;
 
		boost::shared_ptr<Swift::Connection> connection;
 
		time_t m_lastActivity;
 
		std::map<Swift::JID, Swift::DiscoInfo::ref> m_legacyCaps;
 
		std::vector<boost::shared_ptr<Swift::OutgoingFileTransfer> > m_filetransfers;
 
		int m_resources;
 
		int m_reconnectCounter;
 
		std::vector<Swift::Presence::ref> m_joinedRooms;
 
};
 

	
 
}
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"
 
#include "transport/userregistry.h"
 

	
 
namespace Transport {
 

	
 
class User;
 
class Component;
 
class StorageBackend;
 
class StorageResponder;
 
class RosterResponder;
 
class DiscoItemsResponder;
 

	
 
/// 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.
 

	
 
/// Basic user creation process:
 
/**
 
	\msc
 
	Component,UserManager,User,StorageBackend,Slot;
 
	---  [ label = "Available presence received"];
 
	Component->UserManager [label="handlePresence(...)", URL="\ref UserManager::handlePresence()"];
 
	UserManager->StorageBackend [label="getUser(...)", URL="\ref StorageBackend::getUser()"];
 
	UserManager->User [label="User::User(...)", URL="\ref User"];
 
	UserManager->Slot [label="onUserCreated(...)", URL="\ref UserManager::onUserCreated()"];
 
	UserManager->User [label="handlePresence(...)", URL="\ref User::handlePresence()"];
 
	\endmsc
 
*/
 
class UserManager : public Swift::EntityCapsProvider {
 
	public:
 
		/// Creates new UserManager.
 
		/// \param component Component which's presence will be handled
 
		/// \param storageBackend Storage backend used to fetch UserInfos
 
		UserManager(Component *component, UserRegistry *userRegistry, StorageBackend *storageBackend = NULL);
 
		UserManager(Component *component, UserRegistry *userRegistry, DiscoItemsResponder *discoItemsResponder, StorageBackend *storageBackend = NULL);
 

	
 
		/// 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 map with all connected users.
 
		/// \return All connected users.
 
		const std::map<std::string, User *> &getUsers() {
 
			return m_users;
 
		}
 

	
 
		/// 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 StorageBackend.
 
		/// \param user User class to remove
 
		void removeUser(User *user, bool onUserBehalf = true);
 

	
 
		void removeAllUsers(bool onUserBehalf = true);
 

	
 
		Swift::DiscoInfo::ref getCaps(const Swift::JID&) const;
 

	
 
		DiscoItemsResponder *getDiscoResponder() { return m_discoItemsResponder; }
 

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

	
 
		/// Returns true if user is connected.
 
		/// \return True if user is connected.
 
		bool isUserConnected(const std::string &barejid) const {
 
			return m_users.find(barejid) != m_users.end();
 
		}
 

	
 
		/// Returns pointer to UserRegistry.
 
		/// \return Pointer to UserRegistry.
 
		UserRegistry *getUserRegistry() {
 
			return m_userRegistry;
 
		}
 

	
 
		Component *getComponent() {
 
			return m_component;
 
		}
 

	
 
		/// Connects user manually.
 
		/// \param user JID of user.
 
		void connectUser(const Swift::JID &user);
 

	
 
		/// Disconnects user manually.
 
		/// \param user JID of user.
 
		void disconnectUser(const Swift::JID &user);
 

	
 
		void messageToXMPPSent() { m_sentToXMPP++; }
 
		void messageToBackendSent() { m_sentToBackend++; }
 

	
 
		unsigned long getMessagesToXMPP() { return m_sentToXMPP; }
 
		unsigned long getMessagesToBackend() { return m_sentToBackend; }
 
		
 

	
 
	private:
 
		void handlePresence(Swift::Presence::ref presence);
 
		void handleMessageReceived(Swift::Message::ref message);
 
		void handleGeneralPresenceReceived(Swift::Presence::ref presence);
 
		void handleProbePresence(Swift::Presence::ref presence);
 
		void handleSubscription(Swift::Presence::ref presence);
 
		void handleRemoveTimeout(const std::string jid, User *user, bool reconnect);
 
		void handleDiscoInfo(const Swift::JID& jid, boost::shared_ptr<Swift::DiscoInfo> info);
 
		void addUser(User *user);
 

	
 
		long m_onlineBuddies;
 
		User *m_cachedUser;
 
		std::map<std::string, User *> m_users;
 
		Component *m_component;
 
		StorageBackend *m_storageBackend;
 
		StorageResponder *m_storageResponder;
 
		UserRegistry *m_userRegistry;
 
		Swift::Timer::ref m_removeTimer;
 
		unsigned long m_sentToXMPP;
 
		unsigned long m_sentToBackend;
 
		DiscoItemsResponder *m_discoItemsResponder;
 
		friend class RosterResponder;
 
};
 

	
 
}
spectrum/src/main.cpp
Show inline comments
 
@@ -291,147 +291,147 @@ int main(int argc, char **argv)
 
			return 1;
 
		}
 
		struct passwd *pw;
 
		if ((pw = getpwnam(CONFIG_STRING(&config, "service.user").c_str())) == NULL) {
 
			std::cerr << "Invalid service.user name " << CONFIG_STRING(&config, "service.user") << "\n";
 
			return 1;
 
		}
 
		chown(CONFIG_STRING(&config, "service.working_dir").c_str(), pw->pw_uid, gr->gr_gid);
 
	}
 

	
 
	char backendport[20];
 
	FILE* port_file_f;
 
	port_file_f = fopen(CONFIG_STRING(&config, "service.portfile").c_str(), "w+");
 
	if (port_file_f == NULL) {
 
		std::cerr << "Cannot create port_file file " << CONFIG_STRING(&config, "service.portfile").c_str() << ". Exiting\n";
 
		exit(1);
 
	}
 
	sprintf(backendport,"%s\n",CONFIG_STRING(&config, "service.backend_port").c_str());
 
	if (fwrite(backendport,1,strlen(backendport),port_file_f) < strlen(backendport)) {
 
		std::cerr << "Cannot write to port file " << CONFIG_STRING(&config, "service.portfile") << ". Exiting\n";
 
		exit(1);
 
	}
 
	fclose(port_file_f);
 

	
 
	if (!no_daemon) {
 
		// daemonize
 
		daemonize(CONFIG_STRING(&config, "service.working_dir").c_str(), CONFIG_STRING(&config, "service.pidfile").c_str());
 
// 		removeOldIcons(CONFIG_STRING(&config, "service.working_dir") + "/icons");
 
    }
 
#endif
 

	
 
	Logging::initMainLogging(&config);
 

	
 
#ifndef WIN32
 
	if (!CONFIG_STRING(&config, "service.group").empty() ||!CONFIG_STRING(&config, "service.user").empty() ) {
 
		struct rlimit limit;
 
		getrlimit(RLIMIT_CORE, &limit);
 

	
 
		if (!CONFIG_STRING(&config, "service.group").empty()) {
 
			struct group *gr;
 
			if ((gr = getgrnam(CONFIG_STRING(&config, "service.group").c_str())) == NULL) {
 
				std::cerr << "Invalid service.group name " << CONFIG_STRING(&config, "service.group") << "\n";
 
				return 1;
 
			}
 

	
 
			if (((setgid(gr->gr_gid)) != 0) || (initgroups(CONFIG_STRING(&config, "service.user").c_str(), gr->gr_gid) != 0)) {
 
				std::cerr << "Failed to set service.group name " << CONFIG_STRING(&config, "service.group") << " - " << gr->gr_gid << ":" << strerror(errno) << "\n";
 
				return 1;
 
			}
 
		}
 

	
 
		if (!CONFIG_STRING(&config, "service.user").empty()) {
 
			struct passwd *pw;
 
			if ((pw = getpwnam(CONFIG_STRING(&config, "service.user").c_str())) == NULL) {
 
				std::cerr << "Invalid service.user name " << CONFIG_STRING(&config, "service.user") << "\n";
 
				return 1;
 
			}
 

	
 
			if ((setuid(pw->pw_uid)) != 0) {
 
				std::cerr << "Failed to set service.user name " << CONFIG_STRING(&config, "service.user") << " - " << pw->pw_uid << ":" << strerror(errno) << "\n";
 
				return 1;
 
			}
 
		}
 
		setrlimit(RLIMIT_CORE, &limit);
 
	}
 

	
 
	struct rlimit limit;
 
	limit.rlim_max = RLIM_INFINITY;
 
	limit.rlim_cur = RLIM_INFINITY;
 
	setrlimit(RLIMIT_CORE, &limit);
 
#endif
 

	
 
	Swift::SimpleEventLoop eventLoop;
 

	
 
	Swift::BoostNetworkFactories *factories = new Swift::BoostNetworkFactories(&eventLoop);
 
	UserRegistry userRegistry(&config, factories);
 

	
 
	Component transport(&eventLoop, factories, &config, NULL, &userRegistry);
 
	component_ = &transport;
 
// 	Logger logger(&transport);
 

	
 
	std::string error;
 
	StorageBackend *storageBackend = StorageBackend::createBackend(&config, error);
 
	if (storageBackend == NULL) {
 
		if (!error.empty()) {
 
			std::cerr << error << "\n";
 
			return -2;
 
		}
 
	}
 
	else if (!storageBackend->connect()) {
 
		std::cerr << "Can't connect to database. Check the log to find out the reason.\n";
 
		return -1;
 
	}
 

	
 
	Logging::redirect_stderr();
 

	
 
	UserManager userManager(&transport, &userRegistry, storageBackend);
 
	DiscoItemsResponder discoItemsResponder(&transport);
 
	discoItemsResponder.start();
 

	
 
	UserManager userManager(&transport, &userRegistry, &discoItemsResponder, storageBackend);
 
	userManager_ = &userManager;
 

	
 
	UserRegistration *userRegistration = NULL;
 
	UsersReconnecter *usersReconnecter = NULL;
 
	if (storageBackend) {
 
		userRegistration = new UserRegistration(&transport, &userManager, storageBackend);
 
		userRegistration->start();
 

	
 
		usersReconnecter = new UsersReconnecter(&transport, storageBackend);
 
	}
 

	
 
	FileTransferManager ftManager(&transport, &userManager);
 

	
 
	DiscoItemsResponder discoItemsResponder(&transport);
 
	discoItemsResponder.start();
 

	
 
	NetworkPluginServer plugin(&transport, &config, &userManager, &ftManager, &discoItemsResponder);
 

	
 
	AdminInterface adminInterface(&transport, &userManager, &plugin, storageBackend, userRegistration);
 
	plugin.setAdminInterface(&adminInterface);
 

	
 
	StatsResponder statsResponder(&transport, &userManager, &plugin, storageBackend);
 
	statsResponder.start();
 

	
 
	GatewayResponder gatewayResponder(transport.getIQRouter(), &userManager);
 
	gatewayResponder.start();
 

	
 
	AdHocManager adhocmanager(&transport, &discoItemsResponder, &userManager, storageBackend);
 
	adhocmanager.start();
 

	
 
	SettingsAdHocCommandFactory settings;
 
	adhocmanager.addAdHocCommand(&settings);
 

	
 
	eventLoop_ = &eventLoop;
 

	
 
	eventLoop.run();
 

	
 
	if (userRegistration) {
 
		userRegistration->stop();
 
		delete userRegistration;
 
	}
 

	
 
	if (usersReconnecter) {
 
		delete usersReconnecter;
 
	}
 

	
 
	delete storageBackend;
 
	delete factories;
 
	return 0;
 
}
spectrum/src/sample.cfg
Show inline comments
 
[service]
 
jid = localhost
 
password = secret
 
server = 127.0.0.1
 
port = 5222
 
server_mode = 1
 
backend_host=localhost
 
pidfile=./test.pid
 
# < this option doesn't work yet
 
#backend_port=10001
 
#admin_jid=admin@localhost
 
admin_password=test
 
#cert=server.pfx #patch to PKCS#12 certificate
 
#cert_password=test #password to that certificate if any
 
users_per_backend=10
 
backend=../..//backends/libpurple/spectrum2_libpurple_backend
 
#backend=../..//backends/libpurple/spectrum2_libpurple_backend
 
#backend=../../backends/twitter/spectrum2_twitter_backend
 
#backend=/home/hanzz/code/libtransport/backends/libpurple/spectrum2_communi_backend
 
backend=/home/hanzz/code/libtransport/backends/libcommuni/spectrum2_libcommuni_backend
 
protocol=prpl-icq
 
#protocol=prpl-msn
 
#protocol=any
 
#protocol=prpl-icq
 
working_dir=./
 
portfile=$jid.port
 
irc_server=irc.freenode.org
 

	
 
[backend]
 
#default_avatar=catmelonhead.jpg
 
#no_vcard_fetch=true
 

	
 
[logging]
 
#config=logging.cfg # log4cxx/log4j logging configuration file
 
#backend_config=/home/hanzz/code/libtransport/spectrum/src/backend-logging.cfg # log4cxx/log4j logging configuration file for backends
 

	
 
[database]
 
type=sqlite3 # or "none" without database backend
 
database=users.sqlite
 
prefix=twitter
 
#type = mysql # or "none" without database backend.......................................................................................................................
 
#database = test
 
#prefix=
 
#user=root
 
#password=yourrootsqlpassword
 
#encryption_key=hanzzik
src/buddy.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/buddy.h"
 
#include "transport/rostermanager.h"
 
#include "transport/user.h"
 
#include "transport/transport.h"
 
#include "transport/BlockPayload.h"
 
#include "transport/usermanager.h"
 
#include "transport/discoitemsresponder.h"
 

	
 
namespace Transport {
 

	
 
Buddy::Buddy(RosterManager *rosterManager, long id, BuddyFlag flags) : m_id(id), m_flags(flags), m_rosterManager(rosterManager),
 
	m_subscription(Ask) {
 
// 	m_rosterManager->setBuddy(this);
 
}
 

	
 
Buddy::~Buddy() {
 
// 	m_rosterManager->unsetBuddy(this);
 
}
 

	
 
void Buddy::generateJID() {
 
	m_jid = Swift::JID();
 
	m_jid = Swift::JID(getSafeName(), m_rosterManager->getUser()->getComponent()->getJID().toString(), "bot");
 
}
 

	
 
void Buddy::setID(long id) {
 
	m_id = id;
 
}
 

	
 
long Buddy::getID() {
 
	return m_id;
 
}
 

	
 
void Buddy::setFlags(BuddyFlag flags) {
 
	m_flags = flags;
 

	
 
	if (!getSafeName().empty()) {
 
		try {
 
			generateJID();
 
		} catch (...) {
 
		}
 
	}
 
}
 

	
 
BuddyFlag Buddy::getFlags() {
 
	return m_flags;
 
}
 

	
 
const Swift::JID &Buddy::getJID() {
 
	if (!m_jid.isValid() || m_jid.getNode().empty()) {
 
		generateJID();
 
	}
 
	return m_jid;
 
}
 

	
 
void Buddy::setSubscription(Subscription subscription) {
 
	m_subscription = subscription;
 
}
 

	
 
Buddy::Subscription Buddy::getSubscription() {
 
	return m_subscription;
 
}
 

	
 
Swift::Presence::ref Buddy::generatePresenceStanza(int features, bool only_new) {
 
	std::string alias = getAlias();
 
	std::string name = getSafeName();
 

	
 
	Swift::StatusShow s;
 
	std::string statusMessage;
 
	if (!getStatus(s, statusMessage))
 
		return Swift::Presence::ref();
 

	
 
	if (m_jid.getNode().empty()) {
 
		generateJID();
 
	}
 

	
 
	Swift::Presence::ref presence = Swift::Presence::create();
 
 	presence->setFrom(m_jid);
 
	presence->setTo(m_rosterManager->getUser()->getJID().toBare());
 
	presence->setType(Swift::Presence::Available);
 

	
 
	if (!statusMessage.empty())
 
		presence->setStatus(statusMessage);
 

	
 
	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(m_rosterManager->getUser()->getComponent()->getBuddyCapsInfo())));
 
		presence->addPayload(boost::shared_ptr<Swift::Payload>(new Swift::CapsInfo(m_rosterManager->getUser()->getUserManager()->getDiscoResponder()->getBuddyCapsInfo())));
 

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

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

	
 
	return presence;
 
}
 

	
 
std::string Buddy::getSafeName() {
 
	if (m_jid.isValid()) {
 
		return m_jid.getNode();
 
	}
 
	std::string name = getName();
 
// 	Transport::instance()->protocol()->prepareUsername(name, purple_buddy_get_account(m_buddy));
 
	if (getFlags() & BUDDY_JID_ESCAPING) {
 
		name = Swift::JID::getEscapedNode(name);
 
	}
 
	else {
 
		if (name.find_last_of("@") != std::string::npos) {
 
			name.replace(name.find_last_of("@"), 1, "%"); // OK
 
		}
 
	}
 
// 	if (name.empty()) {
 
// 		Log("SpectrumBuddy::getSafeName", "Name is EMPTY! Previous was " << getName() << ".");
 
// 	}
 
	return name;
 
}
 

	
 
void Buddy::handleBuddyChanged() {
 
	Swift::Presence::ref presence = generatePresenceStanza(255);
 
	if (presence) {
 
		m_rosterManager->getUser()->getComponent()->getStanzaChannel()->sendPresence(presence);
 
	}
 
}
 

	
 
void Buddy::handleVCardReceived(const std::string &id, Swift::VCard::ref vcard) {
 
	boost::shared_ptr<Swift::GenericRequest<Swift::VCard> > request(new Swift::GenericRequest<Swift::VCard>(Swift::IQ::Result, m_rosterManager->getUser()->getJID(), vcard, m_rosterManager->getUser()->getComponent()->getIQRouter()));
 
	request->send();
 
}
 

	
 
std::string Buddy::JIDToLegacyName(const Swift::JID &jid) {
 
	std::string name;
 
	if (jid.getUnescapedNode() == jid.getNode()) {
 
		name = jid.getNode();
 
		if (name.find_last_of("%") != std::string::npos) {
 
			name.replace(name.find_last_of("%"), 1, "@"); // OK
 
		}
 
	}
 
	else {
 
		name = jid.getUnescapedNode();
 
		// Psi sucks...
 
// 		if (name.find_last_of("\\40") != std::string::npos) {
 
// 			name.replace(name.find_last_of("\\40"), 1, "@"); // OK
 
// 		}
 
	}
 
	return name;
 
}
 

	
 
BuddyFlag Buddy::buddyFlagsFromJID(const Swift::JID &jid) {
 
	if (jid.getUnescapedNode() == jid.getNode()) {
 
		return BUDDY_NO_FLAG;
 
	}
 
	return BUDDY_JID_ESCAPING;
 
}
 

	
 
}
src/config.cpp
Show inline comments
 
@@ -4,192 +4,193 @@
 
 * 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/config.h"
 
#include <fstream>
 
#ifdef _WIN32
 
#include <direct.h>
 
#define getcwd _getcwd
 
#include <windows.h>
 
#ifdef _MSC_VER
 
#define PATH_MAX MAX_PATH
 
#endif
 
#endif
 

	
 
#include "iostream"
 
#include "boost/version.hpp"
 
#include "boost/algorithm/string.hpp"
 

	
 
#define BOOST_MAJOR_VERSION BOOST_VERSION / 100000
 
#define BOOST_MINOR_VERSION BOOST_VERSION / 100 % 1000
 

	
 
using namespace boost::program_options;
 

	
 
namespace Transport {
 
static int getRandomPort(const std::string &s) {
 
	unsigned long r = 0;
 
	BOOST_FOREACH(char c, s) {
 
		r += (int) c;
 
	}
 
	srand(time(NULL) + r);
 
	return 30000 + rand() % 10000;
 
}
 

	
 
bool Config::load(const std::string &configfile, boost::program_options::options_description &opts, const std::string &jid) {
 
	std::ifstream ifs(configfile.c_str());
 
	if (!ifs.is_open())
 
		return false;
 

	
 
	m_file = configfile;
 
	m_jid = jid;
 
	bool ret = load(ifs, opts, jid);
 
	ifs.close();
 
#ifndef WIN32
 
	char path[PATH_MAX] = "";
 
	if (m_file.find_first_of("/") != 0) {
 
		getcwd(path, PATH_MAX);
 
		m_file = std::string(path) + "/" + m_file;
 
	}
 
#endif
 

	
 
	return ret;
 
}
 

	
 
bool Config::load(std::istream &ifs, boost::program_options::options_description &opts, const std::string &_jid) {
 
	m_unregistered.clear();
 
	opts.add_options()
 
		("service.jid", value<std::string>()->default_value(""), "Transport Jabber ID")
 
		("service.server", value<std::string>()->default_value(""), "Server to connect to")
 
		("service.password", value<std::string>()->default_value(""), "Password used to auth the server")
 
		("service.port", value<int>()->default_value(0), "Port the server is listening on")
 
		("service.user", value<std::string>()->default_value(""), "The name of user Spectrum runs as.")
 
		("service.group", value<std::string>()->default_value(""), "The name of group Spectrum runs as.")
 
		("service.backend", value<std::string>()->default_value("libpurple_backend"), "Backend")
 
		("service.protocol", value<std::string>()->default_value(""), "Protocol")
 
		("service.pidfile", value<std::string>()->default_value("/var/run/spectrum2/$jid.pid"), "Full path to pid file")
 
		("service.portfile", value<std::string>()->default_value("/var/run/spectrum2/$jid.port"), "File to store backend_port to. It's used by spectrum2_manager.")
 
		("service.working_dir", value<std::string>()->default_value("/var/lib/spectrum2/$jid"), "Working dir")
 
		("service.allowed_servers", value<std::vector<std::string> >()->multitoken(), "Only users from these servers can connect")
 
		("service.server_mode", value<bool>()->default_value(false), "True if Spectrum should behave as server")
 
		("service.users_per_backend", value<int>()->default_value(100), "Number of users per one legacy network backend")
 
		("service.backend_host", value<std::string>()->default_value("localhost"), "Host to bind backend server to")
 
		("service.backend_port", value<std::string>()->default_value("0"), "Port to bind backend server to")
 
		("service.cert", value<std::string>()->default_value(""), "PKCS#12 Certificate.")
 
		("service.cert_password", value<std::string>()->default_value(""), "PKCS#12 Certificate password.")
 
		("service.admin_jid", value<std::vector<std::string> >()->multitoken(), "Administrator jid.")
 
		("service.admin_password", value<std::string>()->default_value(""), "Administrator password.")
 
		("service.reuse_old_backends", value<bool>()->default_value(true), "True if Spectrum should use old backends which were full in the past.")
 
		("service.idle_reconnect_time", value<int>()->default_value(0), "Time in seconds after which idle users are reconnected to let their backend die.")
 
		("service.memory_collector_time", value<int>()->default_value(0), "Time in seconds after which backend with most memory is set to die.")
 
		("service.more_resources", value<bool>()->default_value(false), "Allow more resources to be connected in server mode at the same time.")
 
		("service.enable_privacy_lists", value<bool>()->default_value(true), "")
 
		("service.enable_xhtml", value<bool>()->default_value(true), "")
 
		("service.max_room_list_size", value<int>()->default_value(100), "")
 
		("vhosts.vhost", value<std::vector<std::string> >()->multitoken(), "")
 
		("identity.name", value<std::string>()->default_value("Spectrum 2 Transport"), "Name showed in service discovery.")
 
		("identity.category", value<std::string>()->default_value("gateway"), "Disco#info identity category. 'gateway' by default.")
 
		("identity.type", value<std::string>()->default_value(""), "Type of transport ('icq','msn','gg','irc', ...)")
 
		("registration.enable_public_registration", value<bool>()->default_value(true), "True if users should be able to register.")
 
		("registration.language", value<std::string>()->default_value("en"), "Default language for registration form")
 
		("registration.instructions", value<std::string>()->default_value("Enter your legacy network username and password."), "Instructions showed to user in registration form")
 
		("registration.username_label", value<std::string>()->default_value("Legacy network username:"), "Label for username field")
 
		("registration.username_mask", value<std::string>()->default_value(""), "Username mask")
 
		("registration.allowed_usernames", value<std::string>()->default_value(""), "Allowed usernames")
 
		("registration.auto_register", value<bool>()->default_value(false), "Register new user automatically when the presence arrives.")
 
		("registration.encoding", value<std::string>()->default_value("utf8"), "Default encoding in registration form")
 
		("registration.require_local_account", value<bool>()->default_value(false), "True if users have to have a local account to register to this transport from remote servers.")
 
		("registration.local_username_label", value<std::string>()->default_value("Local username:"), "Label for local usernme field")
 
		("registration.local_account_server", value<std::string>()->default_value("localhost"), "The server on which the local accounts will be checked for validity")
 
		("registration.local_account_server_timeout", value<int>()->default_value(10000), "Timeout when checking local user on local_account_server (msecs)")
 
		("gateway_responder.prompt", value<std::string>()->default_value("Contact ID"), "Value of <prompt> </promt> field")
 
		("gateway_responder.label", value<std::string>()->default_value("Enter legacy network contact ID."), "Label for add contact ID field")
 
		("database.type", value<std::string>()->default_value("none"), "Database type.")
 
		("database.database", value<std::string>()->default_value("/var/lib/spectrum2/$jid/database.sql"), "Database used to store data")
 
		("database.server", value<std::string>()->default_value("localhost"), "Database server.")
 
		("database.user", value<std::string>()->default_value(""), "Database user.")
 
		("database.password", value<std::string>()->default_value(""), "Database Password.")
 
		("database.port", value<int>()->default_value(0), "Database port.")
 
		("database.prefix", value<std::string>()->default_value(""), "Prefix of tables in database")
 
		("database.encryption_key", value<std::string>()->default_value(""), "Encryption key.")
 
		("logging.config", value<std::string>()->default_value(""), "Path to log4cxx config file which is used for Spectrum 2 instance")
 
		("logging.backend_config", value<std::string>()->default_value(""), "Path to log4cxx config file which is used for backends")
 
		("backend.default_avatar", value<std::string>()->default_value(""), "Full path to default avatar")
 
		("backend.avatars_directory", value<std::string>()->default_value(""), "Path to directory with avatars")
 
		("backend.no_vcard_fetch", value<bool>()->default_value(false), "True if VCards for buddies should not be fetched. Only avatars will be forwarded.")
 
		("proxy.server", value<std::string>()->default_value("localhost"), "Proxy IP.")
 
		("proxy.user", value<std::string>()->default_value(""), "Proxy user.")
 
		("proxy.password", value<std::string>()->default_value(""), "Proxy Password.")
 
		("proxy.port", value<int>()->default_value(0), "Proxy port.")
 

	
 
	;
 

	
 
	parsed_options parsed = parse_config_file(ifs, opts, true);
 

	
 
	bool found_working = false;
 
	bool found_pidfile = false;
 
	bool found_portfile = false;
 
	bool found_backend_port = false;
 
	bool found_database = false;
 
	std::string jid = "";
 
	BOOST_FOREACH(option &opt, parsed.options) {
 
		if (opt.string_key == "service.jid") {
 
			if (_jid.empty()) {
 
				jid = opt.value[0];
 
			}
 
			else {
 
				opt.value[0] = _jid;
 
				jid = _jid;
 
			}
 
		}
 
		else if (opt.string_key == "service.backend_port") {
 
			found_backend_port = true;
 
			if (opt.value[0] == "0") {
 
				opt.value[0] = boost::lexical_cast<std::string>(getRandomPort(_jid.empty() ? jid : _jid));
 
			}
 
		}
 
		else if (opt.string_key == "service.working_dir") {
 
			found_working = true;
 
		}
 
		else if (opt.string_key == "service.pidfile") {
 
			found_pidfile = true;
 
		}
 
		else if (opt.string_key == "service.portfile") {
 
			found_portfile = true;
 
		}
 
		else if (opt.string_key == "database.database") {
 
			found_database = true;
 
		}
 
	}
 

	
 
	if (!found_working) {
 
		std::vector<std::string> value;
 
		value.push_back("/var/lib/spectrum2/$jid");
 
		parsed.options.push_back(boost::program_options::basic_option<char>("service.working_dir", value));
 
	}
 
	if (!found_pidfile) {
 
		std::vector<std::string> value;
 
		value.push_back("/var/run/spectrum2/$jid.pid");
 
		parsed.options.push_back(boost::program_options::basic_option<char>("service.pidfile", value));
 
	}
 
	if (!found_portfile) {
 
		std::vector<std::string> value;
 
		value.push_back("/var/run/spectrum2/$jid.port");
 
		parsed.options.push_back(boost::program_options::basic_option<char>("service.portfile", value));
 
	}
 
	if (!found_backend_port) {
 
		std::vector<std::string> value;
 
		std::string p = boost::lexical_cast<std::string>(getRandomPort(_jid.empty() ? jid : _jid));
 
		value.push_back(p);
 
		parsed.options.push_back(boost::program_options::basic_option<char>("service.backend_port", value));
src/discoinforesponder.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 "discoinforesponder.h"
 

	
 
#include <iostream>
 
#include <boost/bind.hpp>
 
#include <boost/algorithm/string.hpp>
 
#include "Swiften/Disco/DiscoInfoResponder.h"
 
#include "Swiften/Queries/IQRouter.h"
 
#include "Swiften/Elements/DiscoInfo.h"
 
#include "Swiften/Swiften.h"
 
#include "transport/config.h"
 
#include "transport/logging.h"
 

	
 
using namespace Swift;
 
using namespace boost;
 

	
 
DEFINE_LOGGER(logger, "DiscoInfoResponder");
 

	
 
namespace Transport {
 

	
 
DiscoInfoResponder::DiscoInfoResponder(Swift::IQRouter *router, Config *config) : Swift::GetResponder<DiscoInfo>(router) {
 
	m_config = config;
 
	m_transportInfo.addIdentity(DiscoInfo::Identity(CONFIG_STRING(m_config, "identity.name"),
 
													CONFIG_STRING(m_config, "identity.category"),
 
													CONFIG_STRING(m_config, "identity.type")));
 

	
 
	m_buddyInfo.addIdentity(DiscoInfo::Identity(CONFIG_STRING(m_config, "identity.name"), "client", "pc"));
 
	std::list<std::string> features;
 
	features.push_back("jabber:iq:register");
 
	features.push_back("jabber:iq:gateway");
 
	features.push_back("jabber:iq:private");
 
	features.push_back("http://jabber.org/protocol/disco#info");
 
	features.push_back("http://jabber.org/protocol/commands");
 
	setTransportFeatures(features);
 

	
 
	features.clear();
 
	features.push_back("http://jabber.org/protocol/disco#items");
 
	features.push_back("http://jabber.org/protocol/disco#info");
 
	features.push_back("http://jabber.org/protocol/chatstates");
 
	features.push_back("http://jabber.org/protocol/xhtml-im");
 
	setBuddyFeatures(features);
 
}
 

	
 
DiscoInfoResponder::~DiscoInfoResponder() {
 
	
 
}
 

	
 
void DiscoInfoResponder::setTransportFeatures(std::list<std::string> &features) {
 
	for (std::list<std::string>::iterator it = features.begin(); it != features.end(); it++) {
 
		if (!m_transportInfo.hasFeature(*it)) {
 
			m_transportInfo.addFeature(*it);
 
		}
 
	}
 
}
 

	
 
void DiscoInfoResponder::setBuddyFeatures(std::list<std::string> &f) {
 
	for (std::list<std::string>::iterator it = f.begin(); it != f.end(); it++) {
 
		if (!m_buddyInfo.hasFeature(*it)) {
 
			m_buddyInfo.addFeature(*it);
 
		}
 
	}
 

	
 
	CapsInfoGenerator caps("spectrum");
 
	m_capsInfo = caps.generateCapsInfo(m_buddyInfo);
 
	onBuddyCapsInfoChanged(m_capsInfo);
 
}
 

	
 
void DiscoInfoResponder::addRoom(const std::string &jid, const std::string &name) {
 
	std::string j = jid;
 
	boost::algorithm::to_lower(j);
 
	m_rooms[j] = name;
 
}
 

	
 
void DiscoInfoResponder::clearRooms() {
 
	m_rooms.clear();
 
}
 

	
 
bool DiscoInfoResponder::handleGetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<Swift::DiscoInfo> info) {
 
	if (!info->getNode().empty()) {
 
		sendError(from, id, ErrorPayload::ItemNotFound, ErrorPayload::Cancel);
 
		return true;
 
	}
 

	
 
	// presence for transport
 

	
 
	// disco#info for transport
 
	if (to.getNode().empty()) {
 
		boost::shared_ptr<DiscoInfo> res(new DiscoInfo(m_transportInfo));
 
		res->setNode(info->getNode());
 
		sendResponse(from, id, res);
 
	}
 
	// presence for buddy
 
	// disco#info for room
 
	else if (m_rooms.find(to.toBare().toString()) != m_rooms.end()) {
 
		boost::shared_ptr<DiscoInfo> res(new DiscoInfo());
 
		res->addIdentity(DiscoInfo::Identity(m_rooms[to.toBare().toString()], "conference", "text"));
 
		res->setNode(info->getNode());
 
		sendResponse(from, to, id, res);
 
	}
 
	// disco#info for buddy
 
	else {
 
		boost::shared_ptr<DiscoInfo> res(new DiscoInfo(m_buddyInfo));
 
		res->setNode(info->getNode());
 
		sendResponse(from, to, id, res);
 
	}
 
	return true;
 
}
 

	
 
}
src/discoinforesponder.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/Queries/GetResponder.h"
 
#include "Swiften/Elements/DiscoInfo.h"
 
#include "Swiften/Elements/CapsInfo.h"
 

	
 
namespace Transport {
 

	
 
class Config;
 

	
 
class DiscoInfoResponder : public Swift::GetResponder<Swift::DiscoInfo> {
 
	public:
 
		DiscoInfoResponder(Swift::IQRouter *router, Config *config);
 
		~DiscoInfoResponder();
 

	
 
		void setTransportFeatures(std::list<std::string> &features);
 
		void setBuddyFeatures(std::list<std::string> &features);
 

	
 
		void addRoom(const std::string &jid, const std::string &name);
 
		void clearRooms();
 

	
 
		boost::signal<void (const Swift::CapsInfo &capsInfo)> onBuddyCapsInfoChanged;
 

	
 
		Swift::CapsInfo &getBuddyCapsInfo() {
 
				return m_capsInfo;
 
		}
 

	
 
	private:
 
		virtual bool handleGetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<Swift::DiscoInfo> payload);
 

	
 
		Swift::DiscoInfo m_transportInfo;
 
		Swift::DiscoInfo m_buddyInfo;
 
		Config *m_config;
 
		Swift::CapsInfo m_capsInfo;
 
		std::map<std::string, std::string> m_rooms;
 
};
 

	
 
}
 
\ No newline at end of file
src/discoitemsresponder.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/discoitemsresponder.h"
 

	
 
#include <iostream>
 
#include <boost/bind.hpp>
 
#include "Swiften/Queries/IQRouter.h"
 
#include "Swiften/Swiften.h"
 
#include "transport/transport.h"
 
#include "transport/logging.h"
 
#include "discoinforesponder.h"
 

	
 
using namespace Swift;
 
using namespace boost;
 

	
 
namespace Transport {
 

	
 
DEFINE_LOGGER(logger, "DiscoItemsResponder");
 

	
 
DiscoItemsResponder::DiscoItemsResponder(Component *component) : Swift::GetResponder<DiscoItems>(component->getIQRouter()) {
 
	m_component = component;
 
	m_commands = boost::shared_ptr<DiscoItems>(new DiscoItems());
 
	m_commands->setNode("http://jabber.org/protocol/commands");
 

	
 
	m_rooms = boost::shared_ptr<DiscoItems>(new DiscoItems());
 
	m_discoInfoResponder = new DiscoInfoResponder(component->getIQRouter(), component->getConfig());
 
	m_discoInfoResponder->start();
 
}
 

	
 
DiscoItemsResponder::~DiscoItemsResponder() {
 
	>
 
	delete m_discoInfoResponder;
 
}
 

	
 
void DiscoItemsResponder::addAdHocCommand(const std::string &node, const std::string &name) {
 
	m_commands->addItem(DiscoItems::Item(name, m_component->getJID(), node));
 
}
 

	
 
void DiscoItemsResponder::addRoom(const std::string &node, const std::string &name) {
 
	m_rooms->addItem(DiscoItems::Item(name, m_component->getJID(), node));
 
	if (m_rooms->getItems().size() > CONFIG_INT(m_component->getConfig(), "service.max_room_list_size")) {
 
		return;
 
	}
 
	m_rooms->addItem(DiscoItems::Item(name, node));
 
	m_discoInfoResponder->addRoom(node, name);
 
}
 

	
 
void DiscoItemsResponder::clearRooms() {
 
	m_rooms = boost::shared_ptr<DiscoItems>(new DiscoItems());
 
	m_discoInfoResponder->clearRooms();
 
}
 

	
 
Swift::CapsInfo &DiscoItemsResponder::getBuddyCapsInfo() {
 
	return m_discoInfoResponder->getBuddyCapsInfo();
 
}
 

	
 

	
 
bool DiscoItemsResponder::handleGetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<Swift::DiscoItems> info) {
 
	LOG4CXX_INFO(logger, "get request received with node " << info->getNode());
 
	if (info->getNode() == "http://jabber.org/protocol/commands") {
 
		sendResponse(from, id, m_commands);
 
	}
 
	else if (to.getNode().empty()) {
 
		sendResponse(from, id, m_rooms);
 
	}
 
	else {
 
		sendResponse(from, id, boost::shared_ptr<DiscoItems>(new DiscoItems()));
 
	}
 
	return true;
 
}
 

	
 
}
src/networkpluginserver.cpp
Show inline comments
 
@@ -768,193 +768,193 @@ void NetworkPluginServer::handleFTDataPayload(Backend *b, const std::string &dat
 
}
 

	
 
void NetworkPluginServer::handleFTDataNeeded(Backend *b, unsigned long ftid) {
 
	pbnetwork::FileTransferData f;
 
	f.set_ftid(ftid);
 
	f.set_data("");
 

	
 
	std::string message;
 
	f.SerializeToString(&message);
 

	
 
	WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_FT_CONTINUE);
 

	
 
	send(b->connection, message);
 
}
 

	
 
void NetworkPluginServer::handlePongReceived(Backend *c) {
 
	// This could be first PONG from the backend
 
	if (c->pongReceived == -1) {
 
		// Backend is fully ready to handle requests
 
		c->willDie = false;
 

	
 
		if (m_clients.size() == 1) {
 
			// first backend connected, start the server, we're ready.
 
			m_component->start();
 
		}
 

	
 
		// some users are in queue waiting for this backend
 
		while(!m_waitingUsers.empty()) {
 
			// There's no new backend, so stop associating users and wait for new backend,
 
			// which has been already spawned in getFreeClient() call.
 
			if (getFreeClient() == NULL)
 
				break;
 

	
 
			User *u = m_waitingUsers.front();
 
			m_waitingUsers.pop_front();
 

	
 
			LOG4CXX_INFO(logger, "Associating " << u->getJID().toString() << " with this backend");
 

	
 
			// associate backend with user
 
			handleUserCreated(u);
 

	
 
			// connect user if it's ready
 
			if (u->isReadyToConnect()) {
 
				handleUserReadyToConnect(u);
 
			}
 
		}
 
	}
 

	
 
	c->pongReceived = true;
 
}
 

	
 
void NetworkPluginServer::handleQueryPayload(Backend *b, const std::string &data) {
 
	pbnetwork::BackendConfig payload;
 
	if (payload.ParseFromString(data) == false) {
 
		// TODO: ERROR
 
		return;
 
	}
 

	
 
	if (!m_adminInterface) {
 
		return;
 
	}
 

	
 
	boost::shared_ptr<Swift::Message> msg(new Swift::Message());
 
	msg->setBody(payload.config());
 
	m_adminInterface->handleQuery(msg);
 

	
 
	pbnetwork::BackendConfig response;
 
	response.set_config(msg->getBody());
 

	
 
	std::string message;
 
	response.SerializeToString(&message);
 

	
 
	WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_QUERY);
 

	
 
	send(b->connection, message);
 
}
 

	
 
void NetworkPluginServer::handleBackendConfigPayload(const std::string &data) {
 
	pbnetwork::BackendConfig payload;
 
	if (payload.ParseFromString(data) == false) {
 
		// TODO: ERROR
 
		return;
 
	}
 

	
 
	m_config->updateBackendConfig(payload.config());
 
}
 

	
 
void NetworkPluginServer::handleRoomListPayload(const std::string &data) {
 
	pbnetwork::RoomList payload;
 
	if (payload.ParseFromString(data) == false) {
 
		// TODO: ERROR
 
		return;
 
	}
 

	
 
	m_discoItemsResponder->clearRooms();
 
	for (int i = 0; i < payload.room_size() && i < payload.name_size(); i++) {
 
		m_discoItemsResponder->addRoom(payload.room(i), payload.name(i));
 
		m_discoItemsResponder->addRoom(Swift::JID::getEscapedNode(payload.room(i)) + "@" + m_component->getJID().toString(), payload.name(i));
 
	}
 
}
 

	
 
void NetworkPluginServer::handleDataRead(Backend *c, boost::shared_ptr<Swift::SafeByteArray> data) {
 
	// Append data to buffer
 
	c->data.insert(c->data.end(), data->begin(), data->end());
 

	
 
	// Parse data while there are some
 
	while (c->data.size() != 0) {
 
		// expected_size of wrapper message
 
		unsigned int expected_size;
 

	
 
		// if data is >= 4, we have whole header and we can
 
		// read expected_size.
 
		if (c->data.size() >= 4) {
 
			expected_size = *((unsigned int*) &c->data[0]);
 
			expected_size = ntohl(expected_size);
 
			// If we don't have whole wrapper message, wait for next
 
			// handleDataRead call.
 
			if (c->data.size() - 4 < expected_size)
 
				return;
 
		}
 
		else {
 
			return;
 
		}
 

	
 
		// Parse wrapper message and erase it from buffer.
 
		pbnetwork::WrapperMessage wrapper;
 
		if (wrapper.ParseFromArray(&c->data[4], expected_size) == false) {
 
			std::cout << "PARSING ERROR " << expected_size << "\n";
 
			c->data.erase(c->data.begin(), c->data.begin() + 4 + expected_size);
 
			continue;
 
		}
 
		c->data.erase(c->data.begin(), c->data.begin() + 4 + expected_size);
 

	
 
		// Handle payload in wrapper message
 
		switch(wrapper.type()) {
 
			case pbnetwork::WrapperMessage_Type_TYPE_CONNECTED:
 
				handleConnectedPayload(wrapper.payload());
 
				break;
 
			case pbnetwork::WrapperMessage_Type_TYPE_DISCONNECTED:
 
				handleDisconnectedPayload(wrapper.payload());
 
				break;
 
			case pbnetwork::WrapperMessage_Type_TYPE_BUDDY_CHANGED:
 
				handleBuddyChangedPayload(wrapper.payload());
 
				break;
 
			case pbnetwork::WrapperMessage_Type_TYPE_CONV_MESSAGE:
 
				handleConvMessagePayload(wrapper.payload());
 
				break;
 
			case pbnetwork::WrapperMessage_Type_TYPE_ROOM_SUBJECT_CHANGED:
 
				handleConvMessagePayload(wrapper.payload(), true);
 
				break;
 
			case pbnetwork::WrapperMessage_Type_TYPE_PONG:
 
				handlePongReceived(c);
 
				break;
 
			case pbnetwork::WrapperMessage_Type_TYPE_PARTICIPANT_CHANGED:
 
				handleParticipantChangedPayload(wrapper.payload());
 
				break;
 
			case pbnetwork::WrapperMessage_Type_TYPE_ROOM_NICKNAME_CHANGED:
 
				handleRoomChangedPayload(wrapper.payload());
 
				break;
 
			case pbnetwork::WrapperMessage_Type_TYPE_VCARD:
 
				handleVCardPayload(wrapper.payload());
 
				break;
 
			case pbnetwork::WrapperMessage_Type_TYPE_BUDDY_TYPING:
 
				handleChatStatePayload(wrapper.payload(), Swift::ChatState::Composing);
 
				break;
 
			case pbnetwork::WrapperMessage_Type_TYPE_BUDDY_TYPED:
 
				handleChatStatePayload(wrapper.payload(), Swift::ChatState::Paused);
 
				break;
 
			case pbnetwork::WrapperMessage_Type_TYPE_BUDDY_STOPPED_TYPING:
 
				handleChatStatePayload(wrapper.payload(), Swift::ChatState::Active);
 
				break;
 
			case pbnetwork::WrapperMessage_Type_TYPE_AUTH_REQUEST:
 
				handleAuthorizationPayload(wrapper.payload());
 
				break;
 
			case pbnetwork::WrapperMessage_Type_TYPE_ATTENTION:
 
				handleAttentionPayload(wrapper.payload());
 
				break;
 
			case pbnetwork::WrapperMessage_Type_TYPE_STATS:
 
				handleStatsPayload(c, wrapper.payload());
 
				break;
 
			case pbnetwork::WrapperMessage_Type_TYPE_FT_START:
 
				handleFTStartPayload(wrapper.payload());
 
				break;
 
			case pbnetwork::WrapperMessage_Type_TYPE_FT_FINISH:
 
				handleFTFinishPayload(wrapper.payload());
 
				break;
 
			case pbnetwork::WrapperMessage_Type_TYPE_FT_DATA:
 
				handleFTDataPayload(c, wrapper.payload());
 
				break;
 
			case pbnetwork::WrapperMessage_Type_TYPE_BUDDY_REMOVED:
 
				handleBuddyRemovedPayload(wrapper.payload());
 
				break;
 
			case pbnetwork::WrapperMessage_Type_TYPE_QUERY:
 
				handleQueryPayload(c, wrapper.payload());
src/tests/basictest.cpp
Show inline comments
 
#include "basictest.h"
 
#include "transport/userregistry.h"
 
#include "transport/config.h"
 
#include "transport/storagebackend.h"
 
#include "transport/userregistration.h"
 
#include "transport/user.h"
 
#include "transport/transport.h"
 
#include "transport/conversation.h"
 
#include "transport/usermanager.h"
 
#include "transport/localbuddy.h"
 
#include <cppunit/TestFixture.h>
 
#include <cppunit/extensions/HelperMacros.h>
 
#include <Swiften/Swiften.h>
 
#include <Swiften/EventLoop/DummyEventLoop.h>
 
#include <Swiften/Server/Server.h>
 
#include <Swiften/Network/DummyNetworkFactories.h>
 
#include <Swiften/Network/DummyConnectionServer.h>
 
#include "Swiften/Server/ServerStanzaChannel.h"
 
#include "Swiften/Server/ServerFromClientSession.h"
 
#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h"
 

	
 
#include "Swiften/Serializer/GenericPayloadSerializer.h"
 

	
 
#include "../storageparser.h"
 
#include "Swiften/Parser/PayloadParsers/AttentionParser.h"
 
#include "Swiften/Serializer/PayloadSerializers/AttentionSerializer.h"
 
#include "Swiften/Parser/PayloadParsers/XHTMLIMParser.h"
 
#include "Swiften/Serializer/PayloadSerializers/XHTMLIMSerializer.h"
 
#include "Swiften/Parser/PayloadParsers/StatsParser.h"
 
#include "Swiften/Serializer/PayloadSerializers/StatsSerializer.h"
 
#include "Swiften/Parser/PayloadParsers/GatewayPayloadParser.h"
 
#include "Swiften/Serializer/PayloadSerializers/GatewayPayloadSerializer.h"
 
#include "Swiften/Serializer/PayloadSerializers/SpectrumErrorSerializer.h"
 
#include "Swiften/Parser/PayloadParsers/MUCPayloadParser.h"
 
#include "transport/BlockParser.h"
 
#include "transport/BlockSerializer.h"
 
#include "Swiften/Parser/PayloadParsers/InvisibleParser.h"
 
#include "Swiften/Serializer/PayloadSerializers/InvisibleSerializer.h"
 

	
 
using namespace Transport;
 

	
 
void BasicTest::setMeUp (void) {
 
	streamEnded = false;
 
	std::istringstream ifs("service.server_mode = 1\nservice.jid=localhost\nservice.more_resources=1\n");
 
	cfg = new Config();
 
	cfg->load(ifs);
 

	
 
	factory = new TestingFactory();
 

	
 
	storage = new TestingStorageBackend();
 

	
 
	loop = new Swift::DummyEventLoop();
 
	factories = new Swift::DummyNetworkFactories(loop);
 

	
 
	userRegistry = new UserRegistry(cfg, factories);
 

	
 
	component = new Component(loop, factories, cfg, factory, userRegistry);
 
	component->start();
 

	
 
	userManager = new UserManager(component, userRegistry, storage);
 
	itemsResponder = new DiscoItemsResponder(component);
 
	itemsResponder->start();
 

	
 
	userManager = new UserManager(component, userRegistry, itemsResponder, storage);
 

	
 
	userRegistration = new UserRegistration(component, userManager, storage);
 
	userRegistration->start();
 

	
 
	itemsResponder = new DiscoItemsResponder(component);
 
	itemsResponder->start();
 

	
 
	payloadSerializers = new Swift::FullPayloadSerializerCollection();
 
	payloadParserFactories = new Swift::FullPayloadParserFactoryCollection();
 

	
 
	payloadParserFactories->addFactory(new Swift::GenericPayloadParserFactory<StorageParser>("private", "jabber:iq:private"));
 
	payloadParserFactories->addFactory(new Swift::GenericPayloadParserFactory<Swift::AttentionParser>("attention", "urn:xmpp:attention:0"));
 
	payloadParserFactories->addFactory(new Swift::GenericPayloadParserFactory<Swift::XHTMLIMParser>("html", "http://jabber.org/protocol/xhtml-im"));
 
	payloadParserFactories->addFactory(new Swift::GenericPayloadParserFactory<Transport::BlockParser>("block", "urn:xmpp:block:0"));
 
	payloadParserFactories->addFactory(new Swift::GenericPayloadParserFactory<Swift::InvisibleParser>("invisible", "urn:xmpp:invisible:0"));
 
	payloadParserFactories->addFactory(new Swift::GenericPayloadParserFactory<Swift::StatsParser>("query", "http://jabber.org/protocol/stats"));
 
	payloadParserFactories->addFactory(new Swift::GenericPayloadParserFactory<Swift::GatewayPayloadParser>("query", "jabber:iq:gateway"));
 
	payloadParserFactories->addFactory(new Swift::GenericPayloadParserFactory<Swift::MUCPayloadParser>("x", "http://jabber.org/protocol/muc"));
 

	
 
	payloadSerializers->addSerializer(new Swift::AttentionSerializer());
 
	payloadSerializers->addSerializer(new Swift::XHTMLIMSerializer());
 
	payloadSerializers->addSerializer(new Transport::BlockSerializer());
 
	payloadSerializers->addSerializer(new Swift::InvisibleSerializer());
 
	payloadSerializers->addSerializer(new Swift::StatsSerializer());
 
	payloadSerializers->addSerializer(new Swift::SpectrumErrorSerializer());
 
	payloadSerializers->addSerializer(new Swift::GatewayPayloadSerializer());
 

	
 
	parser = new Swift::XMPPParser(this, payloadParserFactories, factories->getXMLParserFactory());
 
	parser2 = new Swift::XMPPParser(this, payloadParserFactories, factories->getXMLParserFactory());
 

	
 
	serverFromClientSession = boost::shared_ptr<Swift::ServerFromClientSession>(new Swift::ServerFromClientSession("id", factories->getConnectionFactory()->createConnection(),
 
			payloadParserFactories, payloadSerializers, userRegistry, factories->getXMLParserFactory(), Swift::JID("user@localhost/resource")));
 
	serverFromClientSession->startSession();
 

	
 
	serverFromClientSession->onDataWritten.connect(boost::bind(&BasicTest::handleDataReceived, this, _1));
 

	
 
	dynamic_cast<Swift::ServerStanzaChannel *>(component->getStanzaChannel())->addSession(serverFromClientSession);
 
	parser->parse("<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='localhost' version='1.0'>");
 
	parser2->parse("<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='localhost' version='1.0'>");
 
	received.clear();
 
	received2.clear();
 
	receivedData.clear();
 
	loop->processEvents();
 
}
 

	
 
void BasicTest::tearMeDown (void) {
 
	dynamic_cast<Swift::ServerStanzaChannel *>(component->getStanzaChannel())->removeSession(serverFromClientSession);
 
	if (serverFromClientSession2) {
 
		dynamic_cast<Swift::ServerStanzaChannel *>(component->getStanzaChannel())->removeSession(serverFromClientSession2);
 
		serverFromClientSession2.reset();
 
	}
 
	delete component;
 
	delete userRegistry;
 
	delete factories;
 
	delete factory;
 
	delete loop;
 
	delete cfg;
 
	delete parser;
 
	delete parser2;
 
	delete storage;
 
	delete userRegistration;
 
	delete itemsResponder;
 
	received.clear();
 
	received2.clear();
 
	receivedData.clear();
 
	receivedData2.clear();
 
}
 

	
 
void BasicTest::handleDataReceived(const Swift::SafeByteArray &data) {
 
// 	std::cout << safeByteArrayToString(data) << "\n";
 
	stream1_active = true;
 
	receivedData += safeByteArrayToString(data) + "\n";
 
	parser->parse(safeByteArrayToString(data));
 
}
 

	
 
void BasicTest::handleDataReceived2(const Swift::SafeByteArray &data) {
 
// 	std::cout << safeByteArrayToString(data) << "\n";
 
	stream1_active = false;
 
	receivedData2 += safeByteArrayToString(data) + "\n";
 
	parser2->parse(safeByteArrayToString(data));
 
}
 

	
 
void BasicTest::handleStreamStart(const Swift::ProtocolHeader&) {
 

	
 
}
 

	
 
void BasicTest::dumpReceived() {
 
	std::cout << "\nStream1:\n";
 
	std::cout << receivedData << "\n";
 
	std::cout << "Stream2:\n";
 
	std::cout << receivedData2 << "\n";
 
}
 

	
 
void BasicTest::handleElement(boost::shared_ptr<Swift::Element> element) {
 
	if (stream1_active) {
 
		received.push_back(element);
 
	}
 
	else {
 
		received2.push_back(element);
 
	}
 
}
 

	
 
void BasicTest::handleStreamEnd() {
src/tests/discoitemsresponder.cpp
Show inline comments
 
new file 100644
 
#include "transport/userregistry.h"
 
#include "transport/userregistration.h"
 
#include "transport/config.h"
 
#include "transport/storagebackend.h"
 
#include "transport/user.h"
 
#include "transport/transport.h"
 
#include "transport/conversation.h"
 
#include "transport/usermanager.h"
 
#include "transport/localbuddy.h"
 
#include "transport/settingsadhoccommand.h"
 
#include "transport/adhocmanager.h"
 
#include <cppunit/TestFixture.h>
 
#include <cppunit/extensions/HelperMacros.h>
 
#include <Swiften/Swiften.h>
 
#include <Swiften/EventLoop/DummyEventLoop.h>
 
#include <Swiften/Server/Server.h>
 
#include <Swiften/Network/DummyNetworkFactories.h>
 
#include <Swiften/Network/DummyConnectionServer.h>
 
#include "Swiften/Server/ServerStanzaChannel.h"
 
#include "Swiften/Server/ServerFromClientSession.h"
 
#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h"
 
#include "basictest.h"
 

	
 
using namespace Transport;
 

	
 
class DiscoItemsResponderTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
 
	CPPUNIT_TEST_SUITE(DiscoItemsResponderTest);
 
	CPPUNIT_TEST(roomList);
 
	CPPUNIT_TEST(roomInfo);
 
	CPPUNIT_TEST(clearRooms);
 
	CPPUNIT_TEST_SUITE_END();
 

	
 
	public:
 

	
 
		void setUp (void) {
 
			setMeUp();
 
		}
 

	
 
		void tearDown (void) {
 
			received.clear();
 
			tearMeDown();
 
		}
 

	
 
	void roomList() {
 
		itemsResponder->addRoom("#room@localhost", "#room");
 

	
 
		boost::shared_ptr<Swift::DiscoItems> payload(new Swift::DiscoItems());
 
		boost::shared_ptr<Swift::IQ> iq = Swift::IQ::createRequest(Swift::IQ::Get, Swift::JID("localhost"), "id", payload);
 
		iq->setFrom("user@localhost");
 
		injectIQ(iq);
 
		loop->processEvents();
 

	
 
		CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
 
		CPPUNIT_ASSERT(dynamic_cast<Swift::IQ *>(getStanza(received[0])));
 
		CPPUNIT_ASSERT_EQUAL(Swift::IQ::Result, dynamic_cast<Swift::IQ *>(getStanza(received[0]))->getType());
 
		CPPUNIT_ASSERT(getStanza(received[0])->getPayload<Swift::DiscoItems>());
 
		CPPUNIT_ASSERT_EQUAL(std::string("#room@localhost"), getStanza(received[0])->getPayload<Swift::DiscoItems>()->getItems()[0].getJID().toString());
 
		CPPUNIT_ASSERT_EQUAL(std::string("#room"), getStanza(received[0])->getPayload<Swift::DiscoItems>()->getItems()[0].getName());
 
	}
 

	
 
	void roomInfo() {
 
		itemsResponder->addRoom("#room@localhost", "#room");
 

	
 
		boost::shared_ptr<Swift::DiscoInfo> payload(new Swift::DiscoInfo());
 
		boost::shared_ptr<Swift::IQ> iq = Swift::IQ::createRequest(Swift::IQ::Get, Swift::JID("localhost"), "id", payload);
 
		iq->setFrom("user@localhost");
 
		iq->setTo("#room@localhost");
 
		injectIQ(iq);
 
		loop->processEvents();
 

	
 
		dumpReceived();
 
		CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
 
		CPPUNIT_ASSERT(dynamic_cast<Swift::IQ *>(getStanza(received[0])));
 
		CPPUNIT_ASSERT_EQUAL(Swift::IQ::Result, dynamic_cast<Swift::IQ *>(getStanza(received[0]))->getType());
 
		CPPUNIT_ASSERT(getStanza(received[0])->getPayload<Swift::DiscoInfo>());
 
		CPPUNIT_ASSERT_EQUAL(std::string("#room"), getStanza(received[0])->getPayload<Swift::DiscoInfo>()->getIdentities()[0].getName());
 
		CPPUNIT_ASSERT_EQUAL(std::string("conference"), getStanza(received[0])->getPayload<Swift::DiscoInfo>()->getIdentities()[0].getCategory());
 
		CPPUNIT_ASSERT_EQUAL(std::string("text"), getStanza(received[0])->getPayload<Swift::DiscoInfo>()->getIdentities()[0].getType());
 
	}
 

	
 
	void clearRooms() {
 
		itemsResponder->addRoom("#room@localhost", "#room");
 
		itemsResponder->clearRooms();
 

	
 
		boost::shared_ptr<Swift::DiscoItems> payload(new Swift::DiscoItems());
 
		boost::shared_ptr<Swift::IQ> iq = Swift::IQ::createRequest(Swift::IQ::Get, Swift::JID("localhost"), "id", payload);
 
		iq->setFrom("user@localhost");
 
		injectIQ(iq);
 
		loop->processEvents();
 

	
 
		CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
 
		CPPUNIT_ASSERT(dynamic_cast<Swift::IQ *>(getStanza(received[0])));
 
		CPPUNIT_ASSERT_EQUAL(Swift::IQ::Result, dynamic_cast<Swift::IQ *>(getStanza(received[0]))->getType());
 
		CPPUNIT_ASSERT(getStanza(received[0])->getPayload<Swift::DiscoItems>());
 
		CPPUNIT_ASSERT(getStanza(received[0])->getPayload<Swift::DiscoItems>()->getItems().empty());
 
	}
 

	
 
};
 

	
 
CPPUNIT_TEST_SUITE_REGISTRATION (DiscoItemsResponderTest);
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 <boost/smart_ptr/make_shared.hpp>
 
#include <boost/algorithm/string/predicate.hpp>
 
#include "transport/storagebackend.h"
 
#include "transport/factory.h"
 
#include "transport/userregistry.h"
 
#include "transport/logging.h"
 
#include "discoinforesponder.h"
 
#include "storageparser.h"
 
#ifdef _WIN32
 
#include <Swiften/TLS/CAPICertificate.h>
 
#include "Swiften/TLS/Schannel/SchannelServerContext.h"
 
#include "Swiften/TLS/Schannel/SchannelServerContextFactory.h"
 
#else
 
#include "Swiften/TLS/PKCS12Certificate.h"
 
#include "Swiften/TLS/CertificateWithKey.h"
 
#include "Swiften/TLS/OpenSSL/OpenSSLServerContext.h"
 
#include "Swiften/TLS/OpenSSL/OpenSSLServerContextFactory.h"
 
#endif
 
#include "Swiften/Parser/PayloadParsers/AttentionParser.h"
 
#include "Swiften/Serializer/PayloadSerializers/AttentionSerializer.h"
 
#include "Swiften/Parser/PayloadParsers/XHTMLIMParser.h"
 
#include "Swiften/Serializer/PayloadSerializers/XHTMLIMSerializer.h"
 
#include "Swiften/Parser/PayloadParsers/StatsParser.h"
 
#include "Swiften/Serializer/PayloadSerializers/StatsSerializer.h"
 
#include "Swiften/Parser/PayloadParsers/GatewayPayloadParser.h"
 
#include "Swiften/Serializer/PayloadSerializers/GatewayPayloadSerializer.h"
 
#include "Swiften/Serializer/PayloadSerializers/SpectrumErrorSerializer.h"
 
#include "Swiften/Parser/PayloadParsers/MUCPayloadParser.h"
 
#include "transport/BlockParser.h"
 
#include "transport/BlockSerializer.h"
 
#include "Swiften/Parser/PayloadParsers/InvisibleParser.h"
 
#include "Swiften/Serializer/PayloadSerializers/InvisibleSerializer.h"
 
#include "Swiften/Swiften.h"
 

	
 
using namespace Swift;
 
using namespace boost;
 

	
 
namespace Transport {
 
	
 
DEFINE_LOGGER(logger, "Component");
 
DEFINE_LOGGER(logger_xml, "Component.XML");
 

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

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

	
 
	m_factories = factories;
 

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

	
 
	if (CONFIG_BOOL(m_config, "service.server_mode")) {
 
		LOG4CXX_INFO(logger, "Creating component in server mode on port " << CONFIG_INT(m_config, "service.port"));
 
		m_server = new Swift::Server(loop, m_factories, m_userRegistry, m_jid, CONFIG_INT(m_config, "service.port"));
 
		if (!CONFIG_STRING(m_config, "service.cert").empty()) {
 
#ifndef _WIN32
 
//TODO: fix
 
			LOG4CXX_INFO(logger, "Using PKCS#12 certificate " << CONFIG_STRING(m_config, "service.cert"));
 
			LOG4CXX_INFO(logger, "SSLv23_server_method used.");
 
			TLSServerContextFactory *f = new OpenSSLServerContextFactory();
 
			CertificateWithKey::ref certificate = boost::make_shared<PKCS12Certificate>(CONFIG_STRING(m_config, "service.cert"), createSafeByteArray(CONFIG_STRING(m_config, "service.cert_password")));
 
			m_server->addTLSEncryption(f, certificate);
 
#endif
 
			
 
		}
 
		else {
 
			LOG4CXX_WARN(logger, "No PKCS#12 certificate used. TLS is disabled.");
 
		}
 
// 		m_server->start();
 
		m_stanzaChannel = m_server->getStanzaChannel();
 
		m_iqRouter = m_server->getIQRouter();
 

	
 
		m_server->addPayloadParserFactory(new GenericPayloadParserFactory<StorageParser>("private", "jabber:iq:private"));
 
		m_server->addPayloadParserFactory(new GenericPayloadParserFactory<Swift::AttentionParser>("attention", "urn:xmpp:attention:0"));
 
		m_server->addPayloadParserFactory(new GenericPayloadParserFactory<Swift::XHTMLIMParser>("html", "http://jabber.org/protocol/xhtml-im"));
 
		m_server->addPayloadParserFactory(new GenericPayloadParserFactory<Transport::BlockParser>("block", "urn:xmpp:block:0"));
 
		m_server->addPayloadParserFactory(new GenericPayloadParserFactory<Swift::InvisibleParser>("invisible", "urn:xmpp:invisible:0"));
 
		m_server->addPayloadParserFactory(new GenericPayloadParserFactory<Swift::StatsParser>("query", "http://jabber.org/protocol/stats"));
 
		m_server->addPayloadParserFactory(new GenericPayloadParserFactory<Swift::GatewayPayloadParser>("query", "jabber:iq:gateway"));
 
		m_server->addPayloadParserFactory(new GenericPayloadParserFactory<Swift::MUCPayloadParser>("x", "http://jabber.org/protocol/muc"));
 

	
 
		m_server->addPayloadSerializer(new Swift::AttentionSerializer());
 
		m_server->addPayloadSerializer(new Swift::XHTMLIMSerializer());
 
		m_server->addPayloadSerializer(new Transport::BlockSerializer());
 
		m_server->addPayloadSerializer(new Swift::InvisibleSerializer());
 
		m_server->addPayloadSerializer(new Swift::StatsSerializer());
 
		m_server->addPayloadSerializer(new Swift::SpectrumErrorSerializer());
 
		m_server->addPayloadSerializer(new Swift::GatewayPayloadSerializer());
 

	
 
		m_server->onDataRead.connect(boost::bind(&Component::handleDataRead, this, _1));
 
		m_server->onDataWritten.connect(boost::bind(&Component::handleDataWritten, this, _1));
 
	}
 
	else {
 
		LOG4CXX_INFO(logger, "Creating component in gateway mode");
 
		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(boost::bind(&Component::handleConnectionError, this, _1));
 
		m_component->onDataRead.connect(boost::bind(&Component::handleDataRead, this, _1));
 
		m_component->onDataWritten.connect(boost::bind(&Component::handleDataWritten, this, _1));
 

	
 
		m_component->addPayloadParserFactory(new GenericPayloadParserFactory<StorageParser>("private", "jabber:iq:private"));
 
		m_component->addPayloadParserFactory(new GenericPayloadParserFactory<Swift::AttentionParser>("attention", "urn:xmpp:attention:0"));
 
		m_component->addPayloadParserFactory(new GenericPayloadParserFactory<Swift::XHTMLIMParser>("html", "http://jabber.org/protocol/xhtml-im"));
 
		m_component->addPayloadParserFactory(new GenericPayloadParserFactory<Transport::BlockParser>("block", "urn:xmpp:block:0"));
 
		m_component->addPayloadParserFactory(new GenericPayloadParserFactory<Swift::InvisibleParser>("invisible", "urn:xmpp:invisible:0"));
 
		m_component->addPayloadParserFactory(new GenericPayloadParserFactory<Swift::StatsParser>("query", "http://jabber.org/protocol/stats"));
 
		m_component->addPayloadParserFactory(new GenericPayloadParserFactory<Swift::GatewayPayloadParser>("query", "jabber:iq:gateway"));
 
		m_component->addPayloadParserFactory(new GenericPayloadParserFactory<Swift::MUCPayloadParser>("x", "http://jabber.org/protocol/muc"));
 

	
 
		m_component->addPayloadSerializer(new Swift::AttentionSerializer());
 
		m_component->addPayloadSerializer(new Swift::XHTMLIMSerializer());
 
		m_component->addPayloadSerializer(new Transport::BlockSerializer());
 
		m_component->addPayloadSerializer(new Swift::InvisibleSerializer());
 
		m_component->addPayloadSerializer(new Swift::StatsSerializer());
 
		m_component->addPayloadSerializer(new Swift::SpectrumErrorSerializer());
 
		m_component->addPayloadSerializer(new Swift::GatewayPayloadSerializer());
 

	
 
		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 Transport::PresenceOracle(m_stanzaChannel);
 
	m_presenceOracle->onPresenceChange.connect(bind(&Component::handlePresence, this, _1));
 

	
 
	m_discoInfoResponder = new DiscoInfoResponder(m_iqRouter, m_config);
 
	m_discoInfoResponder->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_discoInfoResponder;
 
	if (m_component)
 
		delete m_component;
 
	if (m_server) {
 
		m_server->stop();
 
		delete m_server;
 
	}
 
}
 

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

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

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

	
 
Swift::CapsInfo &Component::getBuddyCapsInfo() {
 
		return m_discoInfoResponder->getBuddyCapsInfo();
 
}
 

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

	
 
void Component::start() {
 
	if (m_component && !m_component->isAvailable()) {
 
		LOG4CXX_INFO(logger, "Connecting XMPP server " << CONFIG_STRING(m_config, "service.server") << " port " << CONFIG_INT(m_config, "service.port"));
 
		if (CONFIG_INT(m_config, "service.port") == 5222) {
 
			LOG4CXX_WARN(logger, "Port 5222 is usually used for client connections, not for component connections! Are you sure you are using right port?");
 
		}
 
		m_reconnectCount++;
 
		m_component->connect(CONFIG_STRING(m_config, "service.server"), CONFIG_INT(m_config, "service.port"));
 
		m_reconnectTimer->stop();
 
	}
 
	else if (m_server) {
 
		LOG4CXX_INFO(logger, "Starting component in server mode on port " << CONFIG_INT(m_config, "service.port"));
 
		m_server->start();
 

	
 
		//Type casting to BoostConnectionServer since onStopped signal is not defined in ConnectionServer
 
		//Ideally, onStopped must be defined in ConnectionServer
 
		if (boost::dynamic_pointer_cast<Swift::BoostConnectionServer>(m_server->getConnectionServer())) {
 
			boost::dynamic_pointer_cast<Swift::BoostConnectionServer>(m_server->getConnectionServer())->onStopped.connect(boost::bind(&Component::handleServerStopped, this, _1));
 
		}
 
		
 
		// We're connected right here, because we're in server mode...
 
		handleConnected();
 
	}
 
}
 

	
 
void Component::stop() {
 
	if (m_component) {
 
		m_reconnectCount = 0;
 
		// TODO: Call this once swiften will fix assert(!session_);
 
// 		m_component->disconnect();
 
		m_reconnectTimer->stop();
 
	}
 
	else if (m_server) {
 
		LOG4CXX_INFO(logger, "Stopping component in server mode on port " << CONFIG_INT(m_config, "service.port"));
 
		m_server->stop();
 
	}
 
}
 

	
 
void Component::handleConnected() {
 
	onConnected();
 
	m_reconnectCount = 0;
 
	m_reconnectTimer->stop();
 
}
 

	
 
void Component::handleServerStopped(boost::optional<Swift::BoostConnectionServer::Error> e) {
 
	if(e != NULL ) {
 
		if(*e == Swift::BoostConnectionServer::Conflict)
 
			LOG4CXX_INFO(logger, "Port "<< CONFIG_INT(m_config, "service.port") << " already in use! Stopping server..");
 
		if(*e == Swift::BoostConnectionServer::UnknownError)
 
			LOG4CXX_INFO(logger, "Unknown error occured! Stopping server..");
 
		exit(1);
 
	}
 
}
 

	
 

	
 
void Component::handleConnectionError(const ComponentError &error) {
 
	onConnectionError(error);
 
// 	if (m_reconnectCount == 2)
 
// 		Component::instance()->userManager()->removeAllUsers();
 
	std::string str = "Unknown error";
 
	switch (error.getType()) {
 
		case ComponentError::UnknownError: str = "Unknown error"; break;
 
		case ComponentError::ConnectionError: str = "Connection error"; break;
 
		case ComponentError::ConnectionReadError: str = "Connection read error"; break;
 
		case ComponentError::ConnectionWriteError: str = "Connection write error"; break;
 
		case ComponentError::XMLError: str = "XML Error"; break;
 
		case ComponentError::AuthenticationFailedError: str = "Authentication failed error"; break;
 
		case ComponentError::UnexpectedElementError: str = "Unexpected element error"; break;
 
	}
 
	LOG4CXX_INFO(logger, "Disconnected from XMPP server. Error: " << str);
 

	
 
	m_reconnectTimer->start();
 
}
 

	
 
void Component::handleDataRead(const Swift::SafeByteArray &data) {
 
	std::string d = safeByteArrayToString(data);
 
	if (!boost::starts_with(d, "<auth")) {
 
		LOG4CXX_INFO(logger_xml, "XML IN " << d);
 
	}
 
}
 

	
 
void Component::handleDataWritten(const Swift::SafeByteArray &data) {
 
	LOG4CXX_INFO(logger_xml, "XML OUT " << safeByteArrayToString(data));
 
}
 

	
 
void Component::handlePresence(Swift::Presence::ref presence) {
 
	bool isMUC = presence->getPayload<MUCPayload>() != NULL || *presence->getTo().getNode().c_str() == '#';
 
	// filter out login/logout presence spam
 
	if (!presence->getTo().getNode().empty() && isMUC == false)
 
		return;
 

	
 
	// filter out bad presences
 
	if (!presence->getFrom().isValid()) {
 
		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"
 
#include "transport/rostermanager.h"
 
#include "transport/userregistry.h"
 
#include "transport/logging.h"
 
#include "transport/discoitemsresponder.h"
 
#include "storageresponder.h"
 

	
 
#include "Swiften/Swiften.h"
 
#include "Swiften/Server/ServerStanzaChannel.h"
 
#include "Swiften/Elements/StreamError.h"
 
#ifndef __FreeBSD__
 
#include "malloc.h"
 
#endif
 
// #include "valgrind/memcheck.h"
 

	
 
namespace Transport {
 

	
 
DEFINE_LOGGER(logger, "UserManager");
 

	
 
UserManager::UserManager(Component *component, UserRegistry *userRegistry, StorageBackend *storageBackend) {
 
UserManager::UserManager(Component *component, UserRegistry *userRegistry, DiscoItemsResponder *discoItemsResponder, StorageBackend *storageBackend) {
 
	m_cachedUser = NULL;
 
	m_onlineBuddies = 0;
 
	m_sentToXMPP = 0;
 
	m_sentToBackend = 0;
 
	m_component = component;
 
	m_storageBackend = storageBackend;
 
	m_storageResponder = NULL;
 
	m_userRegistry = userRegistry;
 
	m_discoItemsResponder = discoItemsResponder;
 

	
 
	if (m_storageBackend) {
 
		m_storageResponder = new StorageResponder(component->getIQRouter(), m_storageBackend, this);
 
		m_storageResponder->start();
 
	}
 

	
 
	component->onUserPresenceReceived.connect(bind(&UserManager::handlePresence, this, _1));
 
	component->onUserDiscoInfoReceived.connect(bind(&UserManager::handleDiscoInfo, this, _1, _2));
 
	m_component->getStanzaChannel()->onMessageReceived.connect(bind(&UserManager::handleMessageReceived, this, _1));
 
	m_component->getStanzaChannel()->onPresenceReceived.connect(bind(&UserManager::handleGeneralPresenceReceived, this, _1));
 

	
 
	m_userRegistry->onConnectUser.connect(bind(&UserManager::connectUser, this, _1));
 
	m_userRegistry->onDisconnectUser.connect(bind(&UserManager::disconnectUser, this, _1));
 

	
 
	m_removeTimer = m_component->getNetworkFactories()->getTimerFactory()->createTimer(1);
 
}
 

	
 
UserManager::~UserManager(){
 
	if (m_storageResponder) {
 
		m_storageResponder->stop();
 
		delete m_storageResponder;
 
	}
 
}
 

	
 
void UserManager::addUser(User *user) {
 
	m_users[user->getJID().toBare().toString()] = user;
 
	if (m_storageBackend) {
 
		m_storageBackend->setUserOnline(user->getUserInfo().id, true);
 
	}
 
	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;
 
}
 

	
 
Swift::DiscoInfo::ref UserManager::getCaps(const Swift::JID &jid) const {
 
	std::map<std::string, User *>::const_iterator it = m_users.find(jid.toBare().toString());
 
	if (it == m_users.end()) {
 
		return Swift::DiscoInfo::ref();
 
	}
 

	
 
	User *user = it->second;
 
	return user->getCaps(jid);
 
}
 

	
 
void UserManager::removeUser(User *user, bool onUserBehalf) {
 
	m_users.erase(user->getJID().toBare().toString());
 
	if (m_cachedUser == user)
 
		m_cachedUser = NULL;
 

	
 
	if (m_component->inServerMode()) {
 
		disconnectUser(user->getJID());
 
	}
 
	else {
 
		// User could be disconnected by User::handleDisconnect() method, but
 
		// Transport::PresenceOracle could still contain his last presence.
 
		// We have to clear all received presences for this user in PresenceOracle.
 
		m_component->getPresenceOracle()->clearPresences(user->getJID().toBare());
 
	}
 

	
 
	if (m_storageBackend && onUserBehalf) {
 
		m_storageBackend->setUserOnline(user->getUserInfo().id, false);
 
	}
 

	
 
	onUserDestroyed(user);
 
	delete user;
 
#ifndef WIN32
 
#ifndef __FreeBSD__
 
	malloc_trim(0);
 
#endif
 
#endif
 
// 	VALGRIND_DO_LEAK_CHECK;
 
}
 

	
 
void UserManager::removeAllUsers(bool onUserBehalf) {
 
	while(m_users.begin() != m_users.end()) {
 
		removeUser((*m_users.begin()).second, onUserBehalf);
 
	}
 
}
 

	
 
int UserManager::getUserCount() {
 
	return m_users.size();
 
}
 

	
 
void UserManager::handleDiscoInfo(const Swift::JID& jid, boost::shared_ptr<Swift::DiscoInfo> info) {
 
	User *user = getUser(jid.toBare().toString());
0 comments (0 inline, 0 general)