Changeset - 79cc6dc63de8
[Not reviewed]
0 8 0
HanzZ - 14 years ago 2011-03-29 21:59:14
hanzz.k@gmail.com
[service] server_mode config
8 files changed with 84 insertions and 24 deletions:
0 comments (0 inline, 0 general)
examples/server_connect/sample.cfg
Show inline comments
 
[service]
 
jid = icq.localhost
 
password = secret
 
server = 127.0.0.1
 
port = 8888
 
port = 5222
 
server_mode = 1
include/transport/transport.h
Show inline comments
 
@@ -13,31 +13,33 @@
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
 * GNU General Public License for more details.
 
 *
 
 * You should have received a copy of the GNU General Public License
 
 * along with this program; if not, write to the Free Software
 
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
 
 */
 

	
 
#pragma once
 

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

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

	
 
namespace Transport {
 
	// typedef enum { 	CLIENT_FEATURE_ROSTERX = 2,
 
	// 				CLIENT_FEATURE_XHTML_IM = 4,
 
	// 				CLIENT_FEATURE_FILETRANSFER = 8,
 
	// 				CLIENT_FEATURE_CHATSTATES = 16
 
	// 				} SpectrumImportantFeatures;
 
@@ -59,31 +61,34 @@ namespace Transport {
 
			/// 	- service.jid
 
			/// 	- service.password
 
			/// 	- service.server
 
			/// 	- service.port
 
			Component(Swift::EventLoop *loop, Config *config);
 

	
 
			/// Component destructor.
 
			~Component();
 

	
 
			/// Returns Swift::Component associated with this Transport::Component.
 
			/// You can use it to send presences and other stanzas.
 
			/// \return Swift::Component associated with this Transport::Component
 
			Swift::Component *getComponent();
 
			Swift::StanzaChannel *getStanzaChannel();
 

	
 
			/// Returns Swift::PresenceOracle associated with this Transport::Component.
 
			/// You can use it to check current resource connected for particular user.
 
			/// \return Swift::PresenceOracle associated with this Transport::Component
 
			Swift::PresenceOracle *getPresenceOracle();
 

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

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

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

	
 
			/// Sets disco#info features which are sent as answer to
 
			/// disco#info IQ-get. This sets features of legacy network buddies (For example "me\40gmail.com@j2j.domain.tld").
 
			/// \param features list of features as sent in disco#info response
 
@@ -125,30 +130,34 @@ namespace Transport {
 
// 			void handleMessageReceived(Swift::Message::ref message);
 
			void handlePresence(Swift::Presence::ref presence);
 
			void handleSubscription(Swift::Presence::ref presence);
 
			void handleProbePresence(Swift::Presence::ref presence);
 
			void handleDataRead(const std::string &data);
 
			void handleDataWritten(const std::string &data);
 

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

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

	
 
		friend class User;
 
		friend class UserRegistration;
 
	};
spectrum/src/sample.cfg
Show inline comments
 
[service]
 
jid = icq.localhost
 
password = secret
 
server = 127.0.0.1
 
port = 8888
 
port = 5222
 
protocol=prpl-jabber
 
server_mode=1
 

	
 
[database]
 
database = test.sql
 
prefix=icq
src/config.cpp
Show inline comments
 
@@ -28,24 +28,25 @@ namespace Transport {
 
bool Config::load(const std::string &configfile, boost::program_options::options_description &opts) {
 
	std::ifstream ifs(configfile.c_str());
 
	if (!ifs.is_open())
 
		return false;
 

	
 
	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.protocol", value<std::string>()->default_value(""), "Protocol")
 
		("service.allowed_servers", value<std::string>()->default_value(""), "Only users from these servers can connect")
 
		("service.server_mode", value<bool>()->default_value(false), "True if Spectrum should behave as server")
 
		("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(""), "Instructions showed to user in registration form")
 
		("registration.username_field", value<std::string>()->default_value(""), "Label for username field")
 
		("registration.username_mask", value<std::string>()->default_value(""), "Username mask")
 
		("registration.encoding", value<std::string>()->default_value("en"), "Default encoding in registration form")
 
		("database.database", value<std::string>()->default_value(""), "Database used to store data")
 
		("database.prefix", value<std::string>()->default_value(""), "Prefix of tables in database")
 
	;
 

	
 
    store(parse_config_file(ifs, opts), m_variables);
 
	notify(m_variables);
src/transport.cpp
Show inline comments
 
@@ -20,91 +20,129 @@
 

	
 
#include "transport/transport.h"
 
#include <boost/bind.hpp>
 
#include "transport/storagebackend.h"
 
#include "discoinforesponder.h"
 
#include "discoitemsresponder.h"
 

	
 
using namespace Swift;
 
using namespace boost;
 

	
 
namespace Transport {
 

	
 

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

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

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

	
 
	m_factories = new BoostNetworkFactories(loop);
 

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

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

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

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

	
 
	m_discoItemsResponder = new DiscoItemsResponder(m_component->getIQRouter());
 
	m_discoItemsResponder = new DiscoItemsResponder(m_iqRouter);
 
	m_discoItemsResponder->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;
 
// 	delete m_registerHandler;
 
	delete m_component;
 
	if (m_component)
 
		delete m_component;
 
	if (m_server)
 
		delete m_server;
 
	if (m_userRegistry)
 
		delete m_userRegistry;
 
	delete m_factories;
 
}
 

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

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

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

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

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

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

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

	
 
void Component::handleConnectionError(const ComponentError &error) {
 
	onConnectionError(error);
 
@@ -161,25 +199,25 @@ void Component::handlePresence(Swift::Presence::ref presence) {
 
		return;
 
	}
 

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

	
 
	onUserPresenceReceived(presence);
 
}
 

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

	
src/user.cpp
Show inline comments
 
@@ -69,32 +69,32 @@ void User::handlePresence(Swift::Presence::ref presence) {
 
				}
 
			}
 
			else {
 
				m_reconnectTimer->start();
 
			}
 
		}
 
	}
 

	
 

	
 
	if (highest) {
 
		highest->setTo(presence->getFrom().toBare());
 
		highest->setFrom(m_component->getJID());
 
		m_component->getComponent()->sendPresence(highest);
 
		m_component->getStanzaChannel()->sendPresence(highest);
 
	}
 
	else {
 
		Swift::Presence::ref response = Swift::Presence::create();
 
		response->setTo(m_jid.toBare());
 
		response->setFrom(m_component->getJID());
 
		response->setType(Swift::Presence::Unavailable);
 
		m_component->getComponent()->sendPresence(response);
 
		m_component->getStanzaChannel()->sendPresence(response);
 
	}
 
}
 

	
 
void User::onConnectingTimeout() {
 
	if (m_connected || m_readyForConnect)
 
		return;
 
	m_reconnectTimer->stop();
 
	m_readyForConnect = true;
 
	onReadyToConnect();
 
}
 

	
 
}
src/usermanager.cpp
Show inline comments
 
