Changeset - fa9b9847088e
CMakeLists.txt
Show inline comments
 
@@ -74,165 +74,167 @@ message("-----------------------")
 
if (SPECTRUM_VERSION)
 
	ADD_DEFINITIONS(-DSPECTRUM_VERSION="${SPECTRUM_VERSION}")
 
else (SPECTRUM_VERSION)
 
	if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git)
 
		execute_process(COMMAND git "--git-dir=${CMAKE_CURRENT_SOURCE_DIR}/.git" rev-parse --short HEAD
 
						OUTPUT_VARIABLE GIT_REVISION
 
						OUTPUT_STRIP_TRAILING_WHITESPACE
 
		)
 
		set(SPECTRUM_VERSION 2.0.0-beta-git-${GIT_REVISION})
 
		ADD_DEFINITIONS(-DSPECTRUM_VERSION="${SPECTRUM_VERSION}")
 
	else (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git)
 
		set(SPECTRUM_VERSION 2.0.0-alpha)
 
		ADD_DEFINITIONS(-DSPECTRUM_VERSION="${SPECTRUM_VERSION}")
 
	endif (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git)
 
endif (SPECTRUM_VERSION)
 

	
 
message("Version           : " ${SPECTRUM_VERSION})
 

	
 
if (SQLITE3_FOUND)
 
	ADD_DEFINITIONS(-DWITH_SQLITE)
 
	include_directories(${SQLITE3_INCLUDE_DIR})
 
	message("SQLite3           : yes")
 
else (SQLITE3_FOUND)
 
	set(SQLITE3_LIBRARIES "")
 
	message("SQLite3           : no")
 
endif (SQLITE3_FOUND)
 

	
 
if (MYSQL_FOUND)
 
	ADD_DEFINITIONS(-DWITH_MYSQL)
 
	include_directories(${MYSQL_INCLUDE_DIR})
 
	message("MySQL             : yes")
 
else (MYSQL_FOUND)
 
	set(MYSQL_LIBRARIES "")
 
	message("MySQL             : no (install mysql-devel)")
 
endif (MYSQL_FOUND)
 

	
 
if (PQXX_FOUND)
 
	ADD_DEFINITIONS(-DWITH_PQXX)
 
	include_directories(${PQXX_INCLUDE_DIR})
 
	message("PostgreSQL        : yes")
 
else (PQXX_FOUND)
 
	set(PQXX_LIBRARY "")
 
	set(PQ_LIBRARY "")
 
	message("PostgreSQL        : no (install libpqxx-devel)")
 
endif (PQXX_FOUND)
 

	
 
if (PROTOBUF_FOUND)
 
	ADD_DEFINITIONS(-DWITH_PROTOBUF)
 
	include_directories(${PROTOBUF_INCLUDE_DIRS})
 
	message("Network plugins   : yes")
 

	
 
	if(PURPLE_LIBRARY AND PURPLE_INCLUDE_DIR)
 
		message("Libpurple plugin  : yes")
 
		include_directories(${PURPLE_INCLUDE_DIR})
 
		include_directories(${GLIB2_INCLUDE_DIR})
 
	else()
 
		message("Libpurple plugin  : no (install libpurple)")
 
	endif()
 

	
 
	if (HAVE_EVENT)
 
		ADD_DEFINITIONS(-DWITH_LIBEVENT)
 
		include_directories(${EVENT_INCLUDE_DIRS})
 
		message("  libev eventloop : yes")
 
	else()
 
		message("  libev eventloop : no (install libev-devel)")
 
	endif()
 

	
 
	if(IRC_FOUND)
 
		ADD_DEFINITIONS(-DCOMMUNI_SHARED)
 
		message("IRC plugin        : yes")
 
		include_directories(${QT_QTNETWORK_INCLUDE_DIR})
 
		include_directories(${IRC_INCLUDE_DIR})
 
		include(${QT_USE_FILE})
 
	else()
 
		message("IRC plugin        : no (install libCommuni and libprotobuf-dev)")
 
	endif()
 

	
 
	message("Frotz plugin      : yes")
 
	message("SMSTools3 plugin  : yes")
 

	
 
	if(${LIBDBUSGLIB_FOUND})
 
		message("Skype plugin      : yes")
 
		include_directories(${LIBDBUSGLIB_INCLUDE_DIRS})
 
	else()
 
		message("Skype plugin      : no (install dbus-glib-devel)")
 
	endif()
 

	
 
else()
 
	message("Network plugins   : no (install libprotobuf-dev)")
 
	message("Libpurple plugin  : no (install libpurple and libprotobuf-dev)")
 
	message("IRC plugin        : no (install libircclient-qt and libprotobuf-dev)")
 
	message("Frotz plugin      : no (install libprotobuf-dev)")
 
	message("SMSTools3 plugin  : no (install libprotobuf-dev)")
 
endif()
 

	
 
if (LOG4CXX_FOUND)
 
	message("Logging           : yes")
 
	message("Log4cxx           : yes")
 
	include_directories(${LOG4CXX_INCLUDE_DIR})
 
	ADD_DEFINITIONS(-DWITH_LOG4CXX)
 
else()
 
	message(FATAL_ERROR "Logging           : no (install log4cxx-devel)")
 
	set(LOG4CXX_LIBRARIES "")
 
	message("Log4cxx           : no (install log4cxx-devel)")
 
endif()
 

	
 
if (WIN32)
 
ADD_DEFINITIONS(-D_WIN32_WINNT=0x501)
 
ADD_DEFINITIONS(-DWIN32_LEAN_AND_MEAN)
 
endif()
 

	
 
if(CMAKE_BUILD_TYPE MATCHES Debug)
 
if (CMAKE_COMPILER_IS_GNUCXX)
 
	ADD_DEFINITIONS(-O3)
 
	ADD_DEFINITIONS(-ggdb)
 
	ADD_DEFINITIONS(-Wall)
 
	ADD_DEFINITIONS(-W)
 
	ADD_DEFINITIONS(-Wcast-align)
 
	ADD_DEFINITIONS(-Wextra -Wno-sign-compare -Wno-unused-parameter)
 
	ADD_DEFINITIONS(-Winit-self)
 
	ADD_DEFINITIONS(-Wmissing-declarations)
 
	ADD_DEFINITIONS(-Wpointer-arith)
 
	ADD_DEFINITIONS(-Wreorder)
 
	ADD_DEFINITIONS(-Woverloaded-virtual)
 
	ADD_DEFINITIONS(-Wsign-promo)
 
	ADD_DEFINITIONS(-Wundef -Wunused)
 
endif()
 
	ADD_DEFINITIONS(-DDEBUG)
 
	message("Debug             : yes")
 
else(CMAKE_BUILD_TYPE MATCHES Debug)
 
	message("Debug             : no (run \"cmake . -DCMAKE_BUILD_TYPE=Debug\")")
 
endif(CMAKE_BUILD_TYPE MATCHES Debug)
 

	
 

	
 
SET(TRANSPORT_VERSION 2.0)
 
SET(PROJECT_VERSION 2.0)
 
include_directories(include)
 

	
 

	
 
include_directories(${EVENT_INCLUDE_DIRS})
 
include_directories(${SWIFTEN_INCLUDE_DIR})
 
include_directories(${Boost_INCLUDE_DIRS})
 
include_directories(${OPENSSL_INCLUDE_DIR})
 

	
 
ADD_SUBDIRECTORY(src)
 
ADD_SUBDIRECTORY(plugin)
 
ADD_SUBDIRECTORY(include)
 
ADD_SUBDIRECTORY(spectrum)
 
ADD_SUBDIRECTORY(backends)
 
if (NOT WIN32)
 
	ADD_SUBDIRECTORY(spectrum_manager)
 
#	ADD_SUBDIRECTORY(spectrum2_send_message)
 
endif()
 

	
 
if (CPPUNIT_FOUND)
 
	message("tests             : yes")
 
	include_directories(${CPPUNIT_INCLUDE_DIR})
 
else()
 
	message("tests             : no (install CPPUnit)")
 
endif()
 

	
 
if(DOXYGEN_FOUND)
 
	message("Docs              : yes")
 
	ADD_SUBDIRECTORY(docs)
 
else(DOXYGEN_FOUND)
 
	message("Docs              : no (install doxygen)")
 
endif(DOXYGEN_FOUND)
 

	
 
message("----------------------")
ChangeLog
Show inline comments
 
Version 2.0.0-beta2 (2012-XX-XX):
 
	General:
 
	* Fixed bug when Roster Item Exchange and subscribe stanzas were sent
 
	  repeatedly.
 
	* Backends related logs now contain the backend PID.
 
	* Fixed username_mask setting.
 
	* Added new fields into statistics (backends_crashed, messages related
 
	  stats).
 
	* Log4cxx is now optional dependency. Without Log4cxx, Spectrum 2 logs
 
	  to standard output.
 
	* Fixed crash when Log4cxx configuration file didn't exist.
 
	* Admin can now see "Admin" contact in server-mode.
 

	
 
	libpurple:
 
	* Added support for MUC for prpl-jabber protocol.
 

	
 
	Skype:
 
	* Memory usage statistic now includes the Skype client.
 
	* Fixed logging issue when the logs were not stored in the proper instance
 
	  directory.
 
	* Skype backend includes also Skype client memory usage into the account.
 
	* Working buddies adding/removing.
 
	* Information about missed call is now forwarded to XMPP user.
 

	
 
Version 2.0.0-beta (2012-02-28):
 
	General:
 
	* Added PostreSQL support (thanks to Jadestorm).
 
	* Added XEP-0100 (Gateway interaction) support.
 
	* Send presences only "from" bare JID (fixed bug with buddies appearing
 
	  twice in the roster and potential unregistering issues).
 
	* Fixed potential MySQL/SQLite3 deadlocks.
 
	* Fixed disconnecting in server-mode when client does not send unavailable
 
	  presence before disconnection.
 
	* Fixed crash in server-mode when client send its custom jabber:iq:storage
 
	  payload.
 
	* Fixed registration from Pidgin.
 
	* Unsubscribe presence sent to some buddy doesn't disconnect the account.
 
	* Remote Roster requests are not sent to resources, but to bare JID.
 
	* Added automatic reconnection in case of non-fatal error.
 
	* Added more error messages.
 

	
 
	Skype:
 
	* Initial support for Skype added, read more on
 
	  http://spectrum.im/projects/spectrum/wiki/Spectrum_2_Admin_-_Skype_backend
 

	
 
	SMSTools3:
 
	* Initial support for SMSTools3, read more on
 
	http://spectrum.im/projects/spectrum/wiki/Spectrum_2_Admin_-_SMSTools3_backend
 

	
 
version 2.0.0 alpha (2011-12-06):
 
	General:
 
	* First Spectrum 2.0.0 alpha release, check more on
 
	  http://spectrum.im/projects/spectrum/wiki/Spectrum_200_alpha
backends/libcommuni/main.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 "transport/config.h"
 
#include "transport/networkplugin.h"
 
#include "transport/logging.h"
 
#include "session.h"
 
#include <QtCore>
 
#include <QtNetwork>
 
#include "Swiften/EventLoop/Qt/QtEventLoop.h"
 
#include "ircnetworkplugin.h"
 
#include "singleircnetworkplugin.h"
 

	
 
#include "log4cxx/logger.h"
 
#include "log4cxx/consoleappender.h"
 
#include "log4cxx/patternlayout.h"
 
#include "log4cxx/propertyconfigurator.h"
 
#include "log4cxx/helpers/properties.h"
 
#include "log4cxx/helpers/fileinputstream.h"
 
#include "log4cxx/helpers/transcoder.h"
 

	
 
using namespace boost::program_options;
 
using namespace Transport;
 

	
 
using namespace log4cxx;
 

	
 
NetworkPlugin * np = NULL;
 

	
 
int main (int argc, char* argv[]) {
 
	std::string host;
 
	int port;
 

	
 

	
 
	boost::program_options::options_description desc("Usage: spectrum [OPTIONS] <config_file.cfg>\nAllowed options");
 
	desc.add_options()
 
		("host,h", value<std::string>(&host), "host")
 
		("port,p", value<int>(&port), "port")
 
		;
 
	try
 
	{
 
		boost::program_options::variables_map vm;
 
		boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm);
 
		boost::program_options::notify(vm);
 
	}
 
	catch (std::runtime_error& e)
 
	{
 
		std::cout << desc << "\n";
 
		exit(1);
 
	}
 
	catch (...)
 
	{
 
		std::cout << desc << "\n";
 
		exit(1);
 
	}
 

	
 

	
 
	if (argc < 5) {
 
		qDebug("Usage: %s <config>", argv[0]);
 
		return 1;
 
	}
 

	
 
// 	QStringList channels;
 
// 	for (int i = 3; i < argc; ++i)
 
// 	{
 
// 		channels.append(argv[i]);
 
// 	}
 
// 
 
// 	MyIrcSession session;
 
// 	session.setNick(argv[2]);
 
// 	session.setAutoJoinChannels(channels);
 
// 	session.connectToServer(argv[1], 6667);
 

	
 
	Config config;
 
	if (!config.load(argv[5])) {
 
		std::cerr << "Can't open " << argv[1] << " configuration file.\n";
 
		return 1;
 
	}
 
	QCoreApplication app(argc, argv);
 

	
 
	Logging::initBackendLogging(&config);
 

	
 
	Swift::QtEventLoop eventLoop;
 

	
 
	if (config.getUnregistered().find("service.irc_server") == config.getUnregistered().end()) {
 
		np = new IRCNetworkPlugin(&config, &eventLoop, host, port);
 
	}
 
	else {
 
		np = new SingleIRCNetworkPlugin(&config, &eventLoop, host, port);
 
	}
 

	
 
	return app.exec();
 
}
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 "Swiften/Elements/StatusShow.h"
 
#include <IrcCommand>
 
#include <IrcMessage>
 

	
 
#include "log4cxx/logger.h"
 
#include "transport/logging.h"
 

	
 
using namespace log4cxx;
 

	
 
static LoggerPtr logger = log4cxx::Logger::getLogger("IRCSession");
 
DEFINE_LOGGER(logger, "IRCSession");
 

	
 
MyIrcSession::MyIrcSession(const std::string &user, NetworkPlugin *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(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);
 
	}
 

	
 
	for(std::list<std::string>::const_iterator it = m_autoJoin.begin(); it != m_autoJoin.end(); it++) {
 
		sendCommand(IrcCommand::createJoin(QString::fromStdString(*it)));
 
	}
 

	
 
	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(QString::fromStdString(to), QString::fromStdString(what)));
 
	}
 
}
 

	
 
void MyIrcSession::on_disconnected() {
 
	if (suffix.empty())
 
		np->handleDisconnected(user, 0, "");
 
	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 = m->sender().name().toStdString();
 
	flags = correctNickname(nickname);
 
	np->handleParticipantChanged(user, nickname, m->channel().toStdString() + suffix, (int) flags, pbnetwork::STATUS_ONLINE);
 
	LOG4CXX_INFO(logger, user << ": Joined " << m->parameters()[0].toStdString());
 
}
 

	
 

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

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

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

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

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

	
 
	// mode changed: "#testik" "HanzZ" "+o" "hanzz_k"
 
	std::string nickname = m->argument().toStdString();
 
	std::string mode = m->mode().toStdString();
 
	if (nickname.empty())
 
		return;
 
	LOG4CXX_INFO(logger, user << ": " << nickname << " changed mode to " << mode);
backends/libcommuni/singleircnetworkplugin.cpp
Show inline comments
 
#include "singleircnetworkplugin.h"
 
#include "log4cxx/logger.h"
 
#include "transport/logging.h"
 
#include <IrcCommand>
 
#include <IrcMessage>
 

	
 
using namespace log4cxx;
 

	
 
static LoggerPtr logger = log4cxx::Logger::getLogger("SingleIRCNetworkPlugin");
 
DEFINE_LOGGER(logger, "SingleIRCNetworkPlugin");
 

	
 
SingleIRCNetworkPlugin::SingleIRCNetworkPlugin(Config *config, Swift::QtEventLoop *loop, const std::string &host, int port) {
 
	this->config = config;
 
	m_server = config->getUnregistered().find("service.irc_server")->second;
 
	m_socket = new QTcpSocket();
 
	m_socket->connectToHost(QString::fromStdString(host), port);
 
	connect(m_socket, SIGNAL(readyRead()), this, SLOT(readData()));
 

	
 
	if (config->getUnregistered().find("service.irc_identify") != config->getUnregistered().end()) {
 
		m_identify = config->getUnregistered().find("service.irc_identify")->second;
 
	}
 
	else {
 
		m_identify = "NickServ identify $name $password";
 
	}
 

	
 
	LOG4CXX_INFO(logger, "SingleIRCNetworkPlugin for server " << m_server << " initialized.");
 
}
 

	
 
void SingleIRCNetworkPlugin::readData() {
 
	size_t availableBytes = m_socket->bytesAvailable();
 
	if (availableBytes == 0)
 
		return;
 

	
 
	std::string d = std::string(m_socket->readAll().data(), availableBytes);
 
	handleDataRead(d);
 
}
 

	
 
void SingleIRCNetworkPlugin::sendData(const std::string &string) {
 
	m_socket->write(string.c_str(), string.size());
 
}
 

	
 
void SingleIRCNetworkPlugin::handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) {
 
	// legacy name is users nickname
 
	if (m_sessions[user] != NULL) {
 
		LOG4CXX_WARN(logger, user << ": Already logged in.");
 
		return;
 
	}
 
	LOG4CXX_INFO(logger, user << ": Connecting " << m_server << " as " << legacyName);
 

	
 
	MyIrcSession *session = new MyIrcSession(user, this);
 
	session->setUserName(QString::fromStdString(legacyName));
 
	session->setNickName(QString::fromStdString(legacyName));
 
	session->setRealName(QString::fromStdString(legacyName));
 
	session->setHost(QString::fromStdString(m_server));
 
	session->setPort(6667);
 

	
 
	std::string identify = m_identify;
 
	boost::replace_all(identify, "$password", password);
 
	boost::replace_all(identify, "$name", legacyName);
 
	session->setIdentify(identify);
 

	
 
	session->open();
 

	
 
	m_sessions[user] = session;
 
}
 

	
 
void SingleIRCNetworkPlugin::handleLogoutRequest(const std::string &user, const std::string &legacyName) {
 
	if (m_sessions[user] == NULL) {
 
		LOG4CXX_WARN(logger, user << ": Already disconnected.");
 
		return;
 
	}
 
	LOG4CXX_INFO(logger, user << ": Disconnecting.");
 

	
 
	m_sessions[user]->close();
 
	m_sessions[user]->deleteLater();
 
	m_sessions.erase(user);
 
}
 

	
 
void SingleIRCNetworkPlugin::handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &/*xhtml*/) {
 
	if (m_sessions[user] == NULL) {
 
		LOG4CXX_WARN(logger, user << ": Message received for unconnected user");
 
		return;
 
	}
 

	
 
	// handle PMs
 
	std::string r = legacyName;
 
	if (legacyName.find("/") == std::string::npos) {
 
		r = legacyName.substr(0, r.find("@"));
 
	}
 
	else {
 
		r = legacyName.substr(legacyName.find("/") + 1);
 
	}
 

	
 
	LOG4CXX_INFO(logger, user << ": Forwarding message to " << r);
 
	m_sessions[user]->sendCommand(IrcCommand::createMessage(QString::fromStdString(r), QString::fromStdString(message)));
 

	
 
	if (r.find("#") == 0) {
 
		handleMessage(user, legacyName, message, m_sessions[user]->nickName().toStdString());
 
	}
 
}
 

	
 
void SingleIRCNetworkPlugin::handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &password) {
 
	if (m_sessions[user] == NULL) {
 
		LOG4CXX_WARN(logger, user << ": Join room requested for unconnected user");
 
		return;
 
	}
backends/libpurple/geventloop.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 "geventloop.h"
 
#ifdef _WIN32
 
#include "win32/win32dep.h"
 
#undef read
 
#undef write
 
#endif
 
#ifdef WITH_LIBEVENT
 
#include "event.h"
 
#endif
 

	
 
#include "log4cxx/logger.h"
 
#include "transport/logging.h"
 

	
 
using namespace log4cxx;
 

	
 
static LoggerPtr logger = Logger::getLogger("EventLoop");
 
DEFINE_LOGGER(logger, "EventLoop");
 

	
 
typedef struct _PurpleIOClosure {
 
	PurpleInputFunction function;
 
	guint result;
 
	gpointer data;
 
#ifdef WITH_LIBEVENT
 
	GSourceFunc function2;
 
	struct timeval timeout;
 
	struct event evfifo;
 
#endif
 
} PurpleIOClosure;
 

	
 
static gboolean io_invoke(GIOChannel *source,
 
										GIOCondition condition,
 
										gpointer data)
 
{
 
	PurpleIOClosure *closure = (PurpleIOClosure* )data;
 
	PurpleInputCondition purple_cond = (PurpleInputCondition)0;
 

	
 
	int tmp = 0;
 
	if (condition & READ_COND)
 
	{
 
		tmp |= PURPLE_INPUT_READ;
 
		purple_cond = (PurpleInputCondition)tmp;
 
	}
 
	if (condition & WRITE_COND)
 
	{
 
		tmp |= PURPLE_INPUT_WRITE;
 
		purple_cond = (PurpleInputCondition)tmp;
 
	}
 

	
 
	closure->function(closure->data, g_io_channel_unix_get_fd(source), purple_cond);
 

	
 
	return TRUE;
 
}
 

	
 
static void io_destroy(gpointer data)
 
{
 
	g_free(data);
 
}
 

	
 
static guint input_add(gint fd,
 
								PurpleInputCondition condition,
 
								PurpleInputFunction function,
 
								gpointer data)
 
{
 
	PurpleIOClosure *closure = g_new0(PurpleIOClosure, 1);
 
	GIOChannel *channel;
 
	GIOCondition cond = (GIOCondition)0;
 
	closure->function = function;
 
	closure->data = data;
 

	
 
	int tmp = 0;
 
	if (condition & PURPLE_INPUT_READ)
 
	{
 
		tmp |= READ_COND;
 
		cond = (GIOCondition)tmp;
 
	}
 
	if (condition & PURPLE_INPUT_WRITE)
 
	{
 
		tmp |= WRITE_COND;
 
		cond = (GIOCondition)tmp;
 
	}
 

	
 
#ifdef WIN32
 
	channel = wpurple_g_io_channel_win32_new_socket(fd);
 
#else
 
	channel = g_io_channel_unix_new(fd);
 
#endif
 
	closure->result = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond,
 
	io_invoke, closure, io_destroy);
 

	
 
	g_io_channel_unref(channel);
 
	return closure->result;
 
}
 

	
 
static PurpleEventLoopUiOps eventLoopOps =
 
{
 
	g_timeout_add,
 
	g_source_remove,
 
	input_add,
 
	g_source_remove,
 
	NULL,
 
#if GLIB_CHECK_VERSION(2,14,0)
 
	g_timeout_add_seconds,
 
#else
 
	NULL,
 
#endif
 

	
 
	NULL,
 
	NULL,
 
	NULL
 
};
 

	
 
#ifdef WITH_LIBEVENT
 

	
backends/libpurple/main.cpp
Show inline comments
 
#include "utils.h"
 

	
 
#include "glib.h"
 
#include "purple.h"
 
#include <algorithm>
 
#include <iostream>
 

	
 
#include "transport/networkplugin.h"
 
#include "transport/logging.h"
 
#include "transport/config.h"
 
#include "transport/logging.h"
 
#include "geventloop.h"
 
#include "log4cxx/logger.h"
 
#include "log4cxx/consoleappender.h"
 
#include "log4cxx/patternlayout.h"
 
#include "log4cxx/propertyconfigurator.h"
 
#include "log4cxx/helpers/properties.h"
 
#include "log4cxx/helpers/fileinputstream.h"
 
#include "log4cxx/helpers/transcoder.h"
 

	
 
// #include "valgrind/memcheck.h"
 
#include "malloc.h"
 
#include <algorithm>
 
#include "errno.h"
 

	
 
#ifdef WITH_LIBEVENT
 
#include <event.h>
 
#endif
 

	
 
#ifdef WIN32
 
#include "win32/win32dep.h"
 
#define ssize_t SSIZE_T
 
#include <process.h>
 
#define getpid _getpid
 
#endif
 

	
 
using namespace log4cxx;
 
DEFINE_LOGGER(logger_libpurple, "libpurple");
 
DEFINE_LOGGER(logger, "backend");
 

	
 
static LoggerPtr logger_libpurple = log4cxx::Logger::getLogger("libpurple");
 
static LoggerPtr logger = log4cxx::Logger::getLogger("backend");
 
int main_socket;
 
static int writeInput;
 

	
 
using namespace Transport;
 

	
 
template <class T> T fromString(const std::string &str) {
 
	T i;
 
	std::istringstream os(str);
 
	os >> i;
 
	return i;
 
}
 

	
 
template <class T> std::string stringOf(T object) {
 
	std::ostringstream os;
 
	os << object;
 
	return (os.str());
 
}
 

	
 
static void transportDataReceived(gpointer data, gint source, PurpleInputCondition cond);
 

	
 
class SpectrumNetworkPlugin;
 

	
 
GKeyFile *keyfile;
 
SpectrumNetworkPlugin *np;
 

	
 
static std::string replaceAll(
 
  std::string result,
 
  const std::string& replaceWhat,
 
  const std::string& replaceWithWhat)
 
{
 
  while(1)
 
  {
 
	const int pos = result.find(replaceWhat);
 
	if (pos==-1) break;
 
	result.replace(pos,replaceWhat.size(),replaceWithWhat);
 
  }
 
  return result;
 
}
 

	
 
static std::string KEYFILE_STRING(const std::string &cat, const std::string &key, const std::string &def = "") {
 
	gchar *str = g_key_file_get_string(keyfile, cat.c_str(), key.c_str(), 0);
 
	if (!str) {
 
		return def;
 
	}
 
	std::string ret(str);
 
	g_free(str);
 

	
 
	if (ret.find("#") != std::string::npos) {
 
		ret = ret.substr(0, ret.find("#"));
 
		while(*(ret.end() - 1) == ' ') {
 
			ret.erase(ret.end() - 1);
 
		}
 
	}
 

	
 
	if (ret.find("$jid") != std::string::npos) {
 
		std::string jid = KEYFILE_STRING("service", "jid");
 
		ret = replaceAll(ret, "$jid", jid);
 
	}
 
	return ret;
 
}
 

	
 
#define KEYFILE_BOOL(CAT, KEY) g_key_file_get_boolean(keyfile, CAT, KEY, 0)
 

	
 
static gchar *host = NULL;
 
static int port = 10000;
 

	
 
struct FTData {
 
	unsigned long id;
 
	unsigned long timer;
 
	bool paused;
 
};
 

	
 
static GOptionEntry options_entries[] = {
 
	{ "host", 'h', 0, G_OPTION_ARG_STRING, &host, "Host to connect to", NULL },
 
	{ "port", 'p', 0, G_OPTION_ARG_INT, &port, "Port to connect to", NULL },
 
	{ NULL, 0, 0, G_OPTION_ARG_NONE, NULL, "", NULL }
 
};
 

	
 
static void *notify_user_info(PurpleConnection *gc, const char *who, PurpleNotifyUserInfo *user_info);
 

	
 
static gboolean ft_ui_ready(void *data) {
 
	PurpleXfer *xfer = (PurpleXfer *) data;
 
	FTData *ftdata = (FTData *) xfer->ui_data;
 
	ftdata->timer = 0;
 
	purple_xfer_ui_ready((PurpleXfer *) data);
 
	return FALSE;
 
}
 

	
 
struct authRequest {
 
	PurpleAccountRequestAuthorizationCb authorize_cb;
 
	PurpleAccountRequestAuthorizationCb deny_cb;
 
	void *user_data;
 
	std::string who;
 
	PurpleAccount *account;
 
	std::string mainJID;	// JID of user connected with this request
 
};
 
@@ -1555,168 +1550,136 @@ static bool initPurple() {
 
		purple_prefs_set_string("/purple/away/idle_reporting", "system");
 

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

	
 

	
 
// 		purple_signal_connect(purple_conversations_get_handle(), "received-im-msg", &conversation_handle, PURPLE_CALLBACK(newMessageReceived), NULL);
 
		purple_signal_connect(purple_conversations_get_handle(), "buddy-typing", &conversation_handle, PURPLE_CALLBACK(buddyTyping), NULL);
 
		purple_signal_connect(purple_conversations_get_handle(), "buddy-typed", &conversation_handle, PURPLE_CALLBACK(buddyTyped), NULL);
 
		purple_signal_connect(purple_conversations_get_handle(), "buddy-typing-stopped", &conversation_handle, PURPLE_CALLBACK(buddyTypingStopped), NULL);
 
		purple_signal_connect(purple_blist_get_handle(), "buddy-privacy-changed", &conversation_handle, PURPLE_CALLBACK(buddyPrivacyChanged), NULL);
 
		purple_signal_connect(purple_conversations_get_handle(), "got-attention", &conversation_handle, PURPLE_CALLBACK(gotAttention), NULL);
 
		purple_signal_connect(purple_connections_get_handle(), "signed-on", &blist_handle,PURPLE_CALLBACK(signed_on), NULL);
 
// 		purple_signal_connect(purple_blist_get_handle(), "buddy-removed", &blist_handle,PURPLE_CALLBACK(buddyRemoved), NULL);
 
// 		purple_signal_connect(purple_blist_get_handle(), "buddy-signed-on", &blist_handle,PURPLE_CALLBACK(buddySignedOn), NULL);
 
// 		purple_signal_connect(purple_blist_get_handle(), "buddy-signed-off", &blist_handle,PURPLE_CALLBACK(buddySignedOff), NULL);
 
// 		purple_signal_connect(purple_blist_get_handle(), "buddy-status-changed", &blist_handle,PURPLE_CALLBACK(buddyStatusChanged), NULL);
 
		purple_signal_connect(purple_blist_get_handle(), "blist-node-removed", &blist_handle,PURPLE_CALLBACK(NodeRemoved), NULL);
 
// 		purple_signal_connect(purple_conversations_get_handle(), "chat-topic-changed", &conversation_handle, PURPLE_CALLBACK(conv_chat_topic_changed), NULL);
 
		static int xfer_handle;
 
		purple_signal_connect(purple_xfers_get_handle(), "file-send-start", &xfer_handle, PURPLE_CALLBACK(fileSendStart), NULL);
 
		purple_signal_connect(purple_xfers_get_handle(), "file-recv-start", &xfer_handle, PURPLE_CALLBACK(fileRecvStart), NULL);
 
		purple_signal_connect(purple_xfers_get_handle(), "file-recv-request", &xfer_handle, PURPLE_CALLBACK(newXfer), NULL);
 
		purple_signal_connect(purple_xfers_get_handle(), "file-recv-complete", &xfer_handle, PURPLE_CALLBACK(XferReceiveComplete), NULL);
 
		purple_signal_connect(purple_xfers_get_handle(), "file-send-complete", &xfer_handle, PURPLE_CALLBACK(XferSendComplete), NULL);
 
// 
 
// 		purple_commands_init();
 

	
 
	}
 
	return ret;
 
}
 

	
 

	
 
static void transportDataReceived(gpointer data, gint source, PurpleInputCondition cond) {
 
	if (cond & PURPLE_INPUT_READ) {
 
		char buffer[65535];
 
		char *ptr = buffer;
 
		ssize_t n = read(source, ptr, sizeof(buffer));
 
		if (n <= 0) {
 
			LOG4CXX_INFO(logger, "Diconnecting from spectrum2 server");
 
			exit(errno);
 
		}
 
		std::string d = std::string(buffer, n);
 
		np->handleDataRead(d);
 
	}
 
	else {
 
		if (writeInput != 0) {
 
			purple_input_remove(writeInput);
 
			writeInput = 0;
 
		}
 
		np->readyForData();
 
	}
 
}
 

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

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

	
 
#if GLIB_CHECK_VERSION(2,14,0)
 
	std::cout << g_option_context_get_help(context, FALSE, NULL);
 
#else
 
	std::cout << "Usage: spectrum <configuration_file.cfg>\n";
 
	std::cout << "See \"man spectrum\" for more info.\n";
 
#endif
 
		
 
#endif
 
	}
 
	else {
 
#ifndef WIN32
 
		signal(SIGPIPE, SIG_IGN);
 

	
 
		if (signal(SIGCHLD, spectrum_sigchld_handler) == SIG_ERR) {
 
			std::cout << "SIGCHLD handler can't be set\n";
 
			g_option_context_free(context);
 
			return -1;
 
		}
 
#endif
 
		keyfile = g_key_file_new ();
 
		if (!g_key_file_load_from_file (keyfile, argv[1], (GKeyFileFlags) 0, 0)) {
 
			std::cout << "Can't open " << argv[1] << " configuration file.\n";
 
			return 1;
 
		}
 

	
 
		if (KEYFILE_STRING("logging", "backend_config").empty()) {
 
			LoggerPtr root = log4cxx::Logger::getRootLogger();
 
#ifndef _MSC_VER
 
			root->addAppender(new ConsoleAppender(new PatternLayout("%d %-5p %c: %m%n")));
 
#else
 
			root->addAppender(new ConsoleAppender(new PatternLayout(L"%d %-5p %c: %m%n")));
 
#endif
 
		}
 
		else {
 
			log4cxx::helpers::Properties p;
 
			log4cxx::helpers::FileInputStream *istream = NULL;
 
			try {
 
				istream = new log4cxx::helpers::FileInputStream(KEYFILE_STRING("logging", "backend_config"));
 
			}
 
			catch(log4cxx::helpers::IOException &ex) {
 
				std::cerr << "Can't create FileInputStream logger instance: " << ex.what() << "\n";
 
			}
 
			catch (...) {
 
				std::cerr << "Can't create FileInputStream logger instance\n";
 
			}
 

	
 
			if (!istream) {
 
				return 1;
 
			}
 

	
 
			p.load(istream);
 
			LogString pid, jid;
 
			log4cxx::helpers::Transcoder::decode(stringOf(getpid()), pid);
 
			log4cxx::helpers::Transcoder::decode(KEYFILE_STRING("service", "jid"), jid);
 
#ifdef _MSC_VER
 
			p.setProperty(L"pid", pid);
 
			p.setProperty(L"jid", jid);
 
#else
 
			p.setProperty("pid", pid);
 
			p.setProperty("jid", jid);
 
#endif
 
			log4cxx::PropertyConfigurator::configure(p);
 
		Config config;
 
		if (!config.load(argv[1])) {
 
			std::cerr << "Can't open " << argv[1] << " configuration file.\n";
 
			return 1;
 
		}
 
		Logging::initBackendLogging(&config);
 

	
 
		initPurple();
 

	
 
		main_socket = create_socket(host, port);
 
		purple_input_add(main_socket, PURPLE_INPUT_READ, &transportDataReceived, NULL);
 
		purple_timeout_add_seconds(30, pingTimeout, NULL);
 

	
 
		np = new SpectrumNetworkPlugin();
 
		bool libev = KEYFILE_STRING("service", "eventloop") == "libev";
 

	
 
		GMainLoop *m_loop;
 
#ifdef WITH_LIBEVENT
 
		if (!libev) {
 
			m_loop = g_main_loop_new(NULL, FALSE);
 
		}
 
		else {
 
			event_init();
 
		}
 
#endif
 
		m_loop = g_main_loop_new(NULL, FALSE);
 

	
 
		if (m_loop) {
 
			g_main_loop_run(m_loop);
 
		}
 
#ifdef WITH_LIBEVENT
 
		else {
 
			event_loop(0);
 
		}
 
#endif
 
	}
 

	
 
	g_option_context_free(context);
 
	return 0;
 
}
backends/skype/main.cpp
Show inline comments
 
#include "glib.h"
 
#include <iostream>
 

	
 
#include "transport/config.h"
 
#include "transport/logging.h"
 
#include "transport/transport.h"
 
#include "transport/usermanager.h"
 
#include "transport/memoryusage.h"
 
#include "transport/logger.h"
 
#include "transport/sqlite3backend.h"
 
#include "transport/userregistration.h"
 
#include "transport/user.h"
 
#include "transport/storagebackend.h"
 
#include "transport/rostermanager.h"
 
#include "transport/conversation.h"
 
#include "transport/networkplugin.h"
 
#include "transport/logger.h"
 
#include <boost/filesystem.hpp>
 
#include "log4cxx/logger.h"
 
#include "log4cxx/consoleappender.h"
 
#include "log4cxx/patternlayout.h"
 
#include "log4cxx/propertyconfigurator.h"
 
#include "log4cxx/helpers/properties.h"
 
#include "log4cxx/helpers/fileinputstream.h"
 
#include "sys/wait.h"
 
#include "sys/signal.h"
 
// #include "valgrind/memcheck.h"
 
#include "malloc.h"
 
#include <dbus-1.0/dbus/dbus-glib-lowlevel.h>
 

	
 

	
 
using namespace log4cxx;
 

	
 
static LoggerPtr logger = Logger::getLogger("backend");
 
DEFINE_LOGGER(logger, "backend");
 

	
 
using namespace Transport;
 

	
 
class SpectrumNetworkPlugin;
 

	
 
#define GET_RESPONSE_DATA(RESP, DATA) ((RESP.find(std::string(DATA) + " ") != std::string::npos) ? RESP.substr(RESP.find(DATA) + strlen(DATA) + 1) : "");
 
#define GET_PROPERTY(VAR, OBJ, WHICH, PROP) std::string VAR = sk->send_command(std::string("GET ") + OBJ + " " + WHICH + " " + PROP); \
 
					try {\
 
						VAR = GET_RESPONSE_DATA(VAR, PROP);\
 
					}\
 
					catch (std::out_of_range& oor) {\
 
						VAR="";\
 
					}
 
					
 

	
 

	
 
SpectrumNetworkPlugin *np;
 

	
 
static gboolean nodaemon = FALSE;
 
static gchar *logfile = NULL;
 
static gchar *lock_file = NULL;
 
static gchar *host = NULL;
 
static int port = 10000;
 
static gboolean ver = FALSE;
 
static gboolean list_purple_settings = FALSE;
 

	
 
int m_sock;
 
static int writeInput;
 

	
 
static GOptionEntry options_entries[] = {
 
	{ "nodaemon", 'n', 0, G_OPTION_ARG_NONE, &nodaemon, "Disable background daemon mode", NULL },
 
	{ "logfile", 'l', 0, G_OPTION_ARG_STRING, &logfile, "Set file to log", NULL },
 
	{ "pidfile", 'p', 0, G_OPTION_ARG_STRING, &lock_file, "File where to write transport PID", NULL },
 
	{ "version", 'v', 0, G_OPTION_ARG_NONE, &ver, "Shows Spectrum version", NULL },
 
	{ "list-purple-settings", 's', 0, G_OPTION_ARG_NONE, &list_purple_settings, "Lists purple settings which can be used in config file", NULL },
 
	{ "host", 'h', 0, G_OPTION_ARG_STRING, &host, "Host to connect to", NULL },
 
	{ "port", 'p', 0, G_OPTION_ARG_INT, &port, "Port to connect to", NULL },
 
	{ NULL, 0, 0, G_OPTION_ARG_NONE, NULL, "", NULL }
 
};
 

	
 
DBusHandlerResult skype_notify_handler(DBusConnection *connection, DBusMessage *message, gpointer user_data);
 

	
 
static pbnetwork::StatusType getStatus(const std::string &st) {
 
	pbnetwork::StatusType status = pbnetwork::STATUS_ONLINE;
 
	if (st == "SKYPEOUT" || st == "OFFLINE") {
 
		status = pbnetwork::STATUS_NONE;
 
	}
 
	else if (st == "DND") {
 
		status = pbnetwork::STATUS_DND;
 
	}
 
	else if (st == "NA") {
 
		status = pbnetwork::STATUS_XA;
 
	}
 
	else if (st == "AWAY") {
 
		status = pbnetwork::STATUS_AWAY;
 
	}
 
	return status;
 
}
 

	
 
class Skype {
 
	public:
 
		Skype(const std::string &user, const std::string &username, const std::string &password);
 
		~Skype() { LOG4CXX_INFO(logger, "Skype instance desctuctor"); logout(); }
 
		void login();
 
		void logout();
 
		std::string send_command(const std::string &message);
 

	
 
		const std::string &getUser() {
 
			return m_user;
 
		}
 

	
 
		const std::string &getUsername() {
 
			return m_username;
 
		}
 

	
 
		bool createDBusProxy();
 
		bool loadSkypeBuddies();
 

	
 
		int getPid() {
 
			return (int) m_pid;
 
		}
 

	
 
	private:
 
		std::string m_username;
 
		std::string m_password;
 
		GPid m_pid;
 
		DBusGConnection *m_connection;
 
		DBusGProxy *m_proxy;
 
		std::string m_user;
 
		int m_timer;
 
		int m_counter;
 
		int fd_output;
 
};
 

	
 
class SpectrumNetworkPlugin : public NetworkPlugin {
 
	public:
backends/smstools3/main.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 "transport/config.h"
 
#include "transport/logging.h"
 
#include "transport/networkplugin.h"
 
#include "transport/sqlite3backend.h"
 
#include "transport/mysqlbackend.h"
 
#include "transport/pqxxbackend.h"
 
#include "transport/storagebackend.h"
 
#include "Swiften/Swiften.h"
 
#include <boost/filesystem.hpp>
 
#include "unistd.h"
 
#include "signal.h"
 
#include "sys/wait.h"
 
#include "sys/signal.h"
 
#include <fstream>
 
#include <streambuf>
 

	
 
Swift::SimpleEventLoop *loop_;
 

	
 
#include "log4cxx/logger.h"
 
#include "log4cxx/consoleappender.h"
 
#include "log4cxx/patternlayout.h"
 
#include "log4cxx/propertyconfigurator.h"
 
#include "log4cxx/helpers/properties.h"
 
#include "log4cxx/helpers/fileinputstream.h"
 
#include "log4cxx/helpers/transcoder.h"
 
#include <boost/filesystem.hpp>
 
#include <boost/algorithm/string.hpp>
 

	
 
using namespace boost::filesystem;
 

	
 
using namespace boost::program_options;
 
using namespace Transport;
 

	
 
using namespace log4cxx;
 

	
 
static LoggerPtr logger = log4cxx::Logger::getLogger("SMSNetworkPlugin");
 
DEFINE_LOGGER(logger, "SMSNetworkPlugin");
 

	
 
#define INTERNAL_USER "/sms@backend@internal@user"
 

	
 
class SMSNetworkPlugin;
 
SMSNetworkPlugin * np = NULL;
 
StorageBackend *storageBackend;
 

	
 
class SMSNetworkPlugin : public NetworkPlugin {
 