@@ -71,37 +71,47 @@ int UserManager::getUserCount() {
 
void UserManager::handlePresence(Swift::Presence::ref presence) {
 
	std::string barejid = presence->getTo().toBare().toString();
 
	std::string userkey = presence->getFrom().toBare().toString();
 

	
 
	User *user = getUser(userkey);
 
	if (!user ) {
 
		// No user and unavailable presence -> answer with unavailable
 
		if (presence->getType() == Swift::Presence::Unavailable) {
 
			Swift::Presence::ref response = Swift::Presence::create();
 
			response->setTo(presence->getFrom());
 
			response->setFrom(presence->getTo());
 
			response->setType(Swift::Presence::Unavailable);
 
			m_component->getComponent()->sendPresence(response);
 
			m_component->getStanzaChannel()->sendPresence(response);
 

	
 
			UserInfo res;
 
			bool registered = m_storageBackend->getUser(userkey, res);
 
			if (registered) {
 
				m_storageBackend->setUserOnline(res.id, false);
 
			}
 
			return;
 
		}
 

	
 
		UserInfo res;
 
		bool registered = m_storageBackend->getUser(userkey, res);
 

	
 
		if (!registered && m_component->inServerMode()) {
 
			res.password = m_component->getUserRegistryPassword(userkey);
 
			res.uin = presence->getFrom().getNode();
 
			if (res.uin.find_last_of("%") != std::string::npos) {
 
				res.uin.replace(res.uin.find_last_of("%"), 1, "@");
 
			}
 
			registered = true;
 
			m_storageBackend->setUser(res);
 
		}
 

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

	
 
		// TODO: isVIP
 
// // 			bool isVip = res.vip;
 
// // 			std::list<std::string> const &x = CONFIG().allowedServers;
 
// // 			if (CONFIG().onlyForVIP && !isVip && std::find(x.begin(), x.end(), presence->getFrom().getDomain().getUTF8String()) == x.end()) {
 
// // 				Log(presence->getFrom().toString().getUTF8String(), "This user is not VIP, can't login...");
 
// // 				return;
 
// // 			}
src/userregistration.cpp
Show inline comments
 
@@ -21,25 +21,25 @@
 
#include "transport/userregistration.h"
 
#include "transport/usermanager.h"
 
#include "transport/storagebackend.h"
 
#include "transport/transport.h"
 
#include "transport/user.h"
 
#include "Swiften/Elements/ErrorPayload.h"
 
#include <boost/shared_ptr.hpp>
 

	
 
using namespace Swift;
 

	
 
namespace Transport {
 

	
 
UserRegistration::UserRegistration(Component *component, UserManager *userManager, StorageBackend *storageBackend) : Swift::GetResponder<Swift::InBandRegistrationPayload>(component->m_component->getIQRouter()), Swift::SetResponder<Swift::InBandRegistrationPayload>(component->m_component->getIQRouter()) {
 
UserRegistration::UserRegistration(Component *component, UserManager *userManager, StorageBackend *storageBackend) : Swift::GetResponder<Swift::InBandRegistrationPayload>(component->m_iqRouter), Swift::SetResponder<Swift::InBandRegistrationPayload>(component->m_iqRouter) {
 
	m_component = component;
 
	m_config = m_component->m_config;
 
	m_storageBackend = storageBackend;
 
	m_userManager = userManager;
 
	Swift::GetResponder<Swift::InBandRegistrationPayload>::start();
 
	Swift::SetResponder<Swift::InBandRegistrationPayload>::start();
 
}
 

	
 
UserRegistration::~UserRegistration(){
 
}
 

	
 
bool UserRegistration::registerUser(const UserInfo &row) {
0 comments (0 inline, 0 general)