	public:
 
		Swift::BoostNetworkFactories *m_factories;
 
		Swift::BoostIOServiceThread m_boostIOServiceThread;
 
		boost::shared_ptr<Swift::Connection> m_conn;
 
		Swift::Timer::ref m_timer;
 
		int m_internalUser;
 

	
 
		SMSNetworkPlugin(Config *config, Swift::SimpleEventLoop *loop, const std::string &host, int port) : NetworkPlugin() {
 
			this->config = config;
 
			m_factories = new Swift::BoostNetworkFactories(loop);
 
			m_conn = m_factories->getConnectionFactory()->createConnection();
 
			m_conn->onDataRead.connect(boost::bind(&SMSNetworkPlugin::_handleDataRead, this, _1));
 
			m_conn->connect(Swift::HostAddressPort(Swift::HostAddress(host), port));
 
// 			m_conn->onConnectFinished.connect(boost::bind(&FrotzNetworkPlugin::_handleConnected, this, _1));
 
// 			m_conn->onDisconnected.connect(boost::bind(&FrotzNetworkPlugin::handleDisconnected, this));
 

	
 
			LOG4CXX_INFO(logger, "Starting the plugin.");
 

	
 
			m_timer = m_factories->getTimerFactory()->createTimer(5000);
 
			m_timer->onTick.connect(boost::bind(&SMSNetworkPlugin::handleSMSDir, this));
 
			m_timer->start();
 

	
 
			// We're reusing our database model here. Buddies of user with JID INTERNAL_USER are there
 
			// to match received GSM messages from number N with the XMPP users who sent message to number N.
 
			// BuddyName = GSM number
 
			// Alias = XMPP user JID to which the messages from this number is sent to.
 
			// TODO: This should be per Modem!!!
 
			UserInfo info;
 
			info.jid = INTERNAL_USER;
 
			info.password = "";
 
			storageBackend->setUser(info);
 
			storageBackend->getUser(INTERNAL_USER, info);
 
			m_internalUser = info.id;
 
		}
 

	
 

	
 
		void handleSMS(const std::string &sms) {
 
			LOG4CXX_INFO(logger, "Handling SMS " << sms << ".")
 
			std::ifstream t(sms.c_str());
 
			std::string str;
 

	
 
			t.seekg(0, std::ios::end);
 
			str.reserve(t.tellg());
 
			t.seekg(0, std::ios::beg);
 

	
 
			str.assign((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
 

	
 
			std::string from = "";
 
			std::string msg = "";
 
			while(str.find("\n") != std::string::npos) {
 
				std::string line = str.substr(0, str.find("\n"));
 
				if (line.find("From: ") == 0) {
 
					from = line.substr(strlen("From: "));
 
				}
 
				else if (line.empty()) {
 
					msg = str.substr(1);
 
					break;
 
				}
 
				str = str.substr(str.find("\n") + 1);
 
			}
 

	
 
			std::list<BuddyInfo> roster;
 
			storageBackend->getBuddies(m_internalUser, roster);
 

	
 
			std::string to;
 
			BOOST_FOREACH(BuddyInfo &b, roster) {
 
				if (b.legacyName == from) {
 
					to = b.alias;
 
				}
 
			}
 

	
 
			if (to.empty()) {
 
				LOG4CXX_WARN(logger, "Received SMS from " << from << ", but this number is not associated with any XMPP user.");
 
			}
 

	
 
			LOG4CXX_INFO(logger, "Forwarding SMS from " << from << " to " << to << ".");
 
			handleMessage(to, from, msg);
 
		}
 

	
 
		void handleSMSDir() {
 
			std::string dir = "/var/spool/sms/incoming/";
 
			if (config->getUnregistered().find("backend.incoming_dir") != config->getUnregistered().end()) {
 
				dir = config->getUnregistered().find("backend.incoming_dir")->second;
 
			}
 
			LOG4CXX_INFO(logger, "Checking directory " << dir << " for incoming SMS.");
 

	
 
			path p(dir);
 
			directory_iterator end_itr;
backends/template/main.cpp
Show inline comments
 
// Transport includes
 
#include "transport/config.h"
 
#include "transport/networkplugin.h"
 
#include "transport/logging.h"
 

	
 
// Swiften
 
#include "Swiften/Swiften.h"
 

	
 
// for signal handler
 
#include "unistd.h"
 
#include "signal.h"
 
#include "sys/wait.h"
 
#include "sys/signal.h"
 

	
 
// Log4cxx
 
#include "log4cxx/logger.h"
 
#include "log4cxx/consoleappender.h"
 
#include "log4cxx/patternlayout.h"
 
#include "log4cxx/propertyconfigurator.h"
 
#include "log4cxx/helpers/properties.h"
 
#include "log4cxx/helpers/fileinputstream.h"
 
#include "log4cxx/helpers/transcoder.h"
 

	
 
// Boost
 
#include <boost/algorithm/string.hpp>
 
using namespace boost::filesystem;
 
using namespace boost::program_options;
 
using namespace Transport;
 

	
 
// log4cxx main logger
 
using namespace log4cxx;
 
static LoggerPtr logger = log4cxx::Logger::getLogger("Backend Template");
 
DEFINE_LOGGER(logger, "Backend Template");
 

	
 
// eventloop
 
Swift::SimpleEventLoop *loop_;
 

	
 
// Plugin
 
class TemplatePlugin;
 
TemplatePlugin * np = NULL;
 

	
 
class TemplatePlugin : public NetworkPlugin {
 
	public:
 
		Swift::BoostNetworkFactories *m_factories;
 
		Swift::BoostIOServiceThread m_boostIOServiceThread;
 
		boost::shared_ptr<Swift::Connection> m_conn;
 

	
 
		TemplatePlugin(Config *config, Swift::SimpleEventLoop *loop, const std::string &host, int port) : NetworkPlugin() {
 
			this->config = config;
 
			m_factories = new Swift::BoostNetworkFactories(loop);
 
			m_conn = m_factories->getConnectionFactory()->createConnection();
 
			m_conn->onDataRead.connect(boost::bind(&TemplatePlugin::_handleDataRead, this, _1));
 
			m_conn->connect(Swift::HostAddressPort(Swift::HostAddress(host), port));
 

	
 
			LOG4CXX_INFO(logger, "Starting the plugin.");
 
		}
 

	
 
		// NetworkPlugin uses this method to send the data to networkplugin server
 
		void sendData(const std::string &string) {
 
			m_conn->write(Swift::createSafeByteArray(string));
 
		}
 

	
 
		// This method has to call handleDataRead with all received data from network plugin server
 
		void _handleDataRead(boost::shared_ptr<Swift::SafeByteArray> data) {
 
			std::string d(data->begin(), data->end());
 
			handleDataRead(d);
 
		}
 

	
 
		void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) {
 
			handleConnected(user);
 
		}
 

	
 
		void handleLogoutRequest(const std::string &user, const std::string &legacyName) {
 
		}
 

	
 
		void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = "") {
 
			LOG4CXX_INFO(logger, "Sending message from " << user << " to " << legacyName << ".");
 
		}
 

	
 
		void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector<std::string> &groups) {
 
			LOG4CXX_INFO(logger, user << ": Added buddy " << buddyName << ".");
 
			handleBuddyChanged(user, buddyName, alias, groups, pbnetwork::STATUS_ONLINE);
 
		}
 

	
 
		void handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector<std::string> &groups) {
 

	
 
		}
 

	
 
	private:
 
		Config *config;
 
};
 

	
 
static void spectrum_sigchld_handler(int sig)
 
{
 
	int status;
 
	pid_t pid;
 

	
 
	do {
 
		pid = waitpid(-1, &status, WNOHANG);
 
	} while (pid != 0 && pid != (pid_t)-1);
 

	
 
	if ((pid == (pid_t) - 1) && (errno != ECHILD)) {
 
		char errmsg[BUFSIZ];
 
		snprintf(errmsg, BUFSIZ, "Warning: waitpid() returned %d", pid);
 
		perror(errmsg);
 
	}
 
}
 

	
 

	
 
int main (int argc, char* argv[]) {
 
	std::string host;
 
	int port;
 

	
 
	if (signal(SIGCHLD, spectrum_sigchld_handler) == SIG_ERR) {
 
		std::cout << "SIGCHLD handler can't be set\n";
 
		return -1;
 
	}
 

	
 
	boost::program_options::options_description desc("Usage: spectrum [OPTIONS] <config_file.cfg>\nAllowed options");
 
	desc.add_options()
 
		("host,h", value<std::string>(&host), "host")
 
		("port,p", value<int>(&port), "port")
 
		;
 
	try
 
	{
 
		boost::program_options::variables_map vm;
 
		boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm);
 
		boost::program_options::notify(vm);
 
	}
 
	catch (std::runtime_error& e)
 
	{
 
		std::cout << desc << "\n";
 
		exit(1);
 
	}
 
	catch (...)
 
	{
 
		std::cout << desc << "\n";
 
		exit(1);
 
	}
 

	
 

	
 
	if (argc < 5) {
 
		return 1;
 
	}
 

	
 
	Config config;
 
	if (!config.load(argv[5])) {
 
		std::cerr << "Can't open " << argv[1] << " configuration file.\n";
 
		return 1;
 
	}
 

	
 
	if (CONFIG_STRING(&config, "logging.backend_config").empty()) {
 
		LoggerPtr root = log4cxx::Logger::getRootLogger();
 
#ifndef _MSC_VER
 
		root->addAppender(new ConsoleAppender(new PatternLayout("%d %-5p %c: %m%n")));
 
#else
 
		root->addAppender(new ConsoleAppender(new PatternLayout(L"%d %-5p %c: %m%n")));
 
#endif
 
	}
 
	else {
 
		log4cxx::helpers::Properties p;
 
		log4cxx::helpers::FileInputStream *istream = new log4cxx::helpers::FileInputStream(CONFIG_STRING(&config, "logging.backend_config"));
 
		p.load(istream);
 
		LogString pid, jid;
 
		log4cxx::helpers::Transcoder::decode(boost::lexical_cast<std::string>(getpid()), pid);
 
		log4cxx::helpers::Transcoder::decode(CONFIG_STRING(&config, "service.jid"), jid);
 
#ifdef _MSC_VER
 
		p.setProperty(L"pid", pid);
 
		p.setProperty(L"jid", jid);
 
#else
 
		p.setProperty("pid", pid);
 
		p.setProperty("jid", jid);
 
#endif
 
		log4cxx::PropertyConfigurator::configure(p);
 
	}
 
	Logging::initBackendLogging(&config);
 

	
 
	Swift::SimpleEventLoop eventLoop;
 
	loop_ = &eventLoop;
 
	np = new TemplatePlugin(&config, &eventLoop, host, port);
 
	loop_->run();
 

	
 
	return 0;
 
}
include/Swiften/TLS/OpenSSL/OpenSSLServerContext.cpp
Show inline comments
 
/*
 
 * Copyright (c) 2010 Remko Tronçon
 
 * Licensed under the GNU General Public License v3.
 
 * See Documentation/Licenses/GPLv3.txt for more information.
 
 */
 
#include "Swiften/Base/Platform.h"
 

	
 
#ifdef SWIFTEN_PLATFORM_WINDOWS
 
#include <windows.h>
 
#include <wincrypt.h>
 
#endif
 

	
 
#include <vector>
 
#include <openssl/err.h>
 
#include <openssl/pkcs12.h>
 

	
 
#include "log4cxx/logger.h"
 
#include "log4cxx/consoleappender.h"
 
#include "log4cxx/patternlayout.h"
 
#include "log4cxx/propertyconfigurator.h"
 
using namespace log4cxx;
 
static LoggerPtr logger = Logger::getLogger("OpenSSLServerContext");
 
#include "transport/logging.h"
 
DEFINE_LOGGER(logger, "OpenSSLServerContext");
 

	
 

	
 
#include "Swiften/TLS/OpenSSL/OpenSSLServerContext.h"
 
#include "Swiften/TLS/OpenSSL/OpenSSLCertificate.h"
 
#include "Swiften/TLS/PKCS12Certificate.h"
 
#ifndef _MSC_VER
 
#pragma GCC diagnostic ignored "-Wold-style-cast"
 
#endif
 
namespace Swift {
 

	
 
static const int MAX_FINISHED_SIZE = 4096;
 
static const int SSL_READ_BUFFERSIZE = 8192;
 

	
 
static void freeX509Stack(STACK_OF(X509)* stack) {
 
	sk_X509_free(stack);
 
}
 

	
 
// static int _sx_ssl_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
 
// 	return 1;
 
// }
 

	
 
OpenSSLServerContext::OpenSSLServerContext() : state_(Start), context_(0), handle_(0), readBIO_(0), writeBIO_(0) {
 
	ensureLibraryInitialized();
 
	context_ = SSL_CTX_new(SSLv23_server_method());
 
// 	SSL_CTX_set_verify(context_, SSL_VERIFY_PEER, _sx_ssl_verify_callback);
 

	
 
	// Load system certs
 
#if defined(SWIFTEN_PLATFORM_WINDOWS)
 
	X509_STORE* store = SSL_CTX_get_cert_store(context_);
 
	HCERTSTORE systemStore = CertOpenSystemStore(0, "ROOT");
 
	if (systemStore) {
 
		PCCERT_CONTEXT certContext = NULL;
 
		while (true) {
 
			certContext = CertFindCertificateInStore(systemStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_ANY, NULL, certContext);
 
			if (!certContext) {
 
				break;
 
			}
 
			ByteArray certData(createByteArray(certContext->pbCertEncoded, certContext->cbCertEncoded));
 
			OpenSSLCertificate cert(certData);
 
			if (store && cert.getInternalX509()) {
 
				X509_STORE_add_cert(store, cert.getInternalX509().get());
 
			}
 
		}
 
	}
 
#elif !defined(SWIFTEN_PLATFORM_MACOSX)
 
	SSL_CTX_load_verify_locations(context_, NULL, "/etc/ssl/certs");
 
#endif
 
}
 

	
 
OpenSSLServerContext::~OpenSSLServerContext() {
 
	SSL_free(handle_);
 
	SSL_CTX_free(context_);
 
}
 

	
 
void OpenSSLServerContext::ensureLibraryInitialized() {
 
	static bool isLibraryInitialized = false;
 
	if (!isLibraryInitialized) {
 
		SSL_load_error_strings();
 
		SSL_library_init();
 
		OpenSSL_add_all_algorithms();
 

	
 
		// Disable compression
 
		/*
 
		STACK_OF(SSL_COMP)* compressionMethods = SSL_COMP_get_compression_methods();
 
		sk_SSL_COMP_zero(compressionMethods);*/
 

	
 
		isLibraryInitialized = true;
 
	}
 
}
 

	
 
void OpenSSLServerContext::connect() {
 
	handle_ = SSL_new(context_);
 
	// Ownership of BIOs is ransferred
 
	readBIO_ = BIO_new(BIO_s_mem());
 
	writeBIO_ = BIO_new(BIO_s_mem());
 
	SSL_set_bio(handle_, readBIO_, writeBIO_);
 

	
 
	state_ = Connecting;
 
	doConnect();
 
}
 

	
 
void OpenSSLServerContext::doConnect() {
 
	int connectResult = SSL_accept(handle_);
 
	int error = SSL_get_error(handle_, connectResult);
 
// 	std::cout << "DO CONNECT\n";
 
	switch (error) {
 
		case SSL_ERROR_NONE: {
 
			if (SSL_is_init_finished(handle_)) {
 
// 				std::cout << "FINISHED\n";
 
				state_ = Connected;
 
				//std::cout << x->name << std::endl;
 
				//const char* comp = SSL_get_current_compression(handle_);
 
				//std::cout << "Compression: " << SSL_COMP_get_name(comp) << std::endl;
 
				onConnected();
 
				ERR_print_errors_fp(stdout);
 
				sendPendingDataToNetwork();
include/transport/logging.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 <stdio.h>
 
#include <stdlib.h>
 
#include <vector>
 
#include <string>
 
#include <iostream>
 

	
 
#ifdef WITH_LOG4CXX
 
#include "log4cxx/logger.h"
 
#include "log4cxx/consoleappender.h"
 
#include "log4cxx/patternlayout.h"
 
#include "log4cxx/propertyconfigurator.h"
 
#include "log4cxx/helpers/properties.h"
 
#include "log4cxx/helpers/fileinputstream.h"
 
#include "log4cxx/helpers/transcoder.h"
 
#include "log4cxx/logger.h"
 

	
 
#define DEFINE_LOGGER(VAR, NAME) static log4cxx::LoggerPtr VAR = log4cxx::Logger::getLogger(NAME);
 

	
 
using namespace log4cxx;
 
#else
 
#define DEFINE_LOGGER(VARIABLE, NAME) static const char *VARIABLE = NAME;
 

	
 
#define LOG4CXX_ERROR(LOGGER, DATA) std::cerr << "E: <" << LOGGER << "> " << DATA << "\n";
 
#define LOG4CXX_WARN(LOGGER, DATA) std::cout << "W: <" << LOGGER << "> " << DATA << "\n";
 
#define LOG4CXX_INFO(LOGGER, DATA) std::cout << "I: <" << LOGGER << "> " << DATA << "\n";
 
#endif
 

	
 
namespace Transport {
 

	
 
class Config;
 

	
 
namespace Logging {
 

	
 
void initBackendLogging(Config *config);
 
void initMainLogging(Config *config);
 

	
 
}
 

	
 
}
plugin/cpp/CMakeLists.txt
Show inline comments
 
cmake_minimum_required(VERSION 2.6)
 
FILE(GLOB SRC *.cpp *.h)
 
FILE(GLOB HEADERS ../include/transport/*.h)
 
 
set(EXTRA_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/../../src/memoryusage.cpp)
 
set(EXTRA_SOURCES ${EXTRA_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/../../src/logging.cpp)
 
set(EXTRA_SOURCES ${EXTRA_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/../../src/config.cpp)
 
set(EXTRA_SOURCES ${EXTRA_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/../../include/transport/protocol.pb.cc)
 
 
if (NOT WIN32)
 
	ADD_LIBRARY(transport-plugin SHARED ${HEADERS} ${SRC} ${PROTOBUF_SRC} ${PROTOBUF_HDRS} ${EXTRA_SOURCES})
 
else()
 
	ADD_LIBRARY(transport-plugin STATIC ${HEADERS} ${SRC} ${PROTOBUF_SRC} ${PROTOBUF_HDRS} ${EXTRA_SOURCES})
 
endif()
 
ADD_DEPENDENCIES(transport-plugin pb)
 
SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/../../include/transport/protocol.pb.cc PROPERTIES GENERATED 1)
 
 
if (CMAKE_COMPILER_IS_GNUCXX)
 
	ADD_DEFINITIONS(-fPIC)
 
endif()
 
 
if (NOT WIN32)
 
	TARGET_LINK_LIBRARIES(transport-plugin ${PROTOBUF_LIBRARIES} ${LOG4CXX_LIBRARIES})
 
	TARGET_LINK_LIBRARIES(transport-plugin ${PROTOBUF_LIBRARIES} ${LOG4CXX_LIBRARIES} ${Boost_LIBRARIES})
 
else()
 
	TARGET_LINK_LIBRARIES(transport-plugin ${PROTOBUF_LIBRARIES} ${LOG4CXX_LIBRARIES} ws2_32.lib)
 
	TARGET_LINK_LIBRARIES(transport-plugin ${PROTOBUF_LIBRARIES} ${LOG4CXX_LIBRARIES} ${Boost_LIBRARIES} ws2_32.lib)
 
endif() 
 
 
SET_TARGET_PROPERTIES(transport-plugin PROPERTIES
 
      VERSION ${TRANSPORT_VERSION} SOVERSION ${TRANSPORT_VERSION}
 
)
 
 
INSTALL(TARGETS transport-plugin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib COMPONENT libraries)
 
 
#CONFIGURE_FILE(transport.pc.in "${CMAKE_CURRENT_BINARY_DIR}/transport.pc")
 
#INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/transport.pc" DESTINATION lib/pkgconfig)
plugin/cpp/networkplugin.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/networkplugin.h"
 
#include "log4cxx/logger.h"
 
#include "log4cxx/basicconfigurator.h"
 
#include "transport/memoryusage.h"
 
#include "transport/logging.h"
 

	
 
#include <sstream>
 

	
 
#ifndef WIN32
 
#include <arpa/inet.h>
 
#else 
 
#include <winsock2.h>
 
#include <stdint.h>
 
#include <process.h>
 
#define getpid _getpid
 
#endif
 

	
 
using namespace log4cxx;
 

	
 
static LoggerPtr logger = Logger::getLogger("NetworkPlugin");
 
DEFINE_LOGGER(logger, "NetworkPlugin");
 

	
 
namespace Transport {
 

	
 
#define WRAP(MESSAGE, TYPE) 	pbnetwork::WrapperMessage wrap; \
 
	wrap.set_type(TYPE); \
 
	wrap.set_payload(MESSAGE); \
 
	wrap.SerializeToString(&MESSAGE);
 

	
 
template <class T> std::string stringOf(T object) {
 
	std::ostringstream os;
 
	os << object;
 
	return (os.str());
 
}
 

	
 
NetworkPlugin::NetworkPlugin() {
 
	m_pingReceived = false;
 

	
 
	double shared;
 
#ifndef WIN32
 
	process_mem_usage(shared, m_init_res);
 
#endif
 
}
 

	
 
NetworkPlugin::~NetworkPlugin() {
 
}
 

	
 
void NetworkPlugin::handleMessage(const std::string &user, const std::string &legacyName, const std::string &msg, const std::string &nickname, const std::string &xhtml) {
 
	pbnetwork::ConversationMessage m;
 
	m.set_username(user);
 
	m.set_buddyname(legacyName);
 
	m.set_message(msg);
 
	m.set_nickname(nickname);
 
	m.set_xhtml(xhtml);
 

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

	
 
	WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_CONV_MESSAGE);
 

	
 
	send(message);
 
}
 

	
 
void NetworkPlugin::handleAttention(const std::string &user, const std::string &buddyName, const std::string &msg) {
 
	pbnetwork::ConversationMessage m;
 
	m.set_username(user);
 
	m.set_buddyname(buddyName);
 
	m.set_message(msg);
 

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

	
 
	WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_ATTENTION);
 

	
 
	send(message);
 
}
 

	
 
void NetworkPlugin::handleVCard(const std::string &user, unsigned int id, const std::string &legacyName, const std::string &fullName, const std::string &nickname, const std::string &photo) {
 
	pbnetwork::VCard vcard;
 
	vcard.set_username(user);
 
	vcard.set_buddyname(legacyName);
 
	vcard.set_id(id);
 
	vcard.set_fullname(fullName);
 
	vcard.set_nickname(nickname);
 
	vcard.set_photo(photo);
 

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

	
 
	WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_VCARD);
 
	send(message);
 
}
 

	
 
void NetworkPlugin::handleSubject(const std::string &user, const std::string &legacyName, const std::string &msg, const std::string &nickname) {
 
	pbnetwork::ConversationMessage m;
 
	m.set_username(user);
 
	m.set_buddyname(legacyName);
 
	m.set_message(msg);
 
	m.set_nickname(nickname);
 

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

	
 
	WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_ROOM_SUBJECT_CHANGED);
 
// 	std::cout << "SENDING MESSAGE\n";
 

	
 
	send(message);
 
}
 

	
 
void NetworkPlugin::handleBuddyChanged(const std::string &user, const std::string &buddyName, const std::string &alias,
 
			const std::vector<std::string> &groups, pbnetwork::StatusType status, const std::string &statusMessage, const std::string &iconHash, bool blocked) {
 
	pbnetwork::Buddy buddy;
 
	buddy.set_username(user);
 
	buddy.set_buddyname(buddyName);
 
	buddy.set_alias(alias);
 
	for (std::vector<std::string>::const_iterator it = groups.begin(); it != groups.end(); it++) {
 
		buddy.add_group(*it);
spectrum/src/main.cpp
Show inline comments
 
#include "transport/config.h"
 
#include "transport/transport.h"
 
#include "transport/filetransfermanager.h"
 
#include "transport/usermanager.h"
 
#include "transport/logger.h"
 
#include "transport/sqlite3backend.h"
 
#include "transport/mysqlbackend.h"
 
#include "transport/pqxxbackend.h"
 
#include "transport/userregistration.h"
 
#include "transport/networkpluginserver.h"
 
#include "transport/admininterface.h"
 
#include "transport/statsresponder.h"
 
#include "transport/usersreconnecter.h"
 
#include "transport/util.h"
 
#include "transport/gatewayresponder.h"
 
#include "transport/logging.h"
 
#include "Swiften/EventLoop/SimpleEventLoop.h"
 
#include <boost/filesystem.hpp>
 
#include <boost/algorithm/string.hpp>
 
#ifndef WIN32
 
#include "sys/signal.h"
 
#include <pwd.h>
 
#include <grp.h>
 
#include <sys/resource.h>
 
#include "libgen.h"
 
#else
 
#include <windows.h>
 
#endif
 
#include "log4cxx/logger.h"
 
#include "log4cxx/consoleappender.h"
 
#include "log4cxx/patternlayout.h"
 
#include "log4cxx/propertyconfigurator.h"
 
#include "log4cxx/helpers/properties.h"
 
#include "log4cxx/helpers/transcoder.h"
 
#include "log4cxx/helpers/fileinputstream.h"
 
#include <sys/stat.h>
 

	
 
using namespace log4cxx;
 

	
 
using namespace Transport;
 

	
 
static LoggerPtr logger = log4cxx::Logger::getLogger("Spectrum");
 
DEFINE_LOGGER(logger, "Spectrum");
 

	
 
Swift::SimpleEventLoop *eventLoop_ = NULL;
 
Component *component_ = NULL;
 
UserManager *userManager_ = NULL;
 

	
 
static void stop_spectrum() {
 
	userManager_->removeAllUsers(false);
 
	component_->stop();
 
	eventLoop_->stop();
 
}
 

	
 
static void spectrum_sigint_handler(int sig) {
 
	eventLoop_->postEvent(&stop_spectrum);
 
}
 

	
 
static void spectrum_sigterm_handler(int sig) {
 
	eventLoop_->postEvent(&stop_spectrum);
 
}
 

	
 
static void removeOldIcons(std::string iconDir) {
 
	std::vector<std::string> dirs;
 
	dirs.push_back(iconDir);
 

	
 
	boost::thread thread(boost::bind(Util::removeEverythingOlderThan, dirs, time(NULL) - 3600*24*14));
 
}
 

	
 
#ifndef WIN32
 
static void daemonize(const char *cwd, const char *lock_file) {
 
	pid_t pid, sid;
 
	FILE* lock_file_f;
 
	char process_pid[20];
 
	/* already a daemon */
 
	if ( getppid() == 1 ) return;
 

	
 
	/* Fork off the parent process */
 
	pid = fork();
 
	if (pid < 0) {
 
		exit(1);
 
	}
 
	/* If we got a good PID, then we can exit the parent process. */
 
	if (pid > 0) {
 
		if (lock_file) {
 
			/* write our pid into it & close the file. */
 
			lock_file_f = fopen(lock_file, "w+");
 
			if (lock_file_f == NULL) {
 
				std::cerr << "Cannot create lock file " << lock_file << ". Exiting\n";
 
				exit(1);
 
			}
 
			sprintf(process_pid,"%d\n",pid);
 
			if (fwrite(process_pid,1,strlen(process_pid),lock_file_f) < strlen(process_pid)) {
 
				std::cerr << "Cannot write to lock file " << lock_file << ". Exiting\n";
 
				exit(1);
 
			}
 
			fclose(lock_file_f);
 
		}
 
		exit(0);
 
	}
 

	
 
	/* Change the file mode mask */
 
	umask(0);
 

	
 
	/* Create a new SID for the child process */
 
	sid = setsid();
 
	if (sid < 0) {
 
		exit(1);
 
	}
 

	
 
	/* Change the current working directory.  This prevents the current
 
		directory from being locked; hence not being able to remove it. */
 
	if ((chdir(cwd)) < 0) {
 
		exit(1);
 
	}
 
	
 
	if (freopen( "/dev/null", "r", stdin) == NULL) {
 
		std::cout << "EE cannot open /dev/null. Exiting\n";
 
		exit(1);
 
	}
 
}
 

	
 
#endif
 

	
 
int main(int argc, char **argv)
 
{
 
	Config config;
 

	
 
	boost::program_options::variables_map vm;
 
	bool no_daemon = false;
 
	std::string config_file;
 
	std::string jid;
 
	
 

	
 
#ifndef WIN32
 
	if (signal(SIGINT, spectrum_sigint_handler) == SIG_ERR) {
 
		std::cout << "SIGINT handler can't be set\n";
 
		return -1;
 
	}
src/admininterface.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/admininterface.h"
 
#include "transport/user.h"
 
#include "transport/transport.h"
 
#include "transport/storagebackend.h"
 
#include "transport/conversationmanager.h"
 
#include "transport/rostermanager.h"
 
#include "transport/usermanager.h"
 
#include "transport/networkpluginserver.h"
 
#include "transport/logging.h"
 
#include "storageresponder.h"
 
#include "log4cxx/logger.h"
 
#include "transport/memoryusage.h"
 
#include <boost/foreach.hpp>
 

	
 
using namespace log4cxx;
 

	
 
namespace Transport {
 

	
 
static LoggerPtr logger = Logger::getLogger("AdminInterface");
 
DEFINE_LOGGER(logger, "AdminInterface");
 

	
 
static std::string getArg(const std::string &body) {
 
	std::string ret;
 
	if (body.find(" ") == std::string::npos)
 
		return ret;
 

	
 
	return body.substr(body.find(" ") + 1);
 
}
 

	
 
AdminInterface::AdminInterface(Component *component, UserManager *userManager, NetworkPluginServer *server, StorageBackend *storageBackend) {
 
	m_component = component;
 
	m_storageBackend = storageBackend;
 
	m_userManager = userManager;
 
	m_server = server;
 

	
 
	m_component->getStanzaChannel()->onMessageReceived.connect(bind(&AdminInterface::handleMessageReceived, this, _1));
 
}
 

	
 
AdminInterface::~AdminInterface() {
 
}
 

	
 
void AdminInterface::handleMessageReceived(Swift::Message::ref message) {
 
	if (!message->getTo().getNode().empty())
 
		return;
 

	
 
	if (message->getFrom().toBare().toString() != CONFIG_STRING(m_component->getConfig(), "service.admin_jid")) {
 
		LOG4CXX_WARN(logger, "Message not from admin user, but from " << message->getFrom().toBare().toString());
 
		return;
 
	}
 

	
 
	// Ignore empty messages
 
	if (message->getBody().empty()) {
 
		return;
 
	}
 

	
 
	LOG4CXX_INFO(logger, "Message from admin received");
 
	message->setTo(message->getFrom());
 
	message->setFrom(m_component->getJID());
 

	
 
	if (message->getBody() == "status") {
 
		int users = m_userManager->getUserCount();
 
		int backends = m_server->getBackendCount();
 
		message->setBody("Running (" + boost::lexical_cast<std::string>(users) + " users connected using " + boost::lexical_cast<std::string>(backends) + " backends)");
 
	}
 
	else if (message->getBody() == "online_users") {
 
		std::string lst;
 
		const std::map<std::string, User *> &users = m_userManager->getUsers();
 
		if (users.size() == 0)
 
			lst = "0";
 

	
 
		for (std::map<std::string, User *>::const_iterator it = users.begin(); it != users.end(); it ++) {
 
			lst += (*it).first + "\n";
 
		}
 

	
 
		message->setBody(lst);
 
	}
 
	else if (message->getBody() == "online_users_count") {
 
		int users = m_userManager->getUserCount();
 
		message->setBody(boost::lexical_cast<std::string>(users));
 
	}
 
	else if (message->getBody() == "reload") {
 
		bool done = m_component->getConfig()->reload();
 
		if (done) {
 
			message->setBody("Config reloaded");
 
		}
 
		else {
 
			message->setBody("Error during config reload");
 
		}
 
	}
 
	else if (message->getBody() == "online_users_per_backend") {
 
		std::string lst;
 
		int id = 1;
 

	
 
		const std::list <NetworkPluginServer::Backend *> &backends = m_server->getBackends();
 
		for (std::list <NetworkPluginServer::Backend *>::const_iterator b = backends.begin(); b != backends.end(); b++) {
 
			NetworkPluginServer::Backend *backend = *b;
 
			lst += "Backend " + boost::lexical_cast<std::string>(id) + " (ID=" + backend->id + ")";
 
			lst += backend->acceptUsers ? "" : " - not-accepting";
 
			lst += backend->longRun ? " - long-running" : "";
 
			lst += ":\n";
 
			if (backend->users.size() == 0) {
 
				lst += "   waiting for users\n";
 
			}
 
			else {
 
				time_t now = time(NULL);
 
				for (std::list<User *>::const_iterator u = backend->users.begin(); u != backend->users.end(); u++) {
 
					User *user = *u;
 
					lst += "   " + user->getJID().toBare().toString();
 
					lst += " - non-active for " + boost::lexical_cast<std::string>(now - user->getLastActivity()) + " seconds";
 
					lst += "\n";
 
				}
 
			}
 
			id++;
 
		}
 

	
 
		message->setBody(lst);
src/blockresponder.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 "blockresponder.h"
 

	
 
#include <iostream>
 
#include <boost/bind.hpp>
 
#include "Swiften/Queries/IQRouter.h"
 
#include "transport/BlockPayload.h"
 
#include "Swiften/Swiften.h"
 
#include "transport/usermanager.h"
 
#include "transport/user.h"
 
#include "transport/buddy.h"
 
#include "transport/rostermanager.h"
 
#include "log4cxx/logger.h"
 

	
 
using namespace log4cxx;
 
#include "transport/logging.h"
 

	
 
using namespace Swift;
 
using namespace boost;
 

	
 
namespace Transport {
 

	
 
static LoggerPtr logger = Logger::getLogger("BlockResponder");
 
DEFINE_LOGGER(logger, "BlockResponder");
 

	
 
BlockResponder::BlockResponder(Swift::IQRouter *router, UserManager *userManager) : Swift::SetResponder<BlockPayload>(router) {
 
	m_userManager = userManager;
 
}
 

	
 
BlockResponder::~BlockResponder() {
 
	
 
}
 

	
 
bool BlockResponder::handleSetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<Transport::BlockPayload> info) {
 
	User *user = m_userManager->getUser(from.toBare().toString());
 
	if (!user) {
 
		LOG4CXX_WARN(logger, from.toBare().toString() << ": User is not logged in");
 
		return true;
 
	}
 

	
 
	Buddy *buddy = user->getRosterManager()->getBuddy(Buddy::JIDToLegacyName(to));
 
	if (!buddy) {
 
		LOG4CXX_WARN(logger, from.toBare().toString() << ": Buddy " << Buddy::JIDToLegacyName(to) << " does not exist");
 
		return true;
 
	}
 

	
 
	if (buddy->isBlocked()) {
 
		LOG4CXX_INFO(logger, from.toBare().toString() << ": Unblocking buddy " << Buddy::JIDToLegacyName(to));
 
	}
 
	else {
 
		LOG4CXX_INFO(logger, from.toBare().toString() << ": Blocking buddy " << Buddy::JIDToLegacyName(to));
 
	}
 

	
 
	onBlockToggled(buddy);
 

	
 
	return true;
 
}
 

	
 
}
src/config.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/config.h"
 
#include "transport/util.h"
 
#include <fstream>
 
#ifdef _MSC_VER
 
#include <direct.h>
 
#define getcwd _getcwd
 
#include <windows.h>
 
#define PATH_MAX MAX_PATH
 
#endif
 

	
 
using namespace boost::program_options;
 

	
 
namespace Transport {
 
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;
 
	bool ret = load(ifs, opts, jid);
 
	ifs.close();
 

	
 
	char path[PATH_MAX] = "";
 
	if (m_file.find_first_of("/") != 0) {
 
		getcwd(path, PATH_MAX);
 
		m_file = std::string(path) + "/" + m_file;
 
	}
 

	
 
	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.working_dir", value<std::string>()->default_value("/var/lib/spectrum2/$jid"), "Working dir")
 
		("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")
 
		("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::string>()->default_value(""), "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), "")
 
		("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.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)")
 
		("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.")
 
	;
 

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

	
 
	bool found_working = false;
 
	bool found_pidfile = 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>(Util::getRandomPort(_jid.empty() ? jid : _jid));
 
				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 == "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_backend_port) {
 
		std::vector<std::string> value;
 
		std::string p = boost::lexical_cast<std::string>(Util::getRandomPort(_jid.empty() ? jid : _jid));
 
		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));
 
	}
 
	if (!found_database) {
 
		std::vector<std::string> value;
 
		value.push_back("/var/lib/spectrum2/$jid/database.sql");
 
		parsed.options.push_back(boost::program_options::basic_option<char>("database.database", value));
 
	}
 

	
 
	BOOST_FOREACH(option &opt, parsed.options) {
 
		if (opt.unregistered) {
 
			m_unregistered[opt.string_key] = opt.value[0];
 
		}
 
		else if (opt.value[0].find("$jid") != std::string::npos) {
 
			boost::replace_all(opt.value[0], "$jid", jid);
 
		}
 
	}
 

	
 
	store(parsed, m_variables);
 
	notify(m_variables);
 

	
 
	onConfigReloaded();
 

	
 
	return true;
 
}
 

	
 
bool Config::load(std::istream &ifs) {
 
	options_description opts("Transport options");
 
	return load(ifs, opts);
 
}
 

	
 
bool Config::load(const std::string &configfile, const std::string &jid) {
 
	options_description opts("Transport options");
 
	return load(configfile, opts, jid);
 
}
 

	
 
bool Config::reload() {
 
	if (m_file.empty()) {
 
		return false;
 
	}
 

	
 
	return load(m_file);
 
}
 

	
 
}
src/conversation.cpp
Show inline comments
 
/**
 
 * XMPP - libpurple transport
 
 *
 
 * Copyright (C) 2009, Jan Kaluza <hanzz@soc.pidgin.im>
 
 *
 
 * This program is free software; you can redistribute it and/or modify
 
 * it under the terms of the GNU General Public License as published by
 
 * the Free Software Foundation; either version 2 of the License, or
 
 * (at your option) any later version.
 
 *
 
 * This program is distributed in the hope that it will be useful,
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
 * GNU General Public License for more details.
 
 *
 
 * You should have received a copy of the GNU General Public License
 
 * along with this program; if not, write to the Free Software
 
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
 
 */
 

	
 
#include <iostream>
 
#include "transport/conversation.h"
 
#include "transport/conversationmanager.h"
 
#include "transport/user.h"
 
#include "transport/transport.h"
 
#include "transport/buddy.h"
 
#include "transport/rostermanager.h"
 
#include "log4cxx/logger.h"
 

	
 
using namespace log4cxx;
 

	
 
namespace Transport {
 

	
 
// static LoggerPtr logger = Logger::getLogger("Conversation");
 

	
 
Conversation::Conversation(ConversationManager *conversationManager, const std::string &legacyName, bool isMUC) : m_conversationManager(conversationManager) {
 
	m_legacyName = legacyName;
 
	m_conversationManager->addConversation(this);
 
	m_muc = isMUC;
 
	m_jid = m_conversationManager->getUser()->getJID().toBare();
 
}
 

	
 
Conversation::~Conversation() {
 
}
 

	
 
void Conversation::setRoom(const std::string &room) {
 
	m_room = room;
 
	m_legacyName = m_room + "/" + m_legacyName;
 
}
 

	
 
void Conversation::handleMessage(boost::shared_ptr<Swift::Message> &message, const std::string &nickname) {
 
	if (m_muc) {
 
		message->setType(Swift::Message::Groupchat);
 
	}
 
	else {
 
		message->setType(Swift::Message::Chat);
 
	}
 

	
 
	std::string n = nickname;
 
	if (n.empty() && !m_room.empty() && !m_muc) {
 
		n = m_nickname;
 
	}
 

	
 
	if (message->getType() != Swift::Message::Groupchat) {
 
		message->setTo(m_jid);
 
		// normal message
 
		if (n.empty()) {
 
			Buddy *buddy = m_conversationManager->getUser()->getRosterManager()->getBuddy(m_legacyName);
 
			if (buddy) {
 
				message->setFrom(buddy->getJID());
 
			}
 
			else {
 
				message->setFrom(Swift::JID(Swift::JID::getEscapedNode(m_legacyName), m_conversationManager->getComponent()->getJID().toBare()));
 
			}
 
		}
 
		// PM message
 
		else {
 
			if (m_room.empty()) {
 
				message->setFrom(Swift::JID(n, m_conversationManager->getComponent()->getJID().toBare(), "user"));
 
			}
 
			else {
 
				message->setFrom(Swift::JID(m_room, m_conversationManager->getComponent()->getJID().toBare(), n));
 
			}
 
		}
 
		m_conversationManager->getComponent()->getStanzaChannel()->sendMessage(message);
 
	}
 
	else {
 
		std::string legacyName = m_legacyName;
 
		if (legacyName.find_last_of("@") != std::string::npos) {
 
			legacyName.replace(legacyName.find_last_of("@"), 1, "%"); // OK
 
		}
 
		message->setTo(m_jid);
 
		message->setFrom(Swift::JID(legacyName, m_conversationManager->getComponent()->getJID().toBare(), nickname));
 
		m_conversationManager->getComponent()->getStanzaChannel()->sendMessage(message);
 
	}
 
}
 

	
 
void Conversation::handleParticipantChanged(const std::string &nick, int flag, int status, const std::string &statusMessage, const std::string &newname) {
 
	std::string nickname = nick;
 
	Swift::Presence::ref presence = Swift::Presence::create();
 
	std::string legacyName = m_legacyName;
 
	if (m_muc) {
 
		if (legacyName.find_last_of("@") != std::string::npos) {
 
			legacyName.replace(legacyName.find_last_of("@"), 1, "%"); // OK
 
		}
 
	}
 
	presence->setFrom(Swift::JID(legacyName, m_conversationManager->getComponent()->getJID().toBare(), nickname));
 
	presence->setTo(m_jid);
 
	presence->setType(Swift::Presence::Available);
 

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

	
 
	Swift::StatusShow s((Swift::StatusShow::Type) status);
 

	
 
	if (s.getType() == Swift::StatusShow::None) {
 
		presence->setType(Swift::Presence::Unavailable);
 
	}
 

	
 
	presence->setShow(s.getType());
 

	
 
	Swift::MUCUserPayload *p = new Swift::MUCUserPayload ();
 
	if (m_nickname == nickname) {
 
		Swift::MUCUserPayload::StatusCode c;
 
		c.code = 110;
 
		p->addStatusCode(c);
 
	}
 

	
 
	
 
	Swift::MUCItem item;
 
	
src/conversationmanager.cpp
Show inline comments
 
/**
 
 * XMPP - libpurple transport
 
 *
 
 * Copyright (C) 2009, Jan Kaluza <hanzz@soc.pidgin.im>
 
 *
 
 * This program is free software; you can redistribute it and/or modify
 
 * it under the terms of the GNU General Public License as published by
 
 * the Free Software Foundation; either version 2 of the License, or
 
 * (at your option) any later version.
 
 *
 
 * This program is distributed in the hope that it will be useful,
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
 * GNU General Public License for more details.
 
 *
 
 * You should have received a copy of the GNU General Public License
 
 * along with this program; if not, write to the Free Software
 
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
 
 */
 

	
 
#include "transport/conversationmanager.h"
 
#include "transport/conversation.h"
 
#include "transport/usermanager.h"
 
#include "transport/buddy.h"
 
#include "transport/factory.h"
 
#include "transport/user.h"
 
#include "transport/logging.h"
 
#include "Swiften/Roster/SetRosterRequest.h"
 
#include "Swiften/Elements/RosterPayload.h"
 
#include "Swiften/Elements/RosterItemPayload.h"
 
#include "log4cxx/logger.h"
 

	
 
using namespace log4cxx;
 

	
 
namespace Transport {
 

	
 
static LoggerPtr logger = Logger::getLogger("ConversationManager");
 
DEFINE_LOGGER(logger, "ConversationManager");
 

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

	
 
ConversationManager::~ConversationManager() {
 
	while(!m_convs.empty()) {
 
		LOG4CXX_INFO(logger, m_user->getJID().toString() << ": Removing conversation " << (*m_convs.begin()).first);
 
		delete (*m_convs.begin()).second;
 
		m_convs.erase(m_convs.begin());
 
	}
 
}
 

	
 
void ConversationManager::addConversation(Conversation *conv) {
 
	m_convs[conv->getLegacyName()] = conv;
 
	LOG4CXX_INFO(logger, m_user->getJID().toString() << ": Adding conversation " << conv->getLegacyName());
 
}
 

	
 
void ConversationManager::removeConversation(Conversation *conv) {
 
	for (std::map<std::string, Conversation *>::const_iterator it = m_convs.begin(); it != m_convs.end(); it++) {
 
		if ((*it).second->getRoom() == conv->getLegacyName()) {
 
			(*it).second->setRoom("");
 
		}
 
	}
 
	m_convs.erase(conv->getLegacyName());
 
}
 

	
 
void ConversationManager::resetResources() {
 
	for (std::map<std::string, Conversation *>::const_iterator it = m_convs.begin(); it != m_convs.end(); it++) {
 
		if ((*it).second->isMUC()) {
 
			continue;
 
		}
 
		(*it).second->setJID(m_user->getJID().toBare());
 
	}
 
}
 

	
 
void ConversationManager::handleMessageReceived(Swift::Message::ref message) {
 
// 	std::string name = message->getTo().getUnescapedNode();
 
// 	if (name.find_last_of("%") != std::string::npos) { // OK when commented
 
// 		name.replace(name.find_last_of("%"), 1, "@"); // OK when commented
 
// 	}
 
	std::string name = Buddy::JIDToLegacyName(message->getTo());
 
	if (name.empty()) {
 
		LOG4CXX_WARN(logger, m_user->getJID().toString() << ": Tried to create empty conversation");
 
		return;
 
	}
 

	
 
	// create conversation if it does not exist.
 
	if (!m_convs[name]) {
 
		m_convs[name] = m_component->getFactory()->createConversation(this, name);
 
	}
 
	// if it exists and it's MUC, but this message is PM, get PM conversation or create new one.
 
	else if (m_convs[name]->isMUC() && message->getType() != Swift::Message::Groupchat) {
 
		std::string room_name = name;
 
		name = message->getTo().getResource();
 
		if (!m_convs[name]) {
 
			m_convs[name] = m_component->getFactory()->createConversation(this, name);
 
			m_convs[name]->setRoom(room_name);
 
			m_convs[name]->setNickname(name);
 
		}
 
	}
 

	
 
	// update resource and send the message
 
	m_convs[name]->setJID(message->getFrom());
 
	m_convs[name]->sendMessage(message);
 
}
 

	
 
}
src/filetransfermanager.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/filetransfermanager.h"
 
#include "transport/transport.h"
 
#include "transport/usermanager.h"
 
#include "transport/user.h"
 
#include "transport/buddy.h"
 
#include "log4cxx/logger.h"
 

	
 
using namespace log4cxx;
 
#include "transport/logging.h"
 

	
 
namespace Transport {
 

	
 
static LoggerPtr logger = Logger::getLogger("FileTransferManager");
 
DEFINE_LOGGER(logger, "FileTransferManager");
 

	
 
FileTransferManager::FileTransferManager(Component *component, UserManager *userManager) {
 
	m_component = component;
 
	m_userManager = userManager;
 

	
 
	m_jingleSessionManager = new Swift::JingleSessionManager(m_component->getIQRouter());
 
	m_connectivityManager = new Swift::ConnectivityManager(m_component->getNetworkFactories()->getNATTraverser());
 
	m_bytestreamRegistry = new Swift::SOCKS5BytestreamRegistry();
 
	m_bytestreamProxy = new Swift::SOCKS5BytestreamProxy(m_component->getNetworkFactories()->getConnectionFactory(), m_component->getNetworkFactories()->getTimerFactory());
 

	
 
	m_localCandidateGeneratorFactory = new Swift::DefaultLocalJingleTransportCandidateGeneratorFactory(m_connectivityManager, m_bytestreamRegistry, m_bytestreamProxy, "thishouldnotbeused");
 
	m_remoteCandidateSelectorFactory = new Swift::DefaultRemoteJingleTransportCandidateSelectorFactory(m_component->getNetworkFactories()->getConnectionFactory(), m_component->getNetworkFactories()->getTimerFactory());
 

	
 
	boost::shared_ptr<Swift::ConnectionServer> server = m_component->getNetworkFactories()->getConnectionServerFactory()->createConnectionServer(19645);
 
	server->start();
 
	m_bytestreamServer = new Swift::SOCKS5BytestreamServer(server, m_bytestreamRegistry);
 
	m_bytestreamServer->start();
 

	
 
	m_outgoingFTManager = new Swift::CombinedOutgoingFileTransferManager(m_jingleSessionManager, m_component->getIQRouter(),
 
																	m_userManager, m_remoteCandidateSelectorFactory, 
 
																	m_localCandidateGeneratorFactory, m_bytestreamRegistry, 
 
																	m_bytestreamProxy, m_component->getPresenceOracle(),
 
																	m_bytestreamServer);
 

	
 
// WARNING: Swiften crashes when this is uncommented... But we probably need it for working Jingle FT
 
// 	m_connectivityManager->addListeningPort(19645);
 
}
 

	
 
FileTransferManager::~FileTransferManager() {
 
	m_bytestreamServer->stop();
 
	delete m_outgoingFTManager;
 
	delete m_remoteCandidateSelectorFactory;
 
	delete m_localCandidateGeneratorFactory;
 
	delete m_jingleSessionManager;
 
	delete m_bytestreamRegistry;
 
	delete m_bytestreamServer;
 
	delete m_bytestreamProxy;
 
	delete m_connectivityManager;
 
}
 

	
 
FileTransferManager::Transfer FileTransferManager::sendFile(User *user, Buddy *buddy, boost::shared_ptr<Swift::ReadBytestream> byteStream, const Swift::StreamInitiationFileInfo &info) {
 
	FileTransferManager::Transfer transfer;
 
	transfer.from = buddy->getJID();
 
	transfer.to = user->getJID();
 
	transfer.readByteStream = byteStream;
 

	
 
	LOG4CXX_INFO(logger, "Starting FT from '" << transfer.from << "' to '" << transfer.to << "'")
 

	
 
	transfer.ft = m_outgoingFTManager->createOutgoingFileTransfer(transfer.from, transfer.to, transfer.readByteStream, info);
 
// 	if (transfer.ft) {
 
// 		m_filetransfers.push_back(ft);
 
// 		ft->onStateChange.connect(boost::bind(&User::handleFTStateChanged, this, _1, Buddy::JIDToLegacyName(from), info.getName(), info.getSize(), id));
 
// 		transfer.ft->start();
 
// 	}
 
	return transfer;
 
}
 

	
 
}
src/gatewayresponder.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/gatewayresponder.h"
 

	
 
#include <iostream>
 
#include <boost/bind.hpp>
 
#include "Swiften/Queries/IQRouter.h"
 
#include "Swiften/Elements/RawXMLPayload.h"
 
#include "Swiften/Swiften.h"
 
#include "transport/usermanager.h"
 
#include "transport/user.h"
 
#include "transport/transport.h"
 
#include "log4cxx/logger.h"
 

	
 
using namespace log4cxx;
 
#include "transport/logging.h"
 

	
 
using namespace Swift;
 
using namespace boost;
 

	
 
namespace Transport {
 

	
 
static LoggerPtr logger = Logger::getLogger("GatewayResponder");
 
DEFINE_LOGGER(logger, "GatewayResponder");
 

	
 
GatewayResponder::GatewayResponder(Swift::IQRouter *router, UserManager *userManager) : Swift::Responder<GatewayPayload>(router) {
 
	m_userManager = userManager;
 
}
 

	
 
GatewayResponder::~GatewayResponder() {
 
}
 

	
 
bool GatewayResponder::handleGetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<Swift::GatewayPayload> payload) {
 
	sendResponse(from, id, boost::shared_ptr<GatewayPayload>(new GatewayPayload(Swift::JID(), "Enter legacy network contact ID.", "Contact ID")));
 
	return true;
 
}
 

	
 
bool GatewayResponder::handleSetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<Swift::GatewayPayload> payload) {
 
	std::string prompt = payload->getPrompt();
 
	std::string escaped = Swift::JID::getEscapedNode(prompt);
 
	std::string jid = escaped + "@" + m_userManager->getComponent()->getJID().toBare().toString();
 
	
 
	sendResponse(from, id, boost::shared_ptr<GatewayPayload>(new GatewayPayload(jid)));
 
	return true;
 
}
 

	
 
}
src/logging.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/logging.h"
 
#include "transport/config.h"
 
#include <boost/foreach.hpp>
 
#include <iostream>
 
#include <iterator>
 
#include <algorithm>
 

	
 
#include "log4cxx/logger.h"
 
#include "log4cxx/consoleappender.h"
 
#include "log4cxx/patternlayout.h"
 
#include "log4cxx/propertyconfigurator.h"
 
#include "log4cxx/helpers/properties.h"
 
#include "log4cxx/helpers/fileinputstream.h"
 
#include "log4cxx/helpers/transcoder.h"
 

	
 
#include <boost/filesystem.hpp>
 
#include <boost/algorithm/string.hpp>
 

	
 
#ifndef WIN32
 
#include "sys/signal.h"
 
#include <pwd.h>
 
#include <grp.h>
 
#include <sys/resource.h>
 
#include "libgen.h"
 
#else
 
#include <windows.h>
 
#include <process.h>
 
#define getpid _getpid
 
#endif
 

	
 
using namespace boost::filesystem;
 
using namespace log4cxx;
 

	
 

	
 
namespace Transport {
 

	
 
namespace Logging {
 

	
 
#ifdef WITH_LOG4CXX
 
using namespace log4cxx;
 
static LoggerPtr root;
 

	
 
static void initLogging(Config *config, std::string key) {
 
	if (CONFIG_STRING(config, key).empty()) {
 
		root = log4cxx::Logger::getRootLogger();
 
#ifdef WIN32
 
		root->addAppender(new ConsoleAppender(new PatternLayout(L"%d %-5p %c: %m%n")));
 
#else
 
		root->addAppender(new ConsoleAppender(new PatternLayout("%d %-5p %c: %m%n")));
 
#endif
 
	}
 
	else {
 
		log4cxx::helpers::Properties p;
 

	
 
		log4cxx::helpers::FileInputStream *istream = NULL;
 
		try {
 
			istream = new log4cxx::helpers::FileInputStream(CONFIG_STRING(config, key));
 
		}
 
		catch(log4cxx::helpers::IOException &ex) {
 
			std::cerr << "Can't create FileInputStream logger instance: " << ex.what() << "\n";
 
		}
 
		catch (...) {
 
			std::cerr << "Can't create FileInputStream logger instance\n";
 
		}
 

	
 
		if (!istream) {
 
			return;
 
		}
 

	
 
		p.load(istream);
 
		LogString pid, jid;
 
		log4cxx::helpers::Transcoder::decode(boost::lexical_cast<std::string>(getpid()), pid);
 
		log4cxx::helpers::Transcoder::decode(CONFIG_STRING(config, "service.jid"), jid);
 
#ifdef WIN32
 
		p.setProperty(L"pid", pid);
 
		p.setProperty(L"jid", jid);
 
#else
 
		p.setProperty("pid", pid);
 
		p.setProperty("jid", jid);
 
#endif
 

	
 
		std::string dir;
 
		BOOST_FOREACH(const log4cxx::LogString &prop, p.propertyNames()) {
 
			if (boost::ends_with(prop, ".File")) {
 
				log4cxx::helpers::Transcoder::encode(p.get(prop), dir);
 
				boost::replace_all(dir, "${jid}", jid);
 
				break;
 
			}
 
		}
 

	
 
		if (!dir.empty()) {
 
			// create directories
 
			try {
 
				boost::filesystem::create_directories(
 
					boost::filesystem::path(dir).parent_path().string()
 
				);
 
			}
 
			catch (...) {
 
				std::cerr << "Can't create logging directory directory " << boost::filesystem::path(dir).parent_path().string() << ".\n";
 
			}
 

	
 
#ifndef WIN32
 
			if (!CONFIG_STRING(config, "service.group").empty() && !CONFIG_STRING(config, "service.user").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";
 
				}
 
				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";
 
				}
 
				chown(dir.c_str(), pw->pw_uid, gr->gr_gid);
 
			}
 

	
 
#endif
 
		}
 

	
 
		log4cxx::PropertyConfigurator::configure(p);
 
	}
 
}
 

	
 
void initBackendLogging(Config *config) {
 
	initLogging(config, "logging.backend_config");
 
}
 

	
 
void initMainLogging(Config *config) {
 
	initLogging(config, "logging.config");
 
}
 

	
 
#else /* WITH_LOG4CXX */
 
void initBackendLogging(Config */*config*/) {
 
}
 

	
 
void initMainLogging(Config */*config*/) {
 
}
 
#endif /* WITH_LOG4CXX */
 

	
 
}
 

	
 
}
src/memoryreadbytestream.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/memoryreadbytestream.h"
 
#include "log4cxx/logger.h"
 
#include <boost/foreach.hpp>
 

	
 
using namespace log4cxx;
 

	
 
namespace Transport {
 
	
 
MemoryReadBytestream::MemoryReadBytestream(unsigned long size) {
 
	neededData = false;
 
	m_finished = false;
 
	m_sent = 0;
 
	m_size = size;
 
}
 

	
 
MemoryReadBytestream::~MemoryReadBytestream() {
 
	
 
}
 

	
 
unsigned long MemoryReadBytestream::appendData(const std::string &data) {
 
	m_data += data;
 
	onDataAvailable();
 
	neededData = false;
 
	return m_data.size();
 
}
 

	
 
boost::shared_ptr<std::vector<unsigned char> > MemoryReadBytestream::read(size_t size) {
 
	if (m_data.empty()) {
 
		onDataNeeded();
 
		return boost::shared_ptr<std::vector<unsigned char> >(new std::vector<unsigned char>());
 
	}
 

	
 
	if (m_data.size() < size) {
 
		boost::shared_ptr<std::vector<unsigned char> > ptr(new std::vector<unsigned char>(m_data.begin(), m_data.end()));
 
		m_sent += m_data.size();
 
		m_data.clear();
 
		if (m_sent == m_size)
 
			m_finished = true;
 
		onDataNeeded();
 
		return ptr;
 
	}
 
	boost::shared_ptr<std::vector<unsigned char> > ptr(new std::vector<unsigned char>(m_data.begin(), m_data.begin() + size));
 
	m_data.erase(m_data.begin(), m_data.begin() + size);
 
	m_sent += size;
 
	if (m_sent == m_size)
 
		m_finished = true;
 
	if (m_data.size() < 500000 && !neededData) {
 
		neededData = true;
 
		onDataNeeded();
 
	}
 
	return ptr;
 
}
 

	
 
bool MemoryReadBytestream::isFinished() const {
 
// 	std::cout << "finished? " << m_finished << "\n";
 
	return m_finished;
 
}
 

	
 
}
src/mysqlbackend.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
 
 */
 

	
 
#ifdef WITH_MYSQL
 

	
 
#include "transport/mysqlbackend.h"
 
#include "transport/util.h"
 
#include "transport/logging.h"
 
#include <boost/bind.hpp>
 
#include "log4cxx/logger.h"
 

	
 
using namespace log4cxx;
 

	
 
#define MYSQL_DB_VERSION 2
 
#define CHECK_DB_RESPONSE(stmt) \
 
	if(stmt) { \
 
		sqlite3_EXEC(m_db, "ROLLBACK;", NULL, NULL, NULL); \
 
		return 0; \
 
	}
 

	
 
// Prepare the SQL statement
 
#define PREP_STMT(sql, str) \
 
	sql = mysql_stmt_init(&m_conn);\
 
	if (mysql_stmt_prepare(sql, std::string(str).c_str(), std::string(str).size())) {\
 
		LOG4CXX_ERROR(logger, str << " " << mysql_error(&m_conn)); \
 
		return false; \
 
	}
 

	
 
// Finalize the prepared statement
 
#define FINALIZE_STMT(prep) \
 
	if(prep != NULL) { \
 
		mysql_stmt_close(prep); \
 
	}
 
	
 
#define BEGIN(STATEMENT, SIZE) 	MYSQL_BIND STATEMENT##_bind[SIZE]; \
 
							memset(STATEMENT##_bind, 0, sizeof(STATEMENT##_bind)); \
 
							int STATEMENT##_id = 1;\
 
							int STATEMENT##_id_get = 0;\
 
							(void)STATEMENT##_id_get;
 

	
 
#define BIND_INT(STATEMENT, VARIABLE) STATEMENT##_bind[STATEMENT##_id].buffer_type= MYSQL_TYPE_LONG;\
 
							STATEMENT##_bind[STATEMENT##_id].buffer= (char *)&VARIABLE;\
 
							STATEMENT##_bind[STATEMENT##_id].is_null= 0;\
 
							STATEMENT##_bind[STATEMENT##_id++].length= 0;
 
#define BIND_STR(STATEMENT, VARIABLE) STATEMENT##_bind[STATEMENT##_id].buffer_type= MYSQL_TYPE_STRING;\
 
							STATEMENT##_bind[STATEMENT##_id].buffer= VARIABLE.c_str();\
 
							STATEMENT##_bind[STATEMENT##_id].buffer_length= STRING_SIZE;\
 
							STATEMENT##_bind[STATEMENT##_id].is_null= 0;\
 
							STATEMENT##_bind[STATEMENT##_id++].length= VARIABLE.size();
 
#define RESET_GET_COUNTER(STATEMENT)	STATEMENT##_id_get = 0;
 
#define GET_INT(STATEMENT)	sqlite3_column_int(STATEMENT, STATEMENT##_id_get++)
 
#define GET_STR(STATEMENT)	(const char *) sqlite3_column_text(STATEMENT, STATEMENT##_id_get++)
 
#define EXECUTE_STATEMENT(STATEMENT, NAME) if (mysql_stmt_bind_param(STATEMENT, STATEMENT##_bind)) { \
 
		LOG4CXX_ERROR(logger, NAME << " " << mysql_error(&m_conn)); \
 
	} \
 
	if (mysql_stmt_execute(STATEMENT)) { \
 
		LOG4CXX_ERROR(logger, NAME << " " << mysql_error(&m_conn)); \
 
	}
 

	
 
#define EXEC(STMT, METHOD) \
 
	{\
 
	int ret = STMT->execute(); \
 
	if (ret == 0) \
 
		exec_ok = true; \
 
	else if (ret == 2013) { \
 
		LOG4CXX_INFO(logger, "MySQL connection lost. Reconnecting...");\
 
		disconnect(); \
 
		connect(); \
 
		return METHOD; \
 
	} \
 
	else \
 
		exec_ok = false; \
 
	}
 

	
 
using namespace boost;
 

	
 
namespace Transport {
 

	
 
static LoggerPtr logger = Logger::getLogger("MySQLBackend");
 
DEFINE_LOGGER(logger, "MySQLBackend");
 
static bool exec_ok;
 

	
 
MySQLBackend::Statement::Statement(MYSQL *conn, const std::string &format, const std::string &statement) {
 
	m_resultOffset = -1;
 
	m_conn = conn;
 
	m_offset = 0;
 
	m_string = statement;
 
	m_stmt = mysql_stmt_init(conn);
 
	if (mysql_stmt_prepare(m_stmt, statement.c_str(), statement.size())) {
 
		LOG4CXX_ERROR(logger, statement << " " << mysql_error(conn));
 
		return;
 
	}
 

	
 
	for (int i = 0; i < format.length() && m_resultOffset == -1; i++) {
 
		switch (format.at(i)) {
 
			case 's':
 
				m_params.resize(m_params.size() + 1);
 
				memset(&m_params.back(), 0, sizeof(MYSQL_BIND));
 

	
 
				m_params.back().buffer_type= MYSQL_TYPE_STRING;
 
				m_params.back().buffer= (char *) malloc(sizeof(char) * 4096);
 
				m_params.back().buffer_length= 4096;
 
				m_params.back().is_null= 0;
 
				m_params.back().length= (unsigned long *) malloc(sizeof(unsigned long));
 
				break;
 
			case 'i':
 
				m_params.resize(m_params.size() + 1);
 
				memset(&m_params.back(), 0, sizeof(MYSQL_BIND));
 

	
 
				m_params.back().buffer_type= MYSQL_TYPE_LONG;
 
				m_params.back().buffer= (int *) malloc(sizeof(int));
 
				m_params.back().is_null= 0;
 
				m_params.back().length= (unsigned long *) malloc(sizeof(unsigned long));
 
				break;
 
			case 'b':
 
				m_params.resize(m_params.size() + 1);
 
				memset(&m_params.back(), 0, sizeof(MYSQL_BIND));
 

	
 
				m_params.back().buffer_type= MYSQL_TYPE_TINY;
 
				m_params.back().buffer= (int *) malloc(sizeof(int));
 
				m_params.back().is_null= 0;
 
				m_params.back().length= (unsigned long *) malloc(sizeof(unsigned long));
 
				break;
 
			case '|':
 
				m_resultOffset = i;
 
				break;
 
		}
 
	}
 

	
 
	for (int i = m_resultOffset; i >= 0 && i < format.length(); i++) {
 
		switch (format.at(i)) {
 
			case 's':
 
				m_results.resize(m_results.size() + 1);
 
				memset(&m_results.back(), 0, sizeof(MYSQL_BIND));
 

	
 
				m_results.back().buffer_type= MYSQL_TYPE_STRING;
 
				m_results.back().buffer= (char *) malloc(sizeof(char) * 4096);
 
				m_results.back().buffer_length= 4096;
 
				m_results.back().is_null= 0;
 
				m_results.back().length= (unsigned long *) malloc(sizeof(unsigned long));
 
				break;
 
			case 'i':
 
				m_results.resize(m_results.size() + 1);
 
				memset(&m_results.back(), 0, sizeof(MYSQL_BIND));
 

	
 
				m_results.back().buffer_type= MYSQL_TYPE_LONG;
 
				m_results.back().buffer= (int *) malloc(sizeof(int));
 
				m_results.back().is_null= 0;
 
				m_results.back().length= (unsigned long *) malloc(sizeof(unsigned long));
 
				break;
 
			case 'b':
 
				m_results.resize(m_results.size() + 1);
 
				memset(&m_results.back(), 0, sizeof(MYSQL_BIND));
 

	
 
				m_results.back().buffer_type= MYSQL_TYPE_TINY;
 
				m_results.back().buffer= (int *) malloc(sizeof(int));
 
				m_results.back().is_null= 0;
 
				m_results.back().length= (unsigned long *) malloc(sizeof(unsigned long));
 
				break;
 
		}
 
	}
 

	
 
	if (mysql_stmt_bind_param(m_stmt, &m_params.front())) {
 
		LOG4CXX_ERROR(logger, statement << " " << mysql_error(conn));
 
	}
 

	
 
	if (m_resultOffset < 0)
 
		m_resultOffset = format.size();
 
	else {
 
		if (mysql_stmt_bind_result(m_stmt, &m_results.front())) {
 
			LOG4CXX_ERROR(logger, statement << " " << mysql_error(conn));
 
		}
 
	}
 
	m_resultOffset = 0;
 
}
 

	
src/networkpluginserver.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/networkpluginserver.h"
 
#include "transport/user.h"
 
#include "transport/transport.h"
 
#include "transport/storagebackend.h"
 
#include "transport/rostermanager.h"
 
#include "transport/usermanager.h"
 
#include "transport/conversationmanager.h"
 
#include "transport/localbuddy.h"
 
#include "transport/config.h"
 
#include "transport/conversation.h"
 
#include "transport/vcardresponder.h"
 
#include "transport/rosterresponder.h"
 
#include "transport/memoryreadbytestream.h"
 
#include "transport/logging.h"
 
#include "blockresponder.h"
 
#include "Swiften/Swiften.h"
 
#include "Swiften/Server/ServerStanzaChannel.h"
 
#include "Swiften/Elements/StreamError.h"
 
#include "Swiften/Network/BoostConnectionServer.h"
 
#include "Swiften/Elements/AttentionPayload.h"
 
#include "Swiften/Elements/XHTMLIMPayload.h"
 
#include "Swiften/Elements/InvisiblePayload.h"
 
#include "Swiften/Elements/SpectrumErrorPayload.h"
 
#include "transport/protocol.pb.h"
 
#include "log4cxx/logger.h"
 

	
 
#include <Swiften/FileTransfer/ReadBytestream.h>
 
#include <Swiften/Elements/StreamInitiationFileInfo.h>
 

	
 
#ifdef _WIN32
 
#include "windows.h"
 
#include <stdint.h>
 
#else
 
#include "sys/wait.h"
 
#include "sys/signal.h"
 
#include "popt.h"
 
#endif
 

	
 
using namespace log4cxx;
 

	
 
namespace Transport {
 

	
 
static unsigned long backend_id;
 
static unsigned long bytestream_id;
 

	
 
static LoggerPtr logger = Logger::getLogger("NetworkPluginServer");
 
DEFINE_LOGGER(logger, "NetworkPluginServer");
 

	
 
class NetworkConversation : public Conversation {
 
	public:
 
		NetworkConversation(ConversationManager *conversationManager, const std::string &legacyName, bool muc = false) : Conversation(conversationManager, legacyName, muc) {
 
		}
 

	
 
		// Called when there's new message to legacy network from XMPP network
 
		void sendMessage(boost::shared_ptr<Swift::Message> &message) {
 
			onMessageToSend(this, message);
 
		}
 

	
 
		boost::signal<void (NetworkConversation *, boost::shared_ptr<Swift::Message> &)> onMessageToSend;
 
};
 

	
 
class NetworkFactory : public Factory {
 
	public:
 
		NetworkFactory(NetworkPluginServer *nps) {
 
			m_nps = nps;
 
		}
 

	
 
		// Creates new conversation (NetworkConversation in this case)
 
		Conversation *createConversation(ConversationManager *conversationManager, const std::string &legacyName) {
 
			NetworkConversation *nc = new NetworkConversation(conversationManager, legacyName);
 
			nc->onMessageToSend.connect(boost::bind(&NetworkPluginServer::handleMessageReceived, m_nps, _1, _2));
 
			return nc;
 
		}
 

	
 
		// Creates new LocalBuddy
 
		Buddy *createBuddy(RosterManager *rosterManager, const BuddyInfo &buddyInfo) {
 
			LocalBuddy *buddy = new LocalBuddy(rosterManager, buddyInfo.id);
 
			buddy->setAlias(buddyInfo.alias);
 
			buddy->setName(buddyInfo.legacyName);
 
			if (buddyInfo.subscription == "both") {
 
				buddy->setSubscription(Buddy::Both);
 
			}
 
			else {
 
				buddy->setSubscription(Buddy::Ask);
 
			}
 
			buddy->setGroups(buddyInfo.groups);
 
			buddy->setFlags((BuddyFlag) (buddyInfo.flags));
 
			if (buddyInfo.settings.find("icon_hash") != buddyInfo.settings.end())
 
				buddy->setIconHash(buddyInfo.settings.find("icon_hash")->second.s);
 
			return buddy;
 
		}
 

	
 
	private:
 
		NetworkPluginServer *m_nps;
 
};
 

	
 
// Wraps google protobuf payload into WrapperMessage and serialize it to string
 
#define WRAP(MESSAGE, TYPE) 	pbnetwork::WrapperMessage wrap; \
 
	wrap.set_type(TYPE); \
 
	wrap.set_payload(MESSAGE); \
 
	wrap.SerializeToString(&MESSAGE);
 

	
 
// Executes new backend
 
static unsigned long exec_(std::string path, const char *host, const char *port, const char *config) {
 
	std::string original_path = path;
 
	// BACKEND_ID is replaced with unique ID. The ID is increasing for every backend.
 
	boost::replace_all(path, "BACKEND_ID", boost::lexical_cast<std::string>(backend_id++));
 

	
 
	// Add host and port.
 
	path += std::string(" --host ") + host + " --port " + port + " " + config;
 
	LOG4CXX_INFO(logger, "Starting new backend " << path);
 

	
 
#ifdef _WIN32
 
	STARTUPINFO         si;
 
	PROCESS_INFORMATION pi;
 

	
 
	ZeroMemory (&si, sizeof(si));
 
	si.cb=sizeof (si);
 

	
 
	if (! CreateProcess(
 
	NULL,
 
	(LPSTR)path.c_str(),         // command line
 
	0,                    // process attributes
 
	0,                    // thread attributes
 
	0,                    // inherit handles
 
	0,                    // creation flags
 
	0,                    // environment
 
	0,                    // cwd
 
	&si,
 
	&pi
 
	)
 
	)  {
 
		LOG4CXX_ERROR(logger, "Could not start process");
 
	}
 

	
 
	return 0;
 
#else
 
	// Create array of char * from string using -lpopt library
 
	char *p = (char *) malloc(path.size() + 1);
 
	strcpy(p, path.c_str());
 
	int argc;
 
	char **argv;
 
	poptParseArgvString(p, &argc, (const char ***) &argv);
src/rostermanager.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/rostermanager.h"
 
#include "transport/rosterstorage.h"
 
#include "transport/storagebackend.h"
 
#include "transport/buddy.h"
 
#include "transport/usermanager.h"
 
#include "transport/buddy.h"
 
#include "transport/user.h"
 
#include "transport/logging.h"
 
#include "Swiften/Roster/SetRosterRequest.h"
 
#include "Swiften/Elements/RosterPayload.h"
 
#include "Swiften/Elements/RosterItemPayload.h"
 
#include "Swiften/Elements/RosterItemExchangePayload.h"
 
#include "log4cxx/logger.h"
 
#include <boost/foreach.hpp>
 

	
 
#include <map>
 
#include <iterator>
 

	
 
using namespace log4cxx;
 

	
 
namespace Transport {
 

	
 
static LoggerPtr logger = Logger::getLogger("RosterManager");
 
DEFINE_LOGGER(logger, "RosterManager");
 

	
 
RosterManager::RosterManager(User *user, Component *component){
 
	m_rosterStorage = NULL;
 
	m_user = user;
 
	m_component = component;
 
	m_setBuddyTimer = m_component->getNetworkFactories()->getTimerFactory()->createTimer(1000);
 
	m_RIETimer = m_component->getNetworkFactories()->getTimerFactory()->createTimer(5000);
 
	m_RIETimer->onTick.connect(boost::bind(&RosterManager::sendRIE, this));
 

	
 
	m_supportRemoteRoster = false;
 

	
 
	if (!m_component->inServerMode()) {
 
		m_remoteRosterRequest = AddressedRosterRequest::ref(new AddressedRosterRequest(m_component->getIQRouter(), m_user->getJID().toBare()));
 
		m_remoteRosterRequest->onResponse.connect(boost::bind(&RosterManager::handleRemoteRosterResponse, this, _1, _2));
 
		m_remoteRosterRequest->send();
 
	}
 
}
 

	
 
RosterManager::~RosterManager() {
 
	m_setBuddyTimer->stop();
 
	m_RIETimer->stop();
 
	if (m_rosterStorage) {
 
		m_rosterStorage->storeBuddies();
 
	}
 

	
 
	sendUnavailablePresences(m_user->getJID().toBare());
 

	
 
	if (m_remoteRosterRequest) {
 
		m_remoteRosterRequest->onResponse.disconnect_all_slots();
 
		m_component->getIQRouter()->removeHandler(m_remoteRosterRequest);
 
	}
 

	
 
	for (std::map<std::string, Buddy *, std::less<std::string>, boost::pool_allocator< std::pair<std::string, Buddy *> > >::iterator it = m_buddies.begin(); it != m_buddies.end(); it++) {
 
		Buddy *buddy = (*it).second;
 
		if (!buddy) {
 
			continue;
 
		}
 
		delete buddy;
 
	}
 

	
 
	if (m_requests.size() != 0) {
 
		LOG4CXX_INFO(logger, m_user->getJID().toString() <<  ": Removing " << m_requests.size() << " unresponded IQs");
 
		BOOST_FOREACH(Swift::SetRosterRequest::ref request, m_requests) {
 
			request->onResponse.disconnect_all_slots();
 
			m_component->getIQRouter()->removeHandler(request);
 
		}
 
		m_requests.clear();
 
	}
 

	
 
	boost::singleton_pool<boost::pool_allocator_tag, sizeof(unsigned int)>::release_memory();
 

	
 
	if (m_rosterStorage)
 
		delete m_rosterStorage;
 
}
 

	
 
void RosterManager::setBuddy(Buddy *buddy) {
 
// 	m_setBuddyTimer->onTick.connect(boost::bind(&RosterManager::setBuddyCallback, this, buddy));
 
// 	m_setBuddyTimer->start();
 
	setBuddyCallback(buddy);
 
}
 

	
 
void RosterManager::sendBuddyRosterPush(Buddy *buddy) {
 
	// user can't receive anything in server mode if he's not logged in.
 
	// He will ask for roster later (handled in rosterreponsder.cpp)
 
	if (m_component->inServerMode() && !m_user->isConnected())
 
		return;
 

	
 
	Swift::RosterPayload::ref payload = Swift::RosterPayload::ref(new Swift::RosterPayload());
 
	Swift::RosterItemPayload item;
 
	item.setJID(buddy->getJID().toBare());
 
	if (buddy->getAlias().empty()) {
 
		item.setName(buddy->getJID().toBare().toString());
 
	}
 
	else {
 
		item.setName(buddy->getAlias());
 
	}
 
	item.setGroups(buddy->getGroups());
 
	item.setSubscription(Swift::RosterItemPayload::Both);
 

	
 
	payload->addItem(item);
 

	
 
	// In server mode we have to send pushes to all resources, but in gateway-mode we send it only to bare JID
 
	if (m_component->inServerMode()) {
 
		std::vector<Swift::Presence::ref> presences = m_component->getPresenceOracle()->getAllPresence(m_user->getJID().toBare());
 
		BOOST_FOREACH(Swift::Presence::ref presence, presences) {
 
			Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(payload, presence->getFrom(), m_component->getIQRouter());
 
			request->onResponse.connect(boost::bind(&RosterManager::handleBuddyRosterPushResponse, this, _1, request, buddy->getName()));
 
			request->send();
 
			m_requests.push_back(request);
 
		}
 
	}
 
	else {
 
		Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(payload, m_user->getJID().toBare(), m_component->getIQRouter());
 
		request->onResponse.connect(boost::bind(&RosterManager::handleBuddyRosterPushResponse, this, _1, request, buddy->getName()));
 
		request->send();
 
		m_requests.push_back(request);
src/rosterresponder.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/rosterresponder.h"
 

	
 
#include <iostream>
 
#include <boost/bind.hpp>
 
#include "Swiften/Queries/IQRouter.h"
 
#include "Swiften/Swiften.h"
 
#include "transport/user.h"
 
#include "transport/usermanager.h"
 
#include "transport/rostermanager.h"
 
#include "transport/buddy.h"
 
#include "log4cxx/logger.h"
 

	
 
using namespace log4cxx;
 
#include "transport/logging.h"
 

	
 
using namespace Swift;
 
using namespace boost;
 

	
 
namespace Transport {
 

	
 
static LoggerPtr logger = Logger::getLogger("RosterResponder");
 
DEFINE_LOGGER(logger, "RosterResponder");
 

	
 
RosterResponder::RosterResponder(Swift::IQRouter *router, UserManager *userManager) : Swift::Responder<RosterPayload>(router) {
 
	m_userManager = userManager;
 
}
 

	
 
RosterResponder::~RosterResponder() {
 
}
 

	
 
bool RosterResponder::handleGetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<Swift::RosterPayload> payload) {
 
	// Get means we're in server mode and user wants to fetch his roster.
 
	// For now we send empty reponse, but TODO: Get buddies from database and send proper stored roster.
 
	User *user = m_userManager->getUser(from.toBare().toString());
 
	if (!user) {
 
		sendResponse(from, id, boost::shared_ptr<RosterPayload>(new RosterPayload()));
 
		LOG4CXX_WARN(logger, from.toBare().toString() << ": User is not logged in");
 
		return true;
 
	}
 
	sendResponse(from, id, user->getRosterManager()->generateRosterPayload());
 
	user->getRosterManager()->sendCurrentPresences(from);
 
	return true;
 
}
 

	
 
bool RosterResponder::handleSetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<Swift::RosterPayload> payload) {
 
	sendResponse(from, id, boost::shared_ptr<RosterPayload>(new RosterPayload()));
 

	
 
	User *user = m_userManager->getUser(from.toBare().toString());
 
	if (!user) {
 
		LOG4CXX_WARN(logger, from.toBare().toString() << ": User is not logged in");
 
		return true;
 
	}
 

	
 
	if (payload->getItems().size() == 0) {
 
		LOG4CXX_WARN(logger, from.toBare().toString() << ": Roster push with no item");
 
		return true;
 
	}
 

	
 
	Swift::RosterItemPayload item = payload->getItems()[0];
 

	
 
	Buddy *buddy = user->getRosterManager()->getBuddy(Buddy::JIDToLegacyName(item.getJID()));
 
	if (buddy) {
 
		if (item.getSubscription() == Swift::RosterItemPayload::Remove) {
 
			LOG4CXX_INFO(logger, from.toBare().toString() << ": Removing buddy " << buddy->getName());
 
			onBuddyRemoved(buddy);
 

	
 
			// send roster push here
 
			Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(payload, user->getJID().toBare(), user->getComponent()->getIQRouter());
 
			request->send();
 
		}
 
		else {
 
			LOG4CXX_INFO(logger, from.toBare().toString() << ": Updating buddy " << buddy->getName());
 
			onBuddyUpdated(buddy, item);
 
		}
 
	}
 
	else if (item.getSubscription() != Swift::RosterItemPayload::Remove) {
 
		// Roster push for this new buddy is sent by RosterManager
 
		BuddyInfo buddyInfo;
 
		buddyInfo.id = -1;
 
		buddyInfo.alias = item.getName();
 
		buddyInfo.legacyName = Buddy::JIDToLegacyName(item.getJID());
 
		buddyInfo.subscription = "both";
 
		buddyInfo.flags = Buddy::buddFlagsFromJID(item.getJID());
 
		LOG4CXX_INFO(logger, from.toBare().toString() << ": Adding buddy " << buddyInfo.legacyName);
 

	
 
		buddy = user->getComponent()->getFactory()->createBuddy(user->getRosterManager(), buddyInfo);
 
		user->getRosterManager()->setBuddy(buddy);
 
		onBuddyAdded(buddy, item);
 
	}
 

	
 
	return true;
 
}
 

	
 
}
src/sqlite3backend.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
 
 */
 

	
 
#ifdef WITH_SQLITE
 

	
 
#include "transport/sqlite3backend.h"
 
#include "transport/util.h"
 
#include "transport/logging.h"
 
#include <boost/bind.hpp>
 
#include "log4cxx/logger.h"
 

	
 
using namespace log4cxx;
 

	
 
#define SQLITE_DB_VERSION 3
 
#define CHECK_DB_RESPONSE(stmt) \
 
	if(stmt) { \
 
		sqlite3_exec(m_db, "ROLLBACK;", NULL, NULL, NULL); \
 
		return 0; \
 
	}
 

	
 
// Prepare the SQL statement
 
#define PREP_STMT(sql, str) \
 
	if(sqlite3_prepare_v2(m_db, std::string(str).c_str(), -1, &sql, NULL)) { \
 
		LOG4CXX_ERROR(logger, str<< (sqlite3_errmsg(m_db) == NULL ? "" : sqlite3_errmsg(m_db))); \
 
		return false; \
 
	}
 

	
 
// Finalize the prepared statement
 
#define FINALIZE_STMT(prep) \
 
	if(prep != NULL) { \
 
		sqlite3_finalize(prep); \
 
	}
 
	
 
#define BEGIN(STATEMENT) 	sqlite3_reset(STATEMENT);\
 
							int STATEMENT##_id = 1;\
 
							int STATEMENT##_id_get = 0;\
 
							(void)STATEMENT##_id_get;
 

	
 
#define BIND_INT(STATEMENT, VARIABLE) sqlite3_bind_int(STATEMENT, STATEMENT##_id++, VARIABLE)
 
#define BIND_STR(STATEMENT, VARIABLE) sqlite3_bind_text(STATEMENT, STATEMENT##_id++, VARIABLE.c_str(), -1, SQLITE_STATIC)
 
#define RESET_GET_COUNTER(STATEMENT)	STATEMENT##_id_get = 0;
 
#define GET_INT(STATEMENT)	sqlite3_column_int(STATEMENT, STATEMENT##_id_get++)
 
#define GET_STR(STATEMENT)	(const char *) sqlite3_column_text(STATEMENT, STATEMENT##_id_get++)
 
#define EXECUTE_STATEMENT(STATEMENT, NAME) 	if(sqlite3_step(STATEMENT) != SQLITE_DONE) {\
 
		LOG4CXX_ERROR(logger, NAME<< (sqlite3_errmsg(m_db) == NULL ? "" : sqlite3_errmsg(m_db)));\
 
			}
 

	
 
using namespace boost;
 

	
 
namespace Transport {
 

	
 
static LoggerPtr logger = Logger::getLogger("SQLite3Backend");
 
DEFINE_LOGGER(logger, "SQLite3Backend");
 

	
 
SQLite3Backend::SQLite3Backend(Config *config) {
 
	m_config = config;
 
	m_db = NULL;
 
	m_prefix = CONFIG_STRING(m_config, "database.prefix");
 
}
 

	
 
SQLite3Backend::~SQLite3Backend(){
 
	if (m_db) {
 
		// Would be nice to use this:
 
		//
 
		//   sqlite3_stmt *pStmt;
 
		//   while((pStmt = sqlite3_next_stmt(db, 0)) != 0 ) {
 
		//    sqlite3_finalize(pStmt);
 
		//   }
 
		//
 
		// But requires SQLite3 >= 3.6.0 beta
 
	
 
		FINALIZE_STMT(m_setUser);
 
		FINALIZE_STMT(m_getUser);
 
		FINALIZE_STMT(m_removeUser);
 
		FINALIZE_STMT(m_removeUserBuddies);
 
		FINALIZE_STMT(m_removeUserSettings);
 
		FINALIZE_STMT(m_removeUserBuddiesSettings);
 
		FINALIZE_STMT(m_addBuddy);
 
		FINALIZE_STMT(m_updateBuddy);
 
		FINALIZE_STMT(m_getBuddies);
 
		FINALIZE_STMT(m_getBuddiesSettings);
 
		FINALIZE_STMT(m_getUserSetting);
 
		FINALIZE_STMT(m_setUserSetting);
 
		FINALIZE_STMT(m_updateUserSetting);
 
		FINALIZE_STMT(m_updateBuddySetting);
 
		FINALIZE_STMT(m_setUserOnline);
 
		FINALIZE_STMT(m_getOnlineUsers);
 
		sqlite3_close(m_db);
 
	}
 
}
 

	
 
bool SQLite3Backend::connect() {
 
	LOG4CXX_INFO(logger, "Opening database " << CONFIG_STRING(m_config, "database.database"));
 
	if (sqlite3_open(CONFIG_STRING(m_config, "database.database").c_str(), &m_db)) {
 
		sqlite3_close(m_db);
 
		return false;
 
	}
 

	
 
	sqlite3_busy_timeout(m_db, 1500);
 

	
 
	if (createDatabase() == false)
 
		return false;
 

	
 
	PREP_STMT(m_setUser, "INSERT OR REPLACE INTO " + m_prefix + "users (jid, uin, password, language, encoding, last_login, vip) VALUES (?, ?, ?, ?, ?, DATETIME('NOW'), ?)");
 
	PREP_STMT(m_getUser, "SELECT id, jid, uin, password, encoding, language, vip FROM " + m_prefix + "users WHERE jid=?");
 

	
 
	PREP_STMT(m_removeUser, "DELETE FROM " + m_prefix + "users WHERE id=?");
 
	PREP_STMT(m_removeUserBuddies, "DELETE FROM " + m_prefix + "buddies WHERE user_id=?");
 
	PREP_STMT(m_removeUserSettings, "DELETE FROM " + m_prefix + "users_settings WHERE user_id=?");
 
	PREP_STMT(m_removeUserBuddiesSettings, "DELETE FROM " + m_prefix + "buddies_settings WHERE user_id=?");
 

	
 
	PREP_STMT(m_addBuddy, "INSERT INTO " + m_prefix + "buddies (user_id, uin, subscription, groups, nickname, flags) VALUES (?, ?, ?, ?, ?, ?)");
 
	PREP_STMT(m_updateBuddy, "UPDATE " + m_prefix + "buddies SET groups=?, nickname=?, flags=?, subscription=? WHERE user_id=? AND uin=?");
 
	PREP_STMT(m_getBuddies, "SELECT id, uin, subscription, nickname, groups, flags FROM " + m_prefix + "buddies WHERE user_id=? ORDER BY id ASC");
 
	PREP_STMT(m_getBuddiesSettings, "SELECT buddy_id, type, var, value FROM " + m_prefix + "buddies_settings WHERE user_id=? ORDER BY buddy_id ASC");
 
	PREP_STMT(m_updateBuddySetting, "INSERT OR REPLACE INTO " + m_prefix + "buddies_settings (user_id, buddy_id, var, type, value) VALUES (?, ?, ?, ?, ?)");
 
	
 
	PREP_STMT(m_getUserSetting, "SELECT type, value FROM " + m_prefix + "users_settings WHERE user_id=? AND var=?");
 
	PREP_STMT(m_setUserSetting, "INSERT INTO " + m_prefix + "users_settings (user_id, var, type, value) VALUES (?,?,?,?)");
 
	PREP_STMT(m_updateUserSetting, "UPDATE " + m_prefix + "users_settings SET value=? WHERE user_id=? AND var=?");
 

	
 
	PREP_STMT(m_setUserOnline, "UPDATE " + m_prefix + "users SET online=?, last_login=DATETIME('NOW') WHERE id=?");
 
	PREP_STMT(m_getOnlineUsers, "SELECT jid FROM " + m_prefix + "users WHERE online=1");
 

	
 
	return true;
 
}
 

	
 
bool SQLite3Backend::createDatabase() {
 
	int not_exist = exec("CREATE TABLE " + m_prefix + "buddies ("
 
				"  id INTEGER PRIMARY KEY NOT NULL,"
 
				"  user_id int(10) NOT NULL,"
 
				"  uin varchar(255) NOT NULL,"
 
				"  subscription varchar(20) NOT NULL,"
 
				"  nickname varchar(255) NOT NULL,"
 
				"  groups varchar(255) NOT NULL,"
 
				"  flags int(4) NOT NULL DEFAULT '0'"
 
				");");
 

	
 
	if (not_exist) {
 
		exec("CREATE UNIQUE INDEX IF NOT EXISTS user_id ON " + m_prefix + "buddies (user_id, uin);");
 

	
 
		exec("CREATE TABLE IF NOT EXISTS " + m_prefix + "buddies_settings ("
 
					"  user_id int(10) NOT NULL,"
 
					"  buddy_id int(10) NOT NULL,"
 
					"  var varchar(50) NOT NULL,"
 
					"  type int(4) NOT NULL,"
 
					"  value varchar(255) NOT NULL,"
 
					"  PRIMARY KEY (buddy_id, var)"
 
					");");
src/statsresponder.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/statsresponder.h"
 

	
 
#include <iostream>
 
#include <boost/bind.hpp>
 
#include "Swiften/Queries/IQRouter.h"
 
#include "transport/BlockPayload.h"
 
#include "Swiften/Swiften.h"
 
#include "transport/usermanager.h"
 
#include "transport/user.h"
 
#include "transport/buddy.h"
 
#include "transport/rostermanager.h"
 
#include "transport/memoryusage.h"
 
#include "transport/conversationmanager.h"
 
#include "transport/rostermanager.h"
 
#include "transport/usermanager.h"
 
#include "transport/networkpluginserver.h"
 
#include "log4cxx/logger.h"
 

	
 
using namespace log4cxx;
 
#include "transport/logging.h"
 

	
 
using namespace Swift;
 
using namespace boost;
 

	
 
namespace Transport {
 

	
 
static LoggerPtr logger = Logger::getLogger("StatsResponder");
 
DEFINE_LOGGER(logger, "StatsResponder");
 

	
 
StatsResponder::StatsResponder(Component *component, UserManager *userManager, NetworkPluginServer *server, StorageBackend *storageBackend) : Swift::Responder<StatsPayload>(component->getIQRouter()) {
 
	m_component = component;
 
	m_userManager = userManager;
 
	m_server = server;
 
	m_storageBackend = storageBackend;
 
	m_start = time(0);
 
}
 

	
 
StatsResponder::~StatsResponder() {
 
	
 
}
 

	
 
unsigned long StatsResponder::usedMemory() {
 
	double shared = 0;
 
	double rss = 0;
 
#ifndef WIN32
 
	process_mem_usage(shared, rss);
 
#endif
 
	rss -= shared;
 

	
 
	const std::list <NetworkPluginServer::Backend *> &backends = m_server->getBackends();
 
	BOOST_FOREACH(NetworkPluginServer::Backend * backend, backends) {
 
		rss += backend->res - backend->shared;
 
	}
 

	
 
	return (unsigned long) rss;
 
}
 

	
 
bool StatsResponder::handleGetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<StatsPayload> stats) {
 
	boost::shared_ptr<StatsPayload> response(new StatsPayload());
 

	
 
	if (stats->getItems().empty()) {
 
		response->addItem(StatsPayload::Item("uptime"));
 
		response->addItem(StatsPayload::Item("users/online"));
 
		response->addItem(StatsPayload::Item("contacts/online"));
 
		response->addItem(StatsPayload::Item("contacts/total"));
 
		response->addItem(StatsPayload::Item("messages/from-xmpp"));
 
		response->addItem(StatsPayload::Item("messages/to-xmpp"));
 
		response->addItem(StatsPayload::Item("backends/running"));
 
		response->addItem(StatsPayload::Item("backends/crashed"));
 
		response->addItem(StatsPayload::Item("memory-usage"));
 
	}
 
	else {
 
		unsigned long contactsOnline = 0;
 
		unsigned long contactsTotal = 0;
 

	
 
		Swift::StatusShow s;
 
		std::string statusMessage;
 
		for (std::map<std::string, User *>::const_iterator it = m_userManager->getUsers().begin(); it != m_userManager->getUsers().end(); it++) {
 
			if (!(*it).second) {
 
				continue;
 
			}
 
			const RosterManager::BuddiesMap &buddies = (*it).second->getRosterManager()->getBuddies();
 
			contactsTotal += buddies.size();
 
			for(RosterManager::BuddiesMap::const_iterator bt = buddies.begin(); bt != buddies.end(); bt++) {
 
				if (!(*bt).second) {
 
					continue;
 
				}
 
				if (!(*bt).second->getStatus(s, statusMessage))
 
					continue;
 
				if (s.getType() != Swift::StatusShow::None) {
 
					contactsOnline++;
 
				}
 
			}
 
		}
 

	
 
		BOOST_FOREACH(const StatsPayload::Item &item, stats->getItems()) {
 
			if (item.getName() == "uptime") {
 
				response->addItem(StatsPayload::Item("uptime", "seconds", boost::lexical_cast<std::string>(time(0) - m_start)));
 
			}
 
			else if (item.getName() == "users/online") {
 
				response->addItem(StatsPayload::Item("users/online", "users", boost::lexical_cast<std::string>(m_userManager->getUserCount())));
 
			}
 
			else if (item.getName() == "backends/running") {
 
				response->addItem(StatsPayload::Item("backends/running", "backends", boost::lexical_cast<std::string>(m_server->getBackendCount())));
 
			}
 
			else if (item.getName() == "backends/crashed") {
 
				response->addItem(StatsPayload::Item("backends/crashed", "backends", boost::lexical_cast<std::string>(m_server->getCrashedBackends().size())));
 
			}
 
			else if (item.getName() == "memory-usage") {
 
				response->addItem(StatsPayload::Item("memory-usage", "KB", boost::lexical_cast<std::string>(usedMemory())));
 
			}
 
			else if (item.getName() == "contacts/online") {
 
				response->addItem(StatsPayload::Item("contacts/online", "contacts", boost::lexical_cast<std::string>(contactsOnline)));
 
			}
 
			else if (item.getName() == "contacts/total") {
 
				response->addItem(StatsPayload::Item("contacts/total", "contacts", boost::lexical_cast<std::string>(contactsTotal)));
 
			}
 
			else if (item.getName() == "messages/from-xmpp") {
 
				response->addItem(StatsPayload::Item("messages/from-xmpp", "messages", boost::lexical_cast<std::string>(m_userManager->getMessagesToBackend())));
 
			}
 
			else if (item.getName() == "messages/to-xmpp") {
 
				response->addItem(StatsPayload::Item("messages/to-xmpp", "messages", boost::lexical_cast<std::string>(m_userManager->getMessagesToXMPP())));
 
			}
 
		}
src/storageresponder.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 "storageresponder.h"
 

	
 
#include <iostream>
 
#include <boost/bind.hpp>
 
#include "Swiften/Queries/IQRouter.h"
 
#include "Swiften/Elements/RawXMLPayload.h"
 
#include "Swiften/Swiften.h"
 
#include "transport/usermanager.h"
 
#include "transport/user.h"
 
#include "log4cxx/logger.h"
 

	
 
using namespace log4cxx;
 
#include "transport/logging.h"
 

	
 
using namespace Swift;
 
using namespace boost;
 

	
 
namespace Transport {
 

	
 
static LoggerPtr logger = Logger::getLogger("StorageResponder");
 
DEFINE_LOGGER(logger, "StorageResponder");
 

	
 
StorageResponder::StorageResponder(Swift::IQRouter *router, StorageBackend *storageBackend, UserManager *userManager) : Swift::Responder<PrivateStorage>(router) {
 
	m_storageBackend = storageBackend;
 
	m_userManager = userManager;
 
}
 

	
 
StorageResponder::~StorageResponder() {
 
}
 

	
 
bool StorageResponder::handleGetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<Swift::PrivateStorage> payload) {
 
	User *user = m_userManager->getUser(from.toBare().toString());
 
	if (!user) {
 
		LOG4CXX_WARN(logger, from.toBare().toString() << ": User is not logged in");
 
		sendError(from, id, ErrorPayload::NotAcceptable, ErrorPayload::Cancel);
 
		return true;
 
	}
 

	
 
	int type = 0;
 
	std::string value = "";
 
	m_storageBackend->getUserSetting(user->getUserInfo().id, "storage", type, value);
 
	LOG4CXX_INFO(logger, from.toBare().toString() << ": Sending jabber:iq:storage");
 

	
 
	sendResponse(from, id, boost::shared_ptr<PrivateStorage>(new PrivateStorage(boost::shared_ptr<RawXMLPayload>(new RawXMLPayload(value)))));
 
	return true;
 
}
 

	
 
bool StorageResponder::handleSetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<Swift::PrivateStorage> payload) {
 
	User *user = m_userManager->getUser(from.toBare().toString());
 
	if (!user) {
 
		sendError(from, id, ErrorPayload::NotAcceptable, ErrorPayload::Cancel);
 
		LOG4CXX_WARN(logger, from.toBare().toString() << ": User is not logged in");
 
		return true;
 
	}
 

	
 
	boost::shared_ptr<Storage> storage = boost::dynamic_pointer_cast<Storage>(payload->getPayload());
 

	
 
	if (storage) {
 
		StorageSerializer serializer;
 
		std::string value = serializer.serializePayload(boost::dynamic_pointer_cast<Storage>(payload->getPayload()));
 
		m_storageBackend->updateUserSetting(user->getUserInfo().id, "storage", value);
 
		LOG4CXX_INFO(logger, from.toBare().toString() << ": Storing jabber:iq:storage");
 
		sendResponse(from, id, boost::shared_ptr<PrivateStorage>());
 
	}
 
	else {
 
		LOG4CXX_INFO(logger, from.toBare().toString() << ": Unknown element. Libtransport does not support serialization of this.");
 
		sendError(from, id, ErrorPayload::NotAcceptable, ErrorPayload::Cancel);
 
	}
 
	return true;
 
}
 

	
 
}
src/tests/main.cpp
Show inline comments
 
#include "main.h"
 
#include <cppunit/CompilerOutputter.h>
 
#include <cppunit/extensions/TestFactoryRegistry.h>
 
#include <cppunit/TestResult.h>
 
#include <cppunit/TestResultCollector.h>
 
#include <cppunit/TestRunner.h>
 
#include <cppunit/BriefTestProgressListener.h>
 
#ifdef WITH_LOG4CXX
 
#include "log4cxx/logger.h"
 
#include "log4cxx/fileappender.h"
 
#include "log4cxx/patternlayout.h"
 
#include "log4cxx/propertyconfigurator.h"
 

	
 
using namespace log4cxx;
 
#endif
 

	
 

	
 
int main (int argc, char* argv[])
 
{
 
#ifdef WITH_LOG4CXX
 
	LoggerPtr root = Logger::getRootLogger();
 
	root->addAppender(new FileAppender(new PatternLayout("%d %-5p %c: %m%n"), "libtransport_test.log", false));
 
#endif
 

	
 
	// informs test-listener about testresults
 
	CPPUNIT_NS :: TestResult testresult;
 

	
 
	// register listener for collecting the test-results
 
	CPPUNIT_NS :: TestResultCollector collectedresults;
 
	testresult.addListener (&collectedresults);
 

	
 
	// register listener for per-test progress output
 
	CPPUNIT_NS :: BriefTestProgressListener progress;
 
	testresult.addListener (&progress);
 

	
 
	// insert test-suite at test-runner by registry
 
	CPPUNIT_NS :: TestRunner testrunner;
 
	testrunner.addTest (CPPUNIT_NS :: TestFactoryRegistry :: getRegistry ().makeTest ());
 
	testrunner.run (testresult);
 

	
 
	// output results in compiler-format
 
	CPPUNIT_NS :: CompilerOutputter compileroutputter (&collectedresults, std::cerr);
 
	compileroutputter.write ();
 

	
 
	// return 0 if tests were successful
 
	return collectedresults.wasSuccessful () ? 0 : 1;
 
}
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/algorithm/string/predicate.hpp>
 
#include "transport/storagebackend.h"
 
#include "transport/factory.h"
 
#include "transport/userregistry.h"
 
#include "transport/logging.h"
 
#include "discoinforesponder.h"
 
#include "discoitemsresponder.h"
 
#include "storageparser.h"
 
#include "Swiften/TLS/OpenSSL/OpenSSLServerContext.h"
 
#include "Swiften/TLS/PKCS12Certificate.h"
 
#include "Swiften/TLS/OpenSSL/OpenSSLServerContextFactory.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 "transport/BlockParser.h"
 
#include "transport/BlockSerializer.h"
 
#include "Swiften/Parser/PayloadParsers/InvisibleParser.h"
 
#include "Swiften/Serializer/PayloadSerializers/InvisibleSerializer.h"
 
#include "log4cxx/logger.h"
 
#include "log4cxx/consoleappender.h"
 
#include "log4cxx/patternlayout.h"
 
#include "log4cxx/propertyconfigurator.h"
 
#include "Swiften/Swiften.h"
 

	
 
using namespace Swift;
 
using namespace boost;
 
using namespace log4cxx;
 

	
 
namespace Transport {
 
	
 
static LoggerPtr logger = Logger::getLogger("Component");
 
static LoggerPtr logger_xml = Logger::getLogger("Component.XML");
 
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()) {
 
			LOG4CXX_INFO(logger, "Using PKCS#12 certificate " << CONFIG_STRING(m_config, "service.cert"));
 
			LOG4CXX_INFO(logger, "SSLv23_server_method used.");
 
			TLSServerContextFactory *f = new OpenSSLServerContextFactory();
 
			m_server->addTLSEncryption(f, PKCS12Certificate(CONFIG_STRING(m_config, "service.cert"), createSafeByteArray(CONFIG_STRING(m_config, "service.cert_password"))));
 
		}
 
		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->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->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_discoItemsResponder = new DiscoItemsResponder(m_iqRouter);
 
	m_discoItemsResponder->start();
 

	
src/user.cpp
Show inline comments
 
/**
 
 * libtransport -- C++ library for easy XMPP Transports development
 
 *
 
 * Copyright (C) 2011, Jan Kaluza <hanzz.k@gmail.com>
 
 *
 
 * This program is free software; you can redistribute it and/or modify
 
 * it under the terms of the GNU General Public License as published by
 
 * the Free Software Foundation; either version 2 of the License, or
 
 * (at your option) any later version.
 
 *
 
 * This program is distributed in the hope that it will be useful,
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
 * GNU General Public License for more details.
 
 *
 
 * You should have received a copy of the GNU General Public License
 
 * along with this program; if not, write to the Free Software
 
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
 
 */
 

	
 
#include "transport/user.h"
 
#include "transport/transport.h"
 
#include "transport/storagebackend.h"
 
#include "transport/rostermanager.h"
 
#include "transport/usermanager.h"
 
#include "transport/conversationmanager.h"
 
#include "transport/presenceoracle.h"
 
#include "transport/logging.h"
 
#include "Swiften/Swiften.h"
 
#include "Swiften/Server/ServerStanzaChannel.h"
 
#include "Swiften/Elements/StreamError.h"
 
#include "Swiften/Elements/MUCPayload.h"
 
#include "Swiften/Elements/SpectrumErrorPayload.h"
 
#include "log4cxx/logger.h"
 
#include <boost/foreach.hpp>
 
#include <stdio.h>
 
#include <stdlib.h>
 

	
 
using namespace log4cxx;
 
using namespace boost;
 

	
 
#define foreach         BOOST_FOREACH
 

	
 
namespace Transport {
 

	
 
static LoggerPtr logger = Logger::getLogger("User");
 
DEFINE_LOGGER(logger, "User");
 

	
 
User::User(const Swift::JID &jid, UserInfo &userInfo, Component *component, UserManager *userManager) {
 
	m_jid = jid.toBare();
 
	m_data = NULL;
 

	
 
	m_component = component;
 
	m_presenceOracle = component->m_presenceOracle;
 
	m_entityCapsManager = component->m_entityCapsManager;
 
	m_userManager = userManager;
 
	m_userInfo = userInfo;
 
	m_connected = false;
 
	m_readyForConnect = false;
 
	m_ignoreDisconnect = false;
 
	m_resources = 0;
 
	m_reconnectCounter = 0;
 

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

	
 
	m_rosterManager = new RosterManager(this, m_component);
 
	m_conversationManager = new ConversationManager(this, m_component);
 
	LOG4CXX_INFO(logger, m_jid.toString() << ": Created");
 
	updateLastActivity();
 
}
 

	
 
User::~User(){
 
	LOG4CXX_INFO(logger, m_jid.toString() << ": Destroying");
 
	if (m_component->inServerMode()) {
 
		dynamic_cast<Swift::ServerStanzaChannel *>(m_component->getStanzaChannel())->finishSession(m_jid, boost::shared_ptr<Swift::Element>());
 
	}
 

	
 
	m_reconnectTimer->stop();
 
	delete m_rosterManager;
 
	delete m_conversationManager;
 
}
 

	
 
const Swift::JID &User::getJID() {
 
	return m_jid;
 
}
 

	
 
Swift::JID User::getJIDWithFeature(const std::string &feature) {
 
	Swift::JID jid;
 
	std::vector<Swift::Presence::ref> presences = m_presenceOracle->getAllPresence(m_jid);
 

	
 
	foreach(Swift::Presence::ref presence, presences) {
 
		if (presence->getType() == Swift::Presence::Unavailable)
 
			continue;
 

	
 
		Swift::DiscoInfo::ref discoInfo = m_entityCapsManager->getCaps(presence->getFrom());
 
		if (!discoInfo) {
 
#ifdef SUPPORT_LEGACY_CAPS
 
			if (m_legacyCaps.find(presence->getFrom()) != m_legacyCaps.end()) {
 
				discoInfo = m_legacyCaps[presence->getFrom()];
 
			}
 
			else {
 
				continue;
 
			}
 

	
 
			if (!discoInfo) {
 
				continue;
 
			}
 
#else
 
			continue;
 
#endif
 
		}
 

	
 
		if (discoInfo->hasFeature(feature)) {
 
			LOG4CXX_INFO(logger, m_jid.toString() << ": Found JID with " << feature << " feature: " << presence->getFrom().toString());
 
			return presence->getFrom();
 
		}
 
	}
 

	
 
	LOG4CXX_INFO(logger, m_jid.toString() << ": No JID with " << feature << " feature " << m_legacyCaps.size());
 
	return jid;
 
}
 

	
 
Swift::DiscoInfo::ref User::getCaps(const Swift::JID &jid) const {
 
	Swift::DiscoInfo::ref discoInfo = m_entityCapsManager->getCaps(jid);
 
#ifdef SUPPORT_LEGACY_CAPS
 
	if (!discoInfo) {
 
		std::map<Swift::JID, Swift::DiscoInfo::ref>::const_iterator it = m_legacyCaps.find(jid);
 
		if (it != m_legacyCaps.end()) {
 
			discoInfo = it->second;
 
		}
 
	}
 
#endif
 
	return discoInfo;
 
}
 

	
 
void User::sendCurrentPresence() {
 
	if (m_component->inServerMode()) {
 
		return;
 
	}
 

	
 
	std::vector<Swift::Presence::ref> presences = m_presenceOracle->getAllPresence(m_jid);
 
	foreach(Swift::Presence::ref presence, presences) {
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 "storageresponder.h"
 
#include "log4cxx/logger.h"
 

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

	
 
using namespace log4cxx;
 

	
 
namespace Transport {
 

	
 
static LoggerPtr logger = Logger::getLogger("UserManager");
 
DEFINE_LOGGER(logger, "UserManager");
 

	
 
UserManager::UserManager(Component *component, UserRegistry *userRegistry, 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;
 

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

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

	
 
	onUserDestroyed(user);
 
	delete user;
 
#ifndef WIN32
 
	malloc_trim(0);
 
#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();
 
}
 

	
src/userregistration.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/userregistration.h"
 
#include "transport/usermanager.h"
 
#include "transport/storagebackend.h"
 
#include "transport/transport.h"
 
#include "transport/rostermanager.h"
 
#include "transport/user.h"
 
#include "transport/logging.h"
 
#include "Swiften/Elements/ErrorPayload.h"
 
#include <boost/shared_ptr.hpp>
 
#include <boost/thread.hpp>
 
#include <boost/date_time/posix_time/posix_time.hpp>
 
#include "log4cxx/logger.h"
 

	
 
using namespace Swift;
 
using namespace log4cxx;
 

	
 
namespace Transport {
 

	
 
static LoggerPtr logger = Logger::getLogger("UserRegistration");
 
DEFINE_LOGGER(logger, "UserRegistration");
 

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

	
 
UserRegistration::~UserRegistration(){
 
}
 

	
 
bool UserRegistration::registerUser(const UserInfo &row) {
 
	UserInfo user;
 
	bool registered = m_storageBackend->getUser(row.jid, user);
 
	// This user is already registered
 
	if (registered)
 
		return false;
 

	
 
	m_storageBackend->setUser(row);
 

	
 
	Swift::Presence::ref response = Swift::Presence::create();
 
	response->setFrom(m_component->getJID());
 
	response->setTo(Swift::JID(row.jid));
 
	response->setType(Swift::Presence::Subscribe);
 
	m_component->getStanzaChannel()->sendPresence(response);
 

	
 
	onUserRegistered(row);
 
	return true;
 
}
 

	
 
bool UserRegistration::unregisterUser(const std::string &barejid) {
 
	UserInfo userInfo;
 
	bool registered = m_storageBackend->getUser(barejid, userInfo);
 
	// This user is not registered
 
	if (!registered)
 
		return false;
 

	
 
	onUserUnregistered(userInfo);
 

	
 
	// We have to check if server supports remoteroster XEP and use it if it's supported or fallback to unsubscribe otherwise
 
	AddressedRosterRequest::ref request = AddressedRosterRequest::ref(new AddressedRosterRequest(m_component->getIQRouter(), barejid));
 
	request->onResponse.connect(boost::bind(&UserRegistration::handleUnregisterRemoteRosterResponse, this, _1, _2, barejid));
 
	request->send();
 

	
 
	return true;
 
}
 

	
 
void UserRegistration::handleUnregisterRemoteRosterResponse(boost::shared_ptr<Swift::RosterPayload> payload, Swift::ErrorPayload::ref remoteRosterNotSupported /*error*/, const std::string &barejid) {
 
	UserInfo userInfo;
 
	bool registered = m_storageBackend->getUser(barejid, userInfo);
 
	// This user is not registered
 
	if (!registered)
 
		return;
 

	
 
	if (remoteRosterNotSupported) {
 
		std::list <BuddyInfo> roster;
 
		m_storageBackend->getBuddies(userInfo.id, roster);
 
		for(std::list<BuddyInfo>::iterator u = roster.begin(); u != roster.end() ; u++){
 
			std::string name = Swift::JID::getEscapedNode((*u).legacyName);
 

	
 
			Swift::Presence::ref response;
 
			response = Swift::Presence::create();
 
			response->setTo(Swift::JID(barejid));
 
			response->setFrom(Swift::JID(name, m_component->getJID().toString()));
 
			response->setType(Swift::Presence::Unsubscribe);
 
			m_component->getStanzaChannel()->sendPresence(response);
 

	
 
			response = Swift::Presence::create();
 
			response->setTo(Swift::JID(barejid));
 
			response->setFrom(Swift::JID(name, m_component->getJID().toString()));
 
			response->setType(Swift::Presence::Unsubscribed);
 
			m_component->getStanzaChannel()->sendPresence(response);
 
		}
 
	}
 
	else {
 
		BOOST_FOREACH(Swift::RosterItemPayload it, payload->getItems()) {
 
			Swift::RosterPayload::ref p = Swift::RosterPayload::ref(new Swift::RosterPayload());
 
			Swift::RosterItemPayload item;
 
			item.setJID(it.getJID());
 
			item.setSubscription(Swift::RosterItemPayload::Remove);
 

	
 
			p->addItem(item);
 

	
 
			Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(p, barejid, m_component->getIQRouter());
 
			request->send();
 
		}
 
	}
 

	
 
	// Remove user from database
 
	m_storageBackend->removeUser(userInfo.id);
 

	
 
	// Disconnect the user
 
	User *user = m_userManager->getUser(barejid);
 
	if (user) {
 
		m_userManager->removeUser(user);
 
	}
src/userregistry.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 <string>
 
#include <map>
 
#include "Swiften/Swiften.h"
 
#include "Swiften/Server/UserRegistry.h"
 
#include "transport/userregistry.h"
 
#include "log4cxx/logger.h"
 

	
 
using namespace log4cxx;
 
#include "transport/logging.h"
 

	
 
namespace Transport {
 

	
 
static LoggerPtr logger = Logger::getLogger("UserRegistry");
 
DEFINE_LOGGER(logger, "UserRegistry");
 

	
 
UserRegistry::UserRegistry(Config *cfg, Swift::NetworkFactories *factories) {
 
	config = cfg;
 
	m_removeTimer = factories->getTimerFactory()->createTimer(1);
 
	m_inRemoveLater = false;
 
}
 

	
 
UserRegistry::~UserRegistry() { m_removeTimer->stop(); }
 

	
 
void UserRegistry::isValidUserPassword(const Swift::JID& user, Swift::ServerFromClientSession *session, const Swift::SafeByteArray& password) {
 
	if (!CONFIG_STRING(config, "service.admin_jid").empty() && user.toBare().toString() == CONFIG_STRING(config, "service.admin_jid")) {
 
		if (Swift::safeByteArrayToString(password) == CONFIG_STRING(config, "service.admin_password")) {
 
			session->handlePasswordValid();
 
		}
 
		else {
 
			session->handlePasswordInvalid();
 
		}
 
		return;
 
	}
 

	
 
	std::string key = user.toBare().toString();
 

	
 
	// Users try to connect twice
 
	if (users.find(key) != users.end()) {
 
		// Kill the first session
 
		LOG4CXX_INFO(logger, key << ": Removing previous session and making this one active");
 
		Swift::ServerFromClientSession *tmp = users[key].session;
 
		users[key].session = session;
 
		tmp->handlePasswordInvalid();
 
	}
 

	
 
	LOG4CXX_INFO(logger, key << ": Connecting this user to find if password is valid");
 

	
 
	users[key].password = Swift::safeByteArrayToString(password);
 
	users[key].session = session;
 
	onConnectUser(user);
 

	
 
	return;
 
}
 

	
 
void UserRegistry::stopLogin(const Swift::JID& user, Swift::ServerFromClientSession *session) {
 
	std::string key = user.toBare().toString();
 
	if (users.find(key) != users.end()) {
 
		if (users[key].session == session) {
 
			LOG4CXX_INFO(logger, key << ": Stopping login process (user probably disconnected while logging in)");
 
			users.erase(key);
 
		}
 
		else {
 
			LOG4CXX_WARN(logger, key << ": Stopping login process (user probably disconnected while logging in), but this is not active session");
 
		}
 
	}
 
	else {
 
		LOG4CXX_WARN(logger, key << ": Stopping login process (user probably disconnected while logging in) for invalid user");
 
	}
 

	
 
	// ::removeLater can be called only by libtransport, not by Swift and libtransport
 
	// takes care about user disconnecting itself, so don't call our signal.
 
	if (!m_inRemoveLater)
 
		onDisconnectUser(user);
 
}
 

	
 
void UserRegistry::onPasswordValid(const Swift::JID &user) {
 
	std::string key = user.toBare().toString();
 
	if (users.find(key) != users.end()) {
 
		LOG4CXX_INFO(logger, key << ": Password is valid");
 
		users[key].session->handlePasswordValid();
 
		users.erase(key);
 
	}
 
	else {
 
		LOG4CXX_INFO(logger, key << ": onPasswordValid called for invalid user");
 
	}
 
}
 

	
 
void UserRegistry::onPasswordInvalid(const Swift::JID &user, const std::string &error) {
 
	std::string key = user.toBare().toString();
 
	if (users.find(key) != users.end()) {
 
		LOG4CXX_INFO(logger, key << ": Password is invalid");
 
		users[key].session->handlePasswordInvalid(error);
 
		users.erase(key);
 
	}
 
	else {
 
		LOG4CXX_INFO(logger, key << ": onPasswordInvalid called for invalid user");
 
	}
 
}
 

	
 
void UserRegistry::handleRemoveTimeout(const Swift::JID &user) {
 
	m_inRemoveLater = true;
 
	onPasswordInvalid(user);
 
	m_inRemoveLater = false;
 
}
 

	
 
void UserRegistry::removeLater(const Swift::JID &user) {
 
	m_removeTimer->onTick.connect(boost::bind(&UserRegistry::handleRemoveTimeout, this, user));
 
	m_removeTimer->start();
 
}
 

	
src/usersreconnecter.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/usersreconnecter.h"
 

	
 
#include <iostream>
 
#include <boost/bind.hpp>
 
#include "Swiften/Queries/IQRouter.h"
 
#include "Swiften/Swiften.h"
 
#include "transport/storagebackend.h"
 
#include "transport/transport.h"
 
#include "log4cxx/logger.h"
 

	
 
using namespace log4cxx;
 
#include "transport/logging.h"
 

	
 
using namespace Swift;
 
using namespace boost;
 

	
 
namespace Transport {
 

	
 
static LoggerPtr logger = Logger::getLogger("UserReconnecter");
 
DEFINE_LOGGER(logger, "UserReconnecter");
 

	
 
UsersReconnecter::UsersReconnecter(Component *component, StorageBackend *storageBackend) {
 
	m_component = component;
 
	m_storageBackend = storageBackend;
 
	m_started = false;
 

	
 
	m_nextUserTimer = m_component->getNetworkFactories()->getTimerFactory()->createTimer(1000);
 
	m_nextUserTimer->onTick.connect(boost::bind(&UsersReconnecter::reconnectNextUser, this));
 

	
 
	m_component->onConnected.connect(bind(&UsersReconnecter::handleConnected, this));
 
}
 

	
 
UsersReconnecter::~UsersReconnecter() {
 
	m_component->onConnected.disconnect(bind(&UsersReconnecter::handleConnected, this));
 
	m_nextUserTimer->stop();
 
	m_nextUserTimer->onTick.disconnect(boost::bind(&UsersReconnecter::reconnectNextUser, this));
 
}
 

	
 
void UsersReconnecter::reconnectNextUser() {
 
	if (m_users.empty()) {
 
		LOG4CXX_INFO(logger, "All users reconnected, stopping UserReconnecter.");
 
		return;
 
	}
 

	
 
	std::string user = m_users.back();
 
	m_users.pop_back();
 

	
 
	LOG4CXX_INFO(logger, "Sending probe presence to " << user);
 
	Swift::Presence::ref response = Swift::Presence::create();
 
	response->setTo(user);
 
	response->setFrom(m_component->getJID());
 
	response->setType(Swift::Presence::Probe);
 

	
 
	m_component->getStanzaChannel()->sendPresence(response);
 
	m_nextUserTimer->start();
 
}
 

	
 
void UsersReconnecter::handleConnected() {
 
	if (m_started)
 
		return;
 

	
 
	LOG4CXX_INFO(logger, "Starting UserReconnecter.");
 
	m_started = true;
 

	
 
	m_storageBackend->getOnlineUsers(m_users);
 

	
 
	reconnectNextUser();
 
}
 

	
 

	
 
}
src/vcardresponder.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/vcardresponder.h"
 

	
 
#include <iostream>
 
#include <boost/bind.hpp>
 
#include "Swiften/Queries/IQRouter.h"
 
#include "Swiften/Swiften.h"
 
#include "transport/user.h"
 
#include "transport/usermanager.h"
 
#include "transport/rostermanager.h"
 
#include "transport/transport.h"
 
#include "log4cxx/logger.h"
 

	
 
using namespace log4cxx;
 
#include "transport/logging.h"
 

	
 
using namespace Swift;
 
using namespace boost;
 

	
 
namespace Transport {
 

	
 
static LoggerPtr logger = Logger::getLogger("VCardResponder");
 
DEFINE_LOGGER(logger, "VCardResponder");
 

	
 
VCardResponder::VCardResponder(Swift::IQRouter *router, Swift::NetworkFactories *factories, UserManager *userManager) : Swift::Responder<VCard>(router) {
 
	m_id = 0;
 
	m_userManager = userManager;
 
	m_collectTimer = factories->getTimerFactory()->createTimer(20000);
 
	m_collectTimer->onTick.connect(boost::bind(&VCardResponder::collectTimeouted, this));
 
	m_collectTimer->start();
 
}
 

	
 
VCardResponder::~VCardResponder() {
 
}
 

	
 
void VCardResponder::sendVCard(unsigned int id, boost::shared_ptr<Swift::VCard> vcard) {
 
	if (m_queries.find(id) == m_queries.end()) {
 
		LOG4CXX_WARN(logger, "Unexpected VCard from legacy network with id " << id);
 
		return;
 
	}
 

	
 
	LOG4CXX_INFO(logger, m_queries[id].from.toString() << ": Forwarding VCard of " << m_queries[id].to.toString() << " from legacy network");
 

	
 
	sendResponse(m_queries[id].from, m_queries[id].to, m_queries[id].id, vcard);
 
	m_queries.erase(id);
 
}
 

	
 
void VCardResponder::collectTimeouted() {
 
	time_t now = time(NULL);
 

	
 
	std::vector<unsigned int> candidates;
 
	for(std::map<unsigned int, VCardData>::iterator it = m_queries.begin(); it != m_queries.end(); it++) {
 
		if (now - (*it).second.received > 40) {
 
			candidates.push_back((*it).first);
 
		}
 
	}
 

	
 
	if (candidates.size() != 0) {
 
		LOG4CXX_INFO(logger, "Removing " << candidates.size() << " timeouted VCard requests");
 
	}
 

	
 
	BOOST_FOREACH(unsigned int id, candidates) {
 
		sendVCard(id, boost::shared_ptr<Swift::VCard>(new Swift::VCard()));
 
	}
 
	m_collectTimer->start();
 
}
 

	
 
bool VCardResponder::handleGetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<Swift::VCard> payload) {
 
	// Get means we're in server mode and user wants to fetch his roster.
 
	// For now we send empty reponse, but TODO: Get buddies from database and send proper stored roster.
 
	User *user = m_userManager->getUser(from.toBare().toString());
 
	if (!user) {
 
		LOG4CXX_WARN(logger, from.toBare().toString() << ": User is not logged in");
 
		return false;
 
	}
 

	
 
	Swift::JID to_ = to;
 

	
 
	std::string name = to_.getUnescapedNode();
 
	if (name.empty()) {
 
		to_ = user->getJID();
 
	}
 

	
 
	name = Buddy::JIDToLegacyName(to_);
 

	
 
	LOG4CXX_INFO(logger, from.toBare().toString() << ": Requested VCard of " << name);
 

	
 
	m_queries[m_id].from = from;
 
	m_queries[m_id].to = to_;
 
	m_queries[m_id].id = id; 
 
	m_queries[m_id].received = time(NULL);
 
	onVCardRequired(user, name, m_id++);
 
	return true;
 
}
 

	
 
bool VCardResponder::handleSetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<Swift::VCard> payload) {
 
	if (!to.getNode().empty()) {
 
		LOG4CXX_WARN(logger, from.toBare().toString() << ": Tried to set VCard of somebody else");
 
		return false;
 
	}
 

	
 
	User *user = m_userManager->getUser(from.toBare().toString());
 
	if (!user) {
 
		LOG4CXX_WARN(logger, from.toBare().toString() << ": User is not logged in");
 
		return false;
 
	}
 

	
 
	LOG4CXX_INFO(logger, from.toBare().toString() << ": Setting VCard");
 
	onVCardUpdated(user, payload);
 

	
 
	sendResponse(from, id, boost::shared_ptr<VCard>(new VCard()));
 
	return true;
 
}
 

	
 
}
0 comments (0 inline, 0 general)