Changeset - 1aba0d0d2eed
[Not reviewed]
0 7 0
Vitaly Takmazov - 13 years ago 2013-02-03 13:10:17
vitalyster@gmail.com
Fixed osx compilation
7 files changed with 51 insertions and 5 deletions:
0 comments (0 inline, 0 general)
CMakeLists.txt
Show inline comments
 
cmake_minimum_required(VERSION 2.6)
 
project(libtransport)
 

	
 
message(STATUS "Variables to override default places where to find libraries:")
 
message(STATUS "|- cppunit : -DCPPUNIT_INCLUDE_DIR,  -DCPPUNIT_LIBRARY")
 
message(STATUS "|- swiften : -DSWIFTEN_INCLUDE_DIR,  -DSWIFTEN_LIBRARY")
 
message(STATUS "  |- zlib  :                         -DZLIB_LIBRARY")
 
message(STATUS "  |- expat :                         -DEXPAT_LIBRARY")
 
message(STATUS "  |-libidn :                         -DLIBIDN_LIBRARY")
 
message(STATUS "  |-libxml :                         -DLIBXML_LIBRARY")
 
message(STATUS "|- boost   : -DBOOST_INCLUDEDIR,     -DBOOST_LIBRARYDIR")
 
message(STATUS "|- protobuf: -DPROTOBUF_INCLUDE_DIR, -DPROTOBUF_LIBRARY")
 
message(STATUS "           : -DPROTOBUF_PROTOC_EXECUTABLE")
 
message(STATUS "|- log4cxx : -DLOG4CXX_INCLUDE_DIR,  -DLOG4CXX_LIBRARY")
 
message(STATUS "|- purple  : -DPURPLE_INCLUDE_DIR,   -DPURPLE_LIBRARY")
 
message(STATUS "           : -DPURPLE_NOT_RUNTIME - enables compilation with libpurple.lib")
 

	
 
option(ENABLE_SQLITE3 "Build with SQLite3 support" ON)
 
option(ENABLE_MYSQL "Build with MySQL support" ON)
 
option(ENABLE_PQXX "Build with Postgres supoort" ON)
 

	
 
option(ENABLE_FROTZ "Build Frotz plugin" ON)
 
option(ENABLE_IRC "Build IRC plugin" ON)
 
option(ENABLE_PURPLE "Build Libpurple plugin" ON)
 
option(ENABLE_SMSTOOLS3 "Build SMSTools3 plugin" ON)
 
option(ENABLE_SKYPE "Build Skype plugin" ON)
 
option(ENABLE_SWIFTEN "Build Swiften plugin" ON)
 
option(ENABLE_TWITTER "Build Twitter plugin" ON)
 
option(ENABLE_YAHOO2 "Build Libyahoo2 plugin" ON)
 

	
 
option(ENABLE_DOCS "Build Docs" ON)
 
# option(ENABLE_LOG "Build with logging using Log4cxx" ON)
 
option(ENABLE_TESTS "Build Tests using CppUnit" OFF)
 

	
 
MACRO(LIST_CONTAINS var value)
 
	SET(${var})
 
	FOREACH (value2 ${ARGN})
 
		IF (${value} STREQUAL ${value2})
 
		SET(${var} TRUE)
 
		ENDIF (${value} STREQUAL ${value2})
 
	ENDFOREACH (value2)
 
ENDMACRO(LIST_CONTAINS)
 

	
 
if(NOT LIB_INSTALL_DIR)
 
	set(LIB_INSTALL_DIR "lib")
 
endif()
 

	
 
set(CMAKE_MODULE_PATH "cmake_modules")
 

	
 
###### Prerequisites ######
 

	
 

	
 
# FIND SWIFTEN
 

	
 
set(Swiften_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
 
find_package(Swiften)
 

	
 
if(NOT SWIFTEN_FOUND)
 
	if (ZLIB_LIBRARY)
 
		set(SWIFTEN_LIBRARY ${SWIFTEN_LIBRARY} ${ZLIB_LIBRARY})
 
	endif()
 
	if (EXPAT_LIBRARY)
 
		set(SWIFTEN_LIBRARY ${SWIFTEN_LIBRARY} ${EXPAT_LIBRARY})
 
	endif()
 
	if (LIBIDN_LIBRARY)
 
		set(SWIFTEN_LIBRARY ${SWIFTEN_LIBRARY} ${LIBIDN_LIBRARY})
 
	endif()
 
	if (LIBXML_LIBRARY)
 
		set(SWIFTEN_LIBRARY ${SWIFTEN_LIBRARY} ${LIBXML_LIBRARY})
 
	endif()
 
	set(SWIFTEN_LIBRARY ${SWIFTEN_LIBRARY} "Dnsapi")
 
	set(SWIFTEN_LIBRARY ${SWIFTEN_LIBRARY} "Crypt32")
 
	set(SWIFTEN_LIBRARY ${SWIFTEN_LIBRARY} "Secur32")
 
	set(SWIFTEN_LIBRARY ${SWIFTEN_LIBRARY} "Iphlpapi")
 
	set(SWIFTEN_LIBRARY ${SWIFTEN_LIBRARY} "Winscard")
 
	message(STATUS "Using swiften: ${SWIFTEN_INCLUDE_DIR} ${SWIFTEN_LIBRARY}")
 
endif()
 

	
 
# FIND BOOST
 
set(Boost_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
 
if (WIN32)
 
	set(Boost_USE_STATIC_LIBS      ON)
 
	set(Boost_USE_MULTITHREADED      ON)
 
	set(Boost_USE_STATIC_RUNTIME    OFF)
 
	find_package(Boost COMPONENTS program_options date_time system filesystem regex thread signals REQUIRED)
 
else(WIN32)
 
	LIST_CONTAINS(contains -lboost_program_options ${SWIFTEN_LIBRARY})
 
	if(contains)
 
		message(STATUS "Using non-multithreaded boost")
 
		set(Boost_USE_MULTITHREADED 0)
 
	endif(contains)
 
	set(Boost_FIND_QUIETLY ON)
 
	find_package(Boost COMPONENTS program_options date_time system filesystem regex thread-mt signals)
 
	if (NOT Boost_FOUND)
 
		set(Boost_FIND_QUIETLY OFF)
 
		find_package(Boost COMPONENTS program_options date_time system filesystem regex thread signals REQUIRED)
 
	endif()
 
endif(WIN32)
 

	
 
message( STATUS "Found Boost: ${Boost_LIBRARIES}, ${Boost_INCLUDE_DIR}")
 

	
 
# FIND POPT
 
if (NOT WIN32)
 
	set(popt_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
 
	find_package(popt REQUIRED)
 
endif()
 

	
 
###### Database ######
 

	
 
# FIND SQLITE3
 
if (ENABLE_SQLITE3)
 
	if (NOT CMAKE_COMPILER_IS_GNUCXX)
 
	if (MSVC)
 
		ADD_SUBDIRECTORY(${CMAKE_SOURCE_DIR}/msvc-deps)
 
	else()
 
		if (WIN32)
 
			ADD_SUBDIRECTORY(${CMAKE_SOURCE_DIR}/msvc-deps/sqlite3)
 
		else()
 
			set(sqlite3_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
 
			find_package(sqlite3)
 
		endif()
 
	endif()
 
endif()
 

	
 
# FIND MYSQL
 
if(ENABLE_MYSQL)
 
	set(mysql_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
 
	find_package(mysql)
 
endif()
 

	
 
# FIND PQXX
 
if(ENABLE_PQXX)
 
	set(pqxx_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
 
	find_package(pqxx)
 
endif()
 

	
 
###### Plugins ######
 

	
 
# FIND LIBPURPLE
 
if(ENABLE_PURPLE)
 
	set(purple_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
 
	find_package(purple)
 

	
 
	if (WIN32)
 
		if (PURPLE_NOT_RUNTIME)
 
			add_definitions(-DPURPLE_RUNTIME=0)
 
		else(PURPLE_NOT_RUNTIME)
 
			add_definitions(-DPURPLE_RUNTIME=1)
 
		endif(PURPLE_NOT_RUNTIME)
 
	else()
 
		add_definitions(-DPURPLE_RUNTIME=0)
 
	endif()
 

	
 
	# FIND LIBEVENT
 
	set(event_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
 
	find_package(event)
 
endif()
 

	
 
# FIND GLIB
 
if(ENABLE_SKYPE OR ENABLE_PURPLE)
 
#	if (GLIB2_INCLUDE_DIR AND GLIB2_LIBRARIES)
 
#		set(GLIB2_FOUND TRUE)
 
#	else()
 
		set(glib_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
 
		find_package(glib)
 
#	endif()
 
endif()
 

	
 
# FIND LIBXML2
 
# set(libxml2_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
 
# find_package(libxml2)
 

	
 
# FIND PROTOBUF
 
set(Protobuf_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
 
find_package(Protobuf REQUIRED)
 

	
 
if (NOT PROTOBUF_FOUND AND PROTOBUF_INCLUDE_DIR AND PROTOBUF_LIBRARY)
 
	set(PROTOBUF_FOUND 1)
 
	set(PROTOBUF_INCLUDE_DIRS ${PROTOBUF_INCLUDE_DIR})
 
	if (PROTOBUF_PROTOC_EXECUTABLE)
 
	else()
 
		set(PROTOBUF_PROTOC_EXECUTABLE protoc)
 
	endif()
 
	message(STATUS "Using protobuf: ${PROTOBUF_INCLUDE_DIRS} ${PROTOBUF_LIBRARY}")
 
endif()
 

	
 
if (WIN32)
 
	add_definitions(-DSWIFTEN_STATIC=1)
 
	ADD_DEFINITIONS(-D_UNICODE)
 
	ADD_DEFINITIONS(-DUNICODE)
 
endif()
 

	
 

	
 
if (CMAKE_COMPILER_IS_GNUCXX)
 
set(openssl_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
 
find_package(openssl)
 
endif()
 

	
 
if(ENABLE_IRC)
 
	set(Communi_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
 
	find_package(Communi)
 

	
 
	INCLUDE(FindQt4)
 
	FIND_PACKAGE(Qt4 COMPONENTS QtCore QtNetwork)
 
	# ADD_DEFINITIONS(${SWIFTEN_CFLAGS})
 
	ADD_DEFINITIONS(-DSUPPORT_LEGACY_CAPS)
 
	# ADD_DEFINITIONS(-DBOOST_FILESYSTEM_VERSION=2)
 
endif()
 

	
 
set(event_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
 
find_package(event)
 

	
 
if (NOT WIN32 AND ENABLE_SKYPE)
 
set(dbus_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
 
find_package(dbus)
 
endif()
 

	
 
# if(ENABLE_YAHOO2)
 
# 	set(yahoo2_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
 
# 	find_package(yahoo2)
 
# endif()
 

	
 
####### Miscallanous ######
 

	
 
if(ENABLE_DOCS)
 
	find_package(Doxygen)
 
endif()
 

	
 
# if(ENABLE_LOG)
 
	if(LOG4CXX_INCLUDE_DIR AND LOG4CXX_LIBRARY)
 
		set(LOG4CXX_LIBRARIES ${LOG4CXX_LIBRARY})
 
		set(LOG4CXX_FOUND 1)
 
		message(STATUS "Using log4cxx: ${CPPUNIT_INCLUDE_DIR} ${LOG4CXX_INCLUDE_DIR}")
 
	else()
 
		set(log4cxx_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
 
		find_package(log4cxx)
 
	endif()
 
# endif()
 

	
 
# FIND CPPUNIT
 
if(ENABLE_TESTS)
 
	set(cppunit_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
 
	find_package(cppunit)
 

	
 
	if(NOT CPPUNIT_FOUND AND CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARY)
 
		set(CCPUNIT_LIBRARIES ${CPPUNIT_LIBRARY})
 
		set(CPPUNIT_FOUND 1)
 
		message(STATUS "Using cppunit: ${CPPUNIT_INCLUDE_DIR} ${CPPUNIT_LIBRARIES}")
 
	endif()
 
endif()
 

	
 
if (APPLE)
 
        FIND_LIBRARY(IOKIT_FRAMEWORK IOKit)
 
        FIND_LIBRARY(SECURITY_FRAMEWORK Security)
 
        FIND_LIBRARY(APPKIT_FRAMEWORK AppKit)
 
        FIND_LIBRARY(SYSTEMCONFIGURATION_FRAMEWORK SystemConfiguration)
 
        FIND_LIBRARY(SECURITYINTERFACE_FRAMEWORK SecurityInterface)
 
        MARK_AS_ADVANCED(IOKIT_FRAMEWORK APPKIT_FRAMEWORK SYSTEMCONFIGURATION_FRAMEWORK SECURITY_FRAMEWORK SECURITYINTERFACE_FRAMEWORK)
 
        SET (APPLE_FRAMEWORKS ${IOKIT_FRAMEWORK} ${APPKIT_FRAMEWORK} ${SYSTEMCONFIGURATION_FRAMEWORK} ${SECURITY_FRAMEWORK} ${SECURITYINTERFACE_FRAMEWORK})
 
endif()
 

	
 
message("  Supported features")
 
message("-----------------------")
 

	
 
if (SPECTRUM_VERSION)
 
	ADD_DEFINITIONS(-DSPECTRUM_VERSION="${SPECTRUM_VERSION}")
 
else (SPECTRUM_VERSION)
 
	if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git)
 
		if (NOT GIT_EXECUTABLE)
 
		set (GIT_EXECUTABLE git)
 
		endif()
 
		execute_process(COMMAND ${GIT_EXECUTABLE} "--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)
 
	if (WIN32)
 
		ADD_DEFINITIONS(-DWITH_SQLITE)
 
		include_directories("${CMAKE_SOURCE_DIR}/msvc-deps/sqlite3")
 
		message("SQLite3           : bundled")
 
	else()
 
		set(SQLITE3_LIBRARIES "")
 
		if(ENABLE_SQLITE3)
 
			message("SQLite3           : no (install sqlite3)")
 
		else(ENABLE_SQLITE3)
 
			message("SQLite3           : no (user disabled)")
 
		endif()
 
	endif()
 
endif (SQLITE3_FOUND)
 

	
 
if (MYSQL_FOUND)
 
	ADD_DEFINITIONS(-DWITH_MYSQL)
 
	include_directories(${MYSQL_INCLUDE_DIR})
 
	message("MySQL             : yes")
 
else (MYSQL_FOUND)
 
	set(MYSQL_LIBRARIES "")
 
	if(ENABLE_MYSQL)
 
		message("MySQL             : no (install mysql-devel)")
 
	else(ENABLE_MYSQL)
 
		message("MySQL             : no (user disabled)")
 
	endif()
 
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 "")
 
	if(ENABLE_PQXX)
 
		message("PostgreSQL        : no (install libpqxx-devel)")
 
	else(ENABLE_PQXX)
 
		message("PostgreSQL        : no (user disabled)")
 
	endif()
 
endif (PQXX_FOUND)
 

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

	
 
	if(PURPLE_FOUND)
 
		message("Libpurple plugin  : yes")
 
		include_directories(${PURPLE_INCLUDE_DIR})
 
		include_directories(${GLIB2_INCLUDE_DIR})
 
	else()
 
		if(ENABLE_PURPLE)
 
			message("Libpurple plugin  : no (install libpurple)")
 
		else(ENABLE_PURPLE)
 
			message("Libpurple plugin  : no (user disabled)")
 
		endif()
 
	endif()
 

	
 
	if (HAVE_EVENT)
 
		ADD_DEFINITIONS(-DWITH_LIBEVENT)
 
		include_directories(${EVENT_INCLUDE_DIRS})
 
		message("  libev eventloop : yes")
 
	else()
 
		if(ENABLE_PURPLE)
 
			message("  libev eventloop : no (install libev-devel)")
 
		endif()
 
	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()
 
		if(ENABLE_IRC)
 
			message("IRC plugin        : no (install libCommuni and libprotobuf-dev)")
 
		else(ENABLE_IRC)
 
			message("IRC plugin        : no (user disabled)")
 
		endif()
 
	endif()
 
	if(ENABLE_TWITTER)
 
		message("Twitter plugin    : yes")
 
	else(ENABLE_TWITTER)
 
		message("Twitter plugin    : no (user disabled)")
 
	endif()
 
	if (NOT WIN32)
 
		if(ENABLE_FROTZ)
 
			message("Frotz plugin      : yes")
 
		else()
 
			message("Frotz plugin      : no (user disabled)")
 
		endif()
 
		if(ENABLE_SMSTOOLS3)
 
			message("SMSTools3 plugin  : yes")
 
		else()
 
			message("SMSTools3 plugin  : no (user disabled)")
 
		endif()
 
		if(${LIBDBUSGLIB_FOUND})
 
			message("Skype plugin      : yes")
 
			include_directories(${LIBDBUSGLIB_INCLUDE_DIRS})
 
		else()
 
			if(ENABLE_SKYPE)
 
				message("Skype plugin      : no (install dbus-glib-devel)")
 
			else(ENABLE_SKYPE)
 
				message("Skype plugin      : no (user disabled)")
 
			endif()
 
		endif()
 
	else()
 
		message("Frotz plugin      : no (does not run on Win32)")
 
		message("SMSTools3 plugin  : no (does not run on Win32)")
 
		message("Skype plugin      : no (does not run on Win32)")
 
	endif()
 

	
 
#  	if(YAHOO2_FOUND)
 
# 		message("Libyahoo2 plugin  : yes")
 
#  		include_directories(${YAHOO2_INCLUDE_DIR})
 
# 	else()
 
		if(ENABLE_YAHOO2)
 
			set(YAHOO2_FOUND 1)
 
			message("Libyahoo2 plugin  : yes")
 
		else(ENABLE_YAHOO2)
 
			message("Libyahoo2 plugin  : no (user disabled)")
 
		endif()
 
#  	endif()
 

	
 
	if(ENABLE_SWIFTEN)
 
		message("Swiften plugin    : yes")
 
	else()
 
		message("Swiften plugin    : no (user disabled)")
 
	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)")
 
	message("Swiften plugin    : no (install libprotobuf-dev)")
 
    message("Twitter plugin    : no (install libprotobuf-dev)")
 
endif()
 

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

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

	
 
if(CMAKE_BUILD_TYPE MATCHES Debug)
 
	if (CMAKE_COMPILER_IS_GNUCXX)
 
		ADD_DEFINITIONS(-O0)
 
		ADD_DEFINITIONS(-ggdb)
 
	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})
 

	
 
if (CMAKE_COMPILER_IS_GNUCXX)
 
include_directories(${OPENSSL_INCLUDE_DIR})
 
endif()
 

	
 
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()
 
	if(ENABLE_TESTS)
 
		message("tests             : no (install CPPUnit)")
 
	else(ENABLE_TESTS)
 
		message("tests             : no (user disabled)")
 
	endif()
 
endif()
 

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

	
 
message("----------------------")
 

	
 
if(NOT SQLITE3_FOUND AND NOT MYSQL_FOUND AND NOT PQXX_FOUND)
 
	if(ENABLE_SQLITE3 OR ENABLE_MYSQL OR ENABLE_PQXX)
 
		message("Could not find any database - Please install at least one of sqlite3-devel, mysql-devel or pqxx-devel if you want to use transport mode.")
 
	else(ENABLE_SQLITE3 OR ENABLE_MYSQL OR ENABLE_PQXX)
 
		message("Please enable at least one of SQLITE3, MYSQL, PQXX databases to use transport mode.")
 
	endif()
 
endif()
 

	
backends/swiften/main.cpp
Show inline comments
 
// Transport includes
 
#include "transport/config.h"
 
#include "transport/networkplugin.h"
 
#include "transport/logging.h"
 

	
 
#include "boost/date_time/posix_time/posix_time.hpp"
 

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

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

	
 
#ifndef __FreeBSD__
 
#ifndef __MACH__
 
// malloc_trim
 
#include "malloc.h"
 
#endif
 
#endif
 

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

	
 
DEFINE_LOGGER(logger, "Swiften");
 

	
 
// eventloop
 
Swift::SimpleEventLoop *loop_;
 

	
 
// Plugins
 
class SwiftenPlugin;
 
NetworkPlugin *np = NULL;
 

	
 
class MUCController {
 
	public:
 
		MUCController(const std::string &user, boost::shared_ptr<Swift::Client> client, const std::string &room, const std::string &nickname, const std::string &password) {
 
			m_user = user;
 
			m_room = room;
 
			muc = client->getMUCManager()->createMUC(room);
 
			if (!password.empty()) {
 
				muc->setPassword(password);
 
			}
 

	
 
			muc->onJoinComplete.connect(boost::bind(&MUCController::handleJoinComplete, this, _1));
 
			muc->onJoinFailed.connect(boost::bind(&MUCController::handleJoinFailed, this, _1));
 
			muc->onOccupantJoined.connect(boost::bind(&MUCController::handleOccupantJoined, this, _1));
 
			muc->onOccupantPresenceChange.connect(boost::bind(&MUCController::handleOccupantPresenceChange, this, _1));
 
			muc->onOccupantLeft.connect(boost::bind(&MUCController::handleOccupantLeft, this, _1, _2, _3));
 
			muc->onOccupantRoleChanged.connect(boost::bind(&MUCController::handleOccupantRoleChanged, this, _1, _2, _3));
 
			muc->onOccupantAffiliationChanged.connect(boost::bind(&MUCController::handleOccupantAffiliationChanged, this, _1, _2, _3));
 

	
 
			muc->joinAs(nickname);
 
		}
 

	
 
		virtual ~MUCController() {
 
			muc->onJoinComplete.disconnect(boost::bind(&MUCController::handleJoinComplete, this, _1));
 
			muc->onJoinFailed.disconnect(boost::bind(&MUCController::handleJoinFailed, this, _1));
 
			muc->onOccupantJoined.disconnect(boost::bind(&MUCController::handleOccupantJoined, this, _1));
 
			muc->onOccupantPresenceChange.disconnect(boost::bind(&MUCController::handleOccupantPresenceChange, this, _1));
 
			muc->onOccupantLeft.disconnect(boost::bind(&MUCController::handleOccupantLeft, this, _1, _2, _3));
 
			muc->onOccupantRoleChanged.disconnect(boost::bind(&MUCController::handleOccupantRoleChanged, this, _1, _2, _3));
 
			muc->onOccupantAffiliationChanged.disconnect(boost::bind(&MUCController::handleOccupantAffiliationChanged, this, _1, _2, _3));
 
		}
 

	
 
		const std::string &getNickname() {
 
			//return muc->getCurrentNick();
 
			return m_nick;
 
		}
 

	
 
		void handleOccupantJoined(const Swift::MUCOccupant& occupant) {
 
			np->handleParticipantChanged(m_user, occupant.getNick(), m_room, occupant.getRole() == Swift::MUCOccupant::Moderator, pbnetwork::STATUS_ONLINE);
 
		}
 

	
 
		void handleOccupantLeft(const Swift::MUCOccupant& occupant, Swift::MUC::LeavingType type, const std::string& reason) {
 
			np->handleParticipantChanged(m_user, occupant.getNick(), m_room, occupant.getRole() == Swift::MUCOccupant::Moderator, pbnetwork::STATUS_NONE);
 
		}
 

	
 
		void handleOccupantPresenceChange(boost::shared_ptr<Swift::Presence> presence) {
 
			const Swift::MUCOccupant& occupant = muc->getOccupant(presence->getFrom().getResource());
 
			np->handleParticipantChanged(m_user, presence->getFrom().getResource(), m_room, (int) occupant.getRole() == Swift::MUCOccupant::Moderator, (pbnetwork::StatusType) presence->getShow(), presence->getStatus());
 
		}
 

	
 
		void handleOccupantRoleChanged(const std::string& nick, const Swift::MUCOccupant& occupant, const Swift::MUCOccupant::Role& oldRole) {
 

	
 
		}
 

	
 
		void handleOccupantAffiliationChanged(const std::string& nick, const Swift::MUCOccupant::Affiliation& affiliation, const Swift::MUCOccupant::Affiliation& oldAffiliation) {
 
// 			np->handleParticipantChanged(m_user, occupant->getNick(), m_room, (int) occupant.getRole() == Swift::MUCOccupant::Moderator, pbnetwork::STATUS_ONLINE);
 
		}
 

	
 
		void handleJoinComplete(const std::string& nick) {
 
			m_nick = nick;
 
		}
 

	
 
		void handleJoinFailed(boost::shared_ptr<Swift::ErrorPayload> error) {
 
			
 
		}
 

	
 
		void part() {
 
			muc->part();
 
		}
 

	
 
	private:
 
		Swift::MUC::ref muc;
 
		std::string m_user;
 
		std::string m_room;
 
		std::string m_nick;
 
};
 

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

	
 
		SwiftenPlugin(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(&SwiftenPlugin::_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 handleSwiftDisconnected(const std::string &user, const boost::optional<Swift::ClientError> &error) {
 
			std::string message = "";
 
			bool reconnect = false;
 
			if (error) {
 
				switch(error->getType()) {
 
					case Swift::ClientError::UnknownError: message = ("Unknown Error"); reconnect = true; break;
 
					case Swift::ClientError::DomainNameResolveError: message = ("Unable to find server"); break;
 
					case Swift::ClientError::ConnectionError: message = ("Error connecting to server"); break;
 
					case Swift::ClientError::ConnectionReadError: message = ("Error while receiving server data"); reconnect = true; break;
 
					case Swift::ClientError::ConnectionWriteError: message = ("Error while sending data to the server"); reconnect = true; break;
 
					case Swift::ClientError::XMLError: message = ("Error parsing server data"); reconnect = true; break;
 
					case Swift::ClientError::AuthenticationFailedError: message = ("Login/password invalid"); break;
 
					case Swift::ClientError::CompressionFailedError: message = ("Error while compressing stream"); break;
 
					case Swift::ClientError::ServerVerificationFailedError: message = ("Server verification failed"); break;
 
					case Swift::ClientError::NoSupportedAuthMechanismsError: message = ("Authentication mechanisms not supported"); break;
 
					case Swift::ClientError::UnexpectedElementError: message = ("Unexpected response"); break;
 
					case Swift::ClientError::ResourceBindError: message = ("Error binding resource"); break;
 
					case Swift::ClientError::SessionStartError: message = ("Error starting session"); break;
 
					case Swift::ClientError::StreamError: message = ("Stream error"); break;
 
					case Swift::ClientError::TLSError: message = ("Encryption error"); break;
 
					case Swift::ClientError::ClientCertificateLoadError: message = ("Error loading certificate (Invalid password?)"); break;
 
					case Swift::ClientError::ClientCertificateError: message = ("Certificate not authorized"); break;
 

	
 
					case Swift::ClientError::UnknownCertificateError: message = ("Unknown certificate"); break;
 
					case Swift::ClientError::CertificateExpiredError: message = ("Certificate has expired"); break;
 
					case Swift::ClientError::CertificateNotYetValidError: message = ("Certificate is not yet valid"); break;
 
					case Swift::ClientError::CertificateSelfSignedError: message = ("Certificate is self-signed"); break;
 
					case Swift::ClientError::CertificateRejectedError: message = ("Certificate has been rejected"); break;
 
					case Swift::ClientError::CertificateUntrustedError: message = ("Certificate is not trusted"); break;
 
					case Swift::ClientError::InvalidCertificatePurposeError: message = ("Certificate cannot be used for encrypting your connection"); break;
 
					case Swift::ClientError::CertificatePathLengthExceededError: message = ("Certificate path length constraint exceeded"); break;
 
					case Swift::ClientError::InvalidCertificateSignatureError: message = ("Invalid certificate signature"); break;
 
					case Swift::ClientError::InvalidCAError: message = ("Invalid Certificate Authority"); break;
 
					case Swift::ClientError::InvalidServerIdentityError: message = ("Certificate does not match the host identity"); break;
 
				}
 
			}
 
			LOG4CXX_INFO(logger, user << ": Disconnected " << message);
 
			handleDisconnected(user, reconnect ? 0 : 3, message);
 

	
 
			boost::shared_ptr<Swift::Client> client = m_users[user];
 
			if (client) {
 
				client->onConnected.disconnect(boost::bind(&SwiftenPlugin::handleSwiftConnected, this, user));
 
				client->onDisconnected.disconnect(boost::bind(&SwiftenPlugin::handleSwiftDisconnected, this, user, _1));
 
				client->onMessageReceived.disconnect(boost::bind(&SwiftenPlugin::handleSwiftMessageReceived, this, user, _1));
 
				m_users.erase(user);
 
				m_mucs.erase(user);
 
			}
 

	
 
#ifndef WIN32
 
#ifndef __FreeBSD__
 
#ifndef __MACH__
 
			// force returning of memory chunks allocated by libxml2 to kernel
 
			malloc_trim(0);
 
#endif
 
#endif
 
#endif
 
		}
 

	
 
		void handleSwiftConnected(const std::string &user) {
 
			LOG4CXX_INFO(logger, user << ": Connected to XMPP server.");
 
			handleConnected(user);
 
			m_users[user]->requestRoster();
 
			Swift::Presence::ref response = Swift::Presence::create();
 
			response->setFrom(m_users[user]->getJID());
 
			m_users[user]->sendPresence(response);
 
		}
 

	
 
		void handleSwiftRosterReceived(const std::string &user) {
 
			Swift::PresenceOracle *oracle = m_users[user]->getPresenceOracle();
 
			BOOST_FOREACH(const Swift::XMPPRosterItem &item, m_users[user]->getRoster()->getItems()) {
 
				Swift::Presence::ref lastPresence = oracle->getLastPresence(item.getJID());
 
				pbnetwork::StatusType status = lastPresence ? ((pbnetwork::StatusType) lastPresence->getShow()) : pbnetwork::STATUS_NONE;
 
				handleBuddyChanged(user, item.getJID().toBare().toString(),
 
								   item.getName(), item.getGroups(), status);
 
			}
 
		}
 

	
 
		void handleSwiftPresenceChanged(const std::string &user, Swift::Presence::ref presence) {
 
			boost::shared_ptr<Swift::Client> client = m_users[user];
 
			if (client->getMUCRegistry()->isMUC(presence->getFrom().toBare())) {
 
				return;
 
			}
 

	
 
			LOG4CXX_INFO(logger, user << ": " << presence->getFrom().toBare().toString() << " presence changed");
 

	
 
			std::string message = presence->getStatus();
 
			std::string photo = "";
 

	
 
			boost::shared_ptr<Swift::VCardUpdate> update = presence->getPayload<Swift::VCardUpdate>();
 
			if (update) {
 
				photo = update->getPhotoHash();
 
			}
 

	
 
			boost::optional<Swift::XMPPRosterItem> item = m_users[user]->getRoster()->getItem(presence->getFrom());
 
			if (item) {
 
				handleBuddyChanged(user, presence->getFrom().toBare().toString(), item->getName(), item->getGroups(), (pbnetwork::StatusType) presence->getShow(), message, photo);
 
			}
 
			else {
 
				std::vector<std::string> groups;
 
				handleBuddyChanged(user, presence->getFrom().toBare().toString(), presence->getFrom().toBare(), groups, (pbnetwork::StatusType) presence->getShow(), message, photo);
 
			}
 
		}
 

	
 
		void handleSwiftMessageReceived(const std::string &user, Swift::Message::ref message) {
 
			std::string body = message->getBody();
 
			boost::shared_ptr<Swift::Client> client = m_users[user];
 
			if (client) {
 
				if (message->getType() == Swift::Message::Groupchat) {
 
					boost::shared_ptr<Swift::Delay> delay = message->getPayload<Swift::Delay>();
 
					std::string timestamp = "";
 
					if (delay) {
 
						timestamp = boost::posix_time::to_iso_string(delay->getStamp());
 
					}
 
					handleMessage(user, message->getFrom().toBare().toString(), body, message->getFrom().getResource(), "", timestamp);
 
				}
 
				else {
 
					if (client->getMUCRegistry()->isMUC(message->getFrom().toBare())) {
 
						handleMessage(user, message->getFrom().toBare().toString(), body, message->getFrom().getResource(), "", "", false, true);
 
					}
 
					else {
 
						handleMessage(user, message->getFrom().toBare().toString(), body, "", "");
 
					}
 
				}
 
			}
 
		}
 

	
 
		void handleSwiftVCardReceived(const std::string &user, unsigned int id, Swift::VCard::ref vcard, Swift::ErrorPayload::ref error) {
 
			if (error || !vcard) {
 
				LOG4CXX_INFO(logger, user << ": error fetching VCard with id=" << id);
 
				handleVCard(user, id, "", "", "", "");
 
				return;
 
			}
 
			LOG4CXX_INFO(logger, user << ": VCard fetched - id=" << id);
 
			std::string photo((const char *)&vcard->getPhoto()[0], vcard->getPhoto().size());
 
			handleVCard(user, id, vcard->getFullName(), vcard->getFullName(), vcard->getNickname(), photo);
 
		}
 

	
 
		void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) {
 
			LOG4CXX_INFO(logger, user << ": connecting as " << legacyName);
 
			boost::shared_ptr<Swift::Client> client = boost::make_shared<Swift::Client>(Swift::JID(legacyName), password, m_factories);
 
			m_users[user] = client;
 
			client->setAlwaysTrustCertificates();
 
			client->onConnected.connect(boost::bind(&SwiftenPlugin::handleSwiftConnected, this, user));
 
			client->onDisconnected.connect(boost::bind(&SwiftenPlugin::handleSwiftDisconnected, this, user, _1));
 
			client->onMessageReceived.connect(boost::bind(&SwiftenPlugin::handleSwiftMessageReceived, this, user, _1));
 
			client->getRoster()->onInitialRosterPopulated.connect(boost::bind(&SwiftenPlugin::handleSwiftRosterReceived, this, user));
 
			client->getPresenceOracle()->onPresenceChange.connect(boost::bind(&SwiftenPlugin::handleSwiftPresenceChanged, this, user, _1));
 
			Swift::ClientOptions opt;
 
			opt.allowPLAINWithoutTLS = true;
 
			client->connect(opt);
 
		}
 

	
 
		void handleLogoutRequest(const std::string &user, const std::string &legacyName) {
 
			boost::shared_ptr<Swift::Client> client = m_users[user];
 
			if (client) {
 
				client->onConnected.disconnect(boost::bind(&SwiftenPlugin::handleSwiftConnected, this, user));
 
// 				client->onDisconnected.disconnect(boost::bind(&SwiftenPlugin::handleSwiftDisconnected, this, user, _1));
 
				client->onMessageReceived.disconnect(boost::bind(&SwiftenPlugin::handleSwiftMessageReceived, this, user, _1));
 
				client->getRoster()->onInitialRosterPopulated.disconnect(boost::bind(&SwiftenPlugin::handleSwiftRosterReceived, this, user));
 
				client->getPresenceOracle()->onPresenceChange.disconnect(boost::bind(&SwiftenPlugin::handleSwiftPresenceChanged, this, user, _1));
 
				client->disconnect();
 
				m_mucs.erase(user);
 
				m_users.erase(user);
 
			}
 
		}
 

	
 
		void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &msg, const std::string &xhtml = "", const std::string &id = "") {
 
			LOG4CXX_INFO(logger, "Sending message from " << user << " to " << legacyName << ".");
 
			boost::shared_ptr<Swift::Client> client = m_users[user];
 
			if (client) {
 
				boost::shared_ptr<Swift::Message> message(new Swift::Message());
 
				message->setTo(Swift::JID(legacyName));
 
				message->setFrom(client->getJID());
 
				message->setBody(msg);
 
				if (client->getMUCRegistry()->isMUC(legacyName)) {
 
					message->setType(Swift::Message::Groupchat);
 
					boost::shared_ptr<MUCController> muc = m_mucs[user][legacyName];
 
					handleMessage(user, legacyName, msg, muc->getNickname(), xhtml);
 
				}
 

	
 
				client->sendMessage(message);
 
			}
 
		}
 

	
 
		void handleVCardRequest(const std::string &user, const std::string &legacyName, unsigned int id) {
 
			boost::shared_ptr<Swift::Client> client = m_users[user];
 
			if (client) {
 
				LOG4CXX_INFO(logger, user << ": fetching VCard of " << legacyName << " id=" << id);
 
				Swift::GetVCardRequest::ref request = Swift::GetVCardRequest::create(Swift::JID(legacyName), client->getIQRouter());
 
				request->onResponse.connect(boost::bind(&SwiftenPlugin::handleSwiftVCardReceived, this, user, id, _1, _2));
 
				request->send();
 
			}
 
		}
 

	
 
		void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector<std::string> &groups) {
 
			boost::shared_ptr<Swift::Client> client = m_users[user];
 
			if (client) {
 
				LOG4CXX_INFO(logger, user << ": Added/Updated buddy " << buddyName << ".");
 
				if (!client->getRoster()->containsJID(buddyName)) {
 
					Swift::RosterItemPayload item;
 
					item.setName(alias);
 
					item.setJID(buddyName);
 
					item.setGroups(groups);
 
					boost::shared_ptr<Swift::RosterPayload> roster(new Swift::RosterPayload());
 
					roster->addItem(item);
 
					Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(roster, client->getIQRouter());
 
// 					request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster));
 
					request->send();
 
					client->getSubscriptionManager()->requestSubscription(buddyName);
 
				}
 
				else {
 
					Swift::JID contact(buddyName);
 
					Swift::RosterItemPayload item(contact, alias, client->getRoster()->getSubscriptionStateForJID(contact));
 
					item.setGroups(groups);
 
					boost::shared_ptr<Swift::RosterPayload> roster(new Swift::RosterPayload());
 
					roster->addItem(item);
 
					Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(roster, client->getIQRouter());
 
// 					request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster));
 
					request->send();
 
				}
 

	
 
			}
 
		}
 

	
 
		void handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector<std::string> &groups) {
 
			boost::shared_ptr<Swift::Client> client = m_users[user];
 
			if (client) {
 
				Swift::RosterItemPayload item(buddyName, "", Swift::RosterItemPayload::Remove);
 
				boost::shared_ptr<Swift::RosterPayload> roster(new Swift::RosterPayload());
 
				roster->addItem(item);
 
				Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(roster, client->getIQRouter());
 
// 				request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster));
 
				request->send();
 
			}
 
		}
 

	
 
		void handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &password) {
 
			boost::shared_ptr<Swift::Client> client = m_users[user];
 
			if (client) {
 
				if (client->getMUCRegistry()->isMUC(room)) {
 
					return;
 
				}
 

	
 
				boost::shared_ptr<MUCController> muc = boost::shared_ptr<MUCController>( new MUCController(user, client, room, nickname, password));
 
				m_mucs[user][room] = muc;
 
			}
 
		}
 

	
 
		void handleLeaveRoomRequest(const std::string &user, const std::string &room) {
 
			boost::shared_ptr<Swift::Client> client = m_users[user];
 
			if (client) {
 
				if (!client->getMUCRegistry()->isMUC(room)) {
 
					return;
 
				}
 

	
 
				boost::shared_ptr<MUCController> muc = m_mucs[user][room];
 
				if (!muc) {
 
					m_mucs[user].erase(room);
 
					return;
 
				}
 

	
 
				muc->part();
 
				m_mucs[user].erase(room);
 
			}
 
		}
 

	
 
	private:
 
		Config *config;
 
		std::map<std::string, boost::shared_ptr<Swift::Client> > m_users;
 
		std::map<std::string, std::map<std::string, boost::shared_ptr<MUCController> > > m_mucs;
 
};
 

	
 
#ifndef WIN32
 
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);
 
	}
 
}
 
#endif
 

	
 

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

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

	
 
	std::string error;
 
	Config *cfg = Config::createFromArgs(argc, argv, error, host, port);
 
	if (cfg == NULL) {
 
		std::cerr << error;
 
		return 1;
 
	}
 

	
 
	Logging::initBackendLogging(cfg);
 

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

	
 
	return 0;
 
}
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/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 "transport/discoitemsresponder.h"
 
#include "transport/adhocmanager.h"
 
#include "transport/settingsadhoccommand.h"
 
#include "Swiften/EventLoop/SimpleEventLoop.h"
 
#include "Swiften/Network/BoostNetworkFactories.h"
 
#include <boost/filesystem.hpp>
 
#include <boost/algorithm/string.hpp>
 
#ifndef WIN32
 
#include "sys/signal.h"
 
#include "sys/stat.h"
 
#include <pwd.h>
 
#include <grp.h>
 
#include <sys/resource.h>
 
#include "libgen.h"
 
#ifndef __FreeBSD__
 
#ifndef __MACH__
 
#include <malloc.h>
 
#endif
 
#endif
 
#else
 
#include <process.h>
 
#define getpid _getpid
 
#include "win32/ServiceWrapper.h"
 
#endif
 
#include <sys/stat.h>
 

	
 
using namespace Transport;
 
using namespace Transport::Util;
 

	
 
DEFINE_LOGGER(logger, "Spectrum");
 

	
 
Swift::SimpleEventLoop *eventLoop_ = NULL;
 
Component *component_ = NULL;
 
UserManager *userManager_ = NULL;
 
Config *config_ = 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);
 
}
 

	
 
#ifdef WIN32
 
BOOL spectrum_control_handler( DWORD fdwCtrlType ) { 
 
	if (fdwCtrlType == CTRL_C_EVENT || fdwCtrlType == CTRL_CLOSE_EVENT) {
 
		eventLoop_->postEvent(&stop_spectrum);
 
		return TRUE;
 
	}
 
	return FALSE;
 
} 
 
#endif
 

	
 
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
 

	
 
static void _createDirectories(Transport::Config *config, boost::filesystem::path ph) {
 
	if (ph.empty() || exists(ph)) {
 
		return;
 
	}
 

	
 
	// First create branch, by calling ourself recursively
 
	_createDirectories(config, ph.branch_path());
 
	
 
	// Now that parent's path exists, create the directory
 
	boost::filesystem::create_directory(ph);
 

	
 
#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(ph.string().c_str(), pw->pw_uid, gr->gr_gid);
 
	}
 
#endif
 
}
 

	
 
int mainloop() {
 

	
 
#ifndef WIN32
 
	mode_t old_cmask = umask(0007);
 
#endif
 

	
 
	Logging::initMainLogging(config_);
 

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

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

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

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

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

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

	
 
	Swift::SimpleEventLoop eventLoop;
 

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

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

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

	
 
	Logging::redirect_stderr();
 

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

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

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

	
 
		usersReconnecter = new UsersReconnecter(&transport, storageBackend);
 
	}
 
	else if (!CONFIG_BOOL(config_, "service.server_mode")) {
 
		LOG4CXX_WARN(logger, "Registrations won't work, you have specified [database] type=none in config file.");
 
	}
 

	
 
	FileTransferManager ftManager(&transport, &userManager);
 

	
 
	NetworkPluginServer plugin(&transport, config_, &userManager, &ftManager, &discoItemsResponder);
 
	plugin.start();
 

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

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

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

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

	
 
	SettingsAdHocCommandFactory settings;
 
	adhocmanager.addAdHocCommand(&settings);
 

	
 
	eventLoop_ = &eventLoop;
 

	
 
	eventLoop.run();
 

	
 
#ifndef WIN32
 
	umask(old_cmask);
 
#endif
 

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

	
 
	if (usersReconnecter) {
 
		delete usersReconnecter;
 
	}
 

	
 
	delete storageBackend;
 
	delete factories;
 
	return 0;
 
}
 

	
 

	
 
int main(int argc, char **argv)
 
{
 
	Config config(argc, argv);
 
	config_ = &config;
 
	boost::program_options::variables_map vm;
 
	bool no_daemon = false;
 
	std::string config_file;
 
	std::string jid;
 
#ifdef WIN32
 
	std::string install_service_name, uninstall_service_name, run_service_name;
 
	// determine the name of the currently executing file
 
	char szFilePath[MAX_PATH];
 
	GetModuleFileNameA(NULL, szFilePath, sizeof(szFilePath));
 
	std::string exe_file(szFilePath);					
 
#endif	
 
	setlocale(LC_ALL, "");
 
#ifndef WIN32
 
#ifndef __FreeBSD__
 
#ifndef __MACH__
 
	mallopt(M_CHECK_ACTION, 2);
 
	mallopt(M_PERTURB, 0xb);
 
#endif
 
#endif
 
#endif
 

	
 
#ifndef WIN32
 
	if (signal(SIGINT, spectrum_sigint_handler) == SIG_ERR) {
 
		std::cout << "SIGINT handler can't be set\n";
 
		return -1;
 
	}
 

	
 
	if (signal(SIGTERM, spectrum_sigterm_handler) == SIG_ERR) {
 
		std::cout << "SIGTERM handler can't be set\n";
 
		return -1;
 
	}
 
#else
 
	if( !SetConsoleCtrlHandler( (PHANDLER_ROUTINE) spectrum_control_handler, TRUE ) ) 
 
	{ 
 
		std::cout << "control handler can't be set\n";
 
		return -1;
 
	} 
 
#endif
 
	boost::program_options::options_description desc(std::string("Spectrum version: ") + SPECTRUM_VERSION + "\nUsage: spectrum [OPTIONS] <config_file.cfg>\nAllowed options");
 
	desc.add_options()
 
		("help,h", "help")
 
		("no-daemonize,n", "Do not run spectrum as daemon")
 
		("no-debug,d", "Create coredumps on crash")
 
		("jid,j", boost::program_options::value<std::string>(&jid)->default_value(""), "Specify JID of transport manually")
 
		("config", boost::program_options::value<std::string>(&config_file)->default_value(""), "Config file")
 
		("version,v", "Shows Spectrum version")
 
		;
 
#ifdef WIN32
 
 	desc.add_options()
 
		("install-service,i", boost::program_options::value<std::string>(&install_service_name)->default_value(""), "Install spectrum as Windows service")
 
 		("uninstall-service,u", boost::program_options::value<std::string>(&uninstall_service_name)->default_value(""), "Uninstall Windows service")
 
		("run-as-service,r", boost::program_options::value<std::string>(&run_service_name)->default_value(""), "stub for Windows Service Manager");
 
#endif
 
	try
 
	{
 
		boost::program_options::positional_options_description p;
 
		p.add("config", -1);
 
		boost::program_options::store(boost::program_options::command_line_parser(argc, argv).
 
          options(desc).positional(p).allow_unregistered().run(), vm);
 
		boost::program_options::notify(vm);
 

	
 
		if (vm.count("version")) {
 
			std::cout << SPECTRUM_VERSION << "\n";
 
			return 0;
 
		}
 

	
 
		if(vm.count("help"))
 
		{
 
			std::cout << desc << "\n";
 
			return 1;
 
		}
 

	
 
		if(vm.count("config") == 0) {
 
			std::cout << desc << "\n";
 
			return 1;
 
		}
 

	
 
		if(vm.count("no-daemonize")) {
 
			no_daemon = true;
 
		}
 
#ifdef WIN32	
 
		if (!install_service_name.empty()) {				
 
			// build command line for Service Manager
 
			std::string service_path = exe_file + std::string(" --config ") + vm["config"].as<std::string>() 
 
						+ std::string(" --run-as-service ") + install_service_name;													
 
		
 
			ServiceWrapper ntservice((char *)install_service_name.c_str());
 
			if (!ntservice.IsInstalled()) {
 
				if (ntservice.Install((char *)service_path.c_str())) {
 
					std::cout << "Successfully installed " << install_service_name << std::endl;
 
					return 0;
 
				} else {
 
					std::cout << "Error installing service, are you an Administrator?" << std::endl;
 
					return 1;
 
				}                				
 
			} else {
 
				std::cout << "Already installed " << install_service_name << std::endl;
 
				return 1;
 
			}
 
		}
 
		if (!uninstall_service_name.empty()) {
 
			ServiceWrapper ntservice((char *)uninstall_service_name.c_str());
 
			if (ntservice.IsInstalled()) {
 
				if (ntservice.UnInstall()) {
 
					std::cout << "Successfully removed " << uninstall_service_name << std::endl;
 
					return 0;
 
				} else {
 
					std::cout << "Error removing service, are you an Administrator?" << std::endl;
 
					return 1;
 
				}                               				
 
			} else {
 
				std::cout << "Service not installed: " << uninstall_service_name << std::endl;
 
				return 1;
 
			}
 
		}		
 
#endif
 
	}
 
	catch (std::runtime_error& e)
 
	{
 
		std::cout << desc << "\n";
 
		return 1;
 
	}
 
	catch (...)
 
	{
 
		std::cout << desc << "\n";
 
		return 1;
 
	}
 

	
 
	if (!config.load(vm["config"].as<std::string>(), jid)) {
 
		std::cerr << "Can't load configuration file.\n";
 
		return 1;
 
	}
 

	
 
	// create directories
 
	try {
 
		_createDirectories(&config, boost::filesystem::path(CONFIG_STRING(&config, "service.working_dir")));
 
	}
 
	catch (...) {
 
		std::cerr << "Can't create service.working_dir directory " << CONFIG_STRING(&config, "service.working_dir") << ".\n";
 
		return 1;
 
	}
 
#ifndef WIN32
 
	// create directories
 
	try {
 
		boost::filesystem::create_directories(
 
			boost::filesystem::path(CONFIG_STRING(&config, "service.pidfile")).parent_path().string()
 
		);
 
	}
 
	catch (...) {
 
		std::cerr << "Can't create service.pidfile directory " << boost::filesystem::path(CONFIG_STRING(&config, "service.pidfile")).parent_path().string() << ".\n";
 
		return 1;
 
	}
 
	// create directories
 
	try {
 
		boost::filesystem::create_directories(
 
			boost::filesystem::path(CONFIG_STRING(&config, "service.portfile")).parent_path().string()
 
		);
 
	}
 
	catch (...) {
 
		std::cerr << "Can't create service.portfile directory " << CONFIG_STRING(&config, "service.portfile") << ".\n";
 
		return 1;
 
	}
 
#endif
 

	
 
#ifdef WIN32
 
	SetCurrentDirectory( utf8ToUtf16(CONFIG_STRING(&config, "service.working_dir")).c_str() );
 
#endif
 

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

	
 
	if (!no_daemon) {
 
		// daemonize
 
		daemonize(CONFIG_STRING(&config, "service.working_dir").c_str(), CONFIG_STRING(&config, "service.pidfile").c_str());
 
// 		removeOldIcons(CONFIG_STRING(&config, "service.working_dir") + "/icons");
 
	}
 
	else {
 
		if ((chdir(CONFIG_STRING(&config, "service.working_dir").c_str())) < 0) {
 
			std::cerr << "Cannot change directory to " << CONFIG_STRING(&config, "service.working_dir") << "\n";
 
			exit(1);
 
		}
 
	}
 
#endif
 
#ifdef WIN32
 
	if (!run_service_name.empty()) {
 
		ServiceWrapper ntservice((char *)run_service_name.c_str());
 
		if (ntservice.IsInstalled()) {
 
			ntservice.RunService();
 
		} else {
 
			std::cerr << "Service not installed: " << run_service_name << std::endl;
 
			return 1;
 
		}
 
	} else {
 
		mainloop();
 
	}
 
#else
 
	mainloop();
 
#endif
 
}
spectrum_manager/src/CMakeLists.txt
Show inline comments
 
cmake_minimum_required(VERSION 2.6)
 
FILE(GLOB SRC *.cpp *.c)
 
 
ADD_EXECUTABLE(spectrum2_manager ${SRC} ../../src/config.cpp ../../src/util.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../include/transport/protocol.pb.cc)
 

	
 
ADD_DEPENDENCIES(spectrum2_manager pb)
 
SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/../../include/transport/protocol.pb.cc PROPERTIES GENERATED 1)
 

	
 
target_link_libraries(spectrum2_manager ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES})
 

	
 
if(APPLE)
 
target_link_libraries(spectrum2_manager ${APPLE_FRAMEWORKS})
 
endif()
 
INSTALL(TARGETS spectrum2_manager RUNTIME DESTINATION bin)
 
 
INSTALL(FILES
 
	spectrum_manager.cfg
 
	DESTINATION /etc/spectrum2
 
	)
src/CMakeLists.txt
Show inline comments
 
cmake_minimum_required(VERSION 2.6)
 
FILE(GLOB SRC *.cpp *.h)
 
FILE(GLOB_RECURSE SWIFTEN_SRC ../include/Swiften/*.cpp)
 

	
 
# Build without openssl on msvc
 
if (CMAKE_COMPILER_IS_GNUCXX)
 
if (NOT MSVC)
 
	string(REGEX REPLACE "[^;]+;?/Schannel/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}") 
 
else()
 
	string(REGEX REPLACE "[^;]+;?/OpenSSL/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}") 
 
endif()
 

	
 
FILE(GLOB HEADERS ../include/transport/*.h)
 

	
 
if (CPPUNIT_FOUND)
 
	FILE(GLOB SRC_TEST tests/*.cpp)
 

	
 
	ADD_EXECUTABLE(libtransport_test ${SRC_TEST})
 
	set_target_properties(libtransport_test PROPERTIES COMPILE_DEFINITIONS LIBTRANSPORT_TEST=1)
 

	
 
	target_link_libraries(libtransport_test transport ${CPPUNIT_LIBRARY} ${Boost_LIBRARIES})
 
endif()
 

	
 
if (NOT WIN32)
 
include_directories(${POPT_INCLUDE_DIR})
 
endif()
 

	
 
# SOURCE_GROUP(headers FILES ${HEADERS})
 

	
 

	
 
if (PROTOBUF_FOUND)
 
	if (NOT WIN32)
 
		ADD_LIBRARY(transport SHARED ${HEADERS} ${SRC} ${SWIFTEN_SRC})
 
	else()
 
		ADD_LIBRARY(transport STATIC ${HEADERS} ${SRC} ${SWIFTEN_SRC})
 
	endif()
 
#	SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/../include/transport/protocol.pb.cc PROPERTIES GENERATED 1)
 
	ADD_DEPENDENCIES(transport pb) 
 
else(PROTOBUF_FOUND)
 
	ADD_LIBRARY(transport SHARED ${HEADERS} ${SRC} ${SWIFTEN_SRC})
 
endif(PROTOBUF_FOUND)
 

	
 
# if (CMAKE_COMPILER_IS_GNUCXX)
 
	if (NOT WIN32)
 
		ADD_DEFINITIONS(-fPIC)
 
	endif()
 
# endif()
 

	
 
if (WIN32)
 
	include_directories("${CMAKE_SOURCE_DIR}/msvc-deps/sqlite3")
 
	TARGET_LINK_LIBRARIES(transport transport-plugin sqlite3 ${PQXX_LIBRARY} ${PQ_LIBRARY} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES} ${PROTOBUF_LIBRARY})
 
else()
 
	TARGET_LINK_LIBRARIES(transport transport-plugin ${PQXX_LIBRARY} ${PQ_LIBRARY} ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES} ${POPT_LIBRARY} ${PROTOBUF_LIBRARY})
 
endif()
 

	
 
SET_TARGET_PROPERTIES(transport PROPERTIES
 
      VERSION ${TRANSPORT_VERSION} SOVERSION ${TRANSPORT_VERSION}
 
)
 
if (APPLE)
 
	TARGET_LINK_LIBRARIES(transport ${APPLE_FRAMEWORKS})
 
endif()
 

	
 
INSTALL(TARGETS transport LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR} COMPONENT libraries)
 

	
 
#CONFIGURE_FILE(transport.pc.in "${CMAKE_CURRENT_BINARY_DIR}/transport.pc")
 
#INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/transport.pc" DESTINATION lib/pkgconfig)
src/memoryusage.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/memoryusage.h"
 

	
 
#include <iostream>
 
#include <cstring>
 
#include <sstream>
 
#include <fstream>
 
#include <algorithm>
 
#include <boost/lexical_cast.hpp>
 
#ifndef WIN32
 
#include <sys/param.h>
 
#endif
 
#ifdef BSD
 
#ifdef __MACH__
 
#include <mach/mach.h>
 
#elif BSD
 
#include <sys/types.h>
 
#include <sys/sysctl.h>
 
#include <sys/param.h>
 
#include <sys/sysctl.h>
 
#include <sys/user.h>
 

	
 
#endif
 

	
 
namespace Transport {
 

	
 
#ifndef WIN32
 
#ifdef BSD
 
#ifdef __MACH__
 

	
 
void process_mem_usage(double& vm_usage, double& resident_set, pid_t pid) {
 

	
 
	struct task_basic_info t_info;
 
	mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
 

	
 
	if (KERN_SUCCESS != task_info(mach_task_self(),
 
                              TASK_BASIC_INFO, (task_info_t)&t_info, 
 
                              &t_info_count)) {
 
		vm_usage = 0;
 
		resident_set = 0;
 
    		return;
 
	}
 
	vm_usage = t_info.virtual_size;
 
	resident_set = t_info.resident_size;
 
}
 
#elif BSD
 
void process_mem_usage(double& vm_usage, double& resident_set, pid_t pid) {
 
	int mib[4];
 
	size_t size;
 
	mib[0] = CTL_KERN;
 
	mib[1] = KERN_PROC;
 
	mib[2] = KERN_PROC_PID;
 
	if (pid == 0) {
 
		mib[3] = getpid();
 
	}
 
	else {
 
		mib[3] = pid;
 
	}
 
	struct kinfo_proc proc;
 

	
 
	size = sizeof(struct kinfo_proc);
 

	
 
	if (sysctl((int*)mib, 4, &proc, &size, NULL, 0) == -1) {
 
		vm_usage = 0;
 
		resident_set = 0;
 
		return;
 
	}
 

	
 
	// sysctl stores 0 in the size if we can't find the process information.
 
	// Set errno to ESRCH which will be translated in NoSuchProcess later on.
 
	if (size == 0) {
 
		vm_usage = 0;
 
		resident_set = 0;
 
		return;
 
	}
 

	
 
	int pagesize,cnt;
 

	
 
	size = sizeof(pagesize);
 
	sysctlbyname("hw.pagesize", &pagesize, &size, NULL, 0);
 

	
 
	resident_set = (double) (proc.ki_rssize * pagesize / 1024);
 
	vm_usage = (double) proc.ki_size;
 
}
 
#else /* BSD */
 
void process_mem_usage(double& shared, double& resident_set, pid_t pid) {
 
	using std::ios_base;
 
	using std::ifstream;
 
	using std::string;
 

	
 
	shared       = 0.0;
 
	resident_set = 0.0;
 

	
 
	// 'file' stat seems to give the most reliable results
 
	std::string f = "/proc/self/statm";
 
	if (pid != 0) {
 
		f = "/proc/" + boost::lexical_cast<std::string>(pid) + "/statm";
 
	}
 
	ifstream stat_stream(f.c_str(), ios_base::in);
 
	if (!stat_stream.is_open()) {
 
		shared = 0;
 
		resident_set = 0;
 
		return;
 
	}
 

	
 
	// dummy vars for leading entries in stat that we don't care about
 
	//
 
	string pid1, comm, state, ppid, pgrp, session, tty_nr;
 
	string tpgid, flags, minflt, cminflt, majflt, cmajflt;
 
	string utime, stime, cutime, cstime, priority, nice;
 
	string O, itrealvalue, starttime;
 

	
 
	// the two fields we want
 
	//
 
	unsigned long shared_;
 
	long rss;
 

	
 
	stat_stream >> O >> rss >> shared_; // don't care about the rest
 

	
 
	long page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024; // in case x86-64 is configured to use 2MB pages
 
	shared     = shared_ * page_size_kb;
 
	resident_set = rss * page_size_kb;
 
}
 
#endif /* else BSD */
 
#endif /* WIN32 */
 

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

	
 
#include "transport/usermanager.h"
 
#include "transport/user.h"
 
#include "transport/transport.h"
 
#include "transport/storagebackend.h"
 
#include "transport/conversationmanager.h"
 
#include "transport/rostermanager.h"
 
#include "transport/userregistry.h"
 
#include "transport/logging.h"
 
#include "transport/discoitemsresponder.h"
 
#include "storageresponder.h"
 

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

	
 
namespace Transport {
 

	
 
DEFINE_LOGGER(logger, "UserManager");
 

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

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

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

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

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

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

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

	
 
User *UserManager::getUser(const std::string &barejid){
 
	if (m_cachedUser && barejid == m_cachedUser->getJID().toBare().toString()) {
 
		return m_cachedUser;
 
	}
 

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

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

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

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

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

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

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

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

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

	
 
void UserManager::handleDiscoInfo(const Swift::JID& jid, boost::shared_ptr<Swift::DiscoInfo> info) {
 
	User *user = getUser(jid.toBare().toString());
 
	if (!user) {
 
		return;
 
	}
 

	
 
	user->handleDiscoInfo(jid, info);
 
}
 

	
 
void UserManager::handlePresence(Swift::Presence::ref presence) {
 
	std::string barejid = presence->getTo().toBare().toString();
 
	std::string userkey = presence->getFrom().toBare().toString();
 

	
 
	User *user = getUser(userkey);
 
	// Create user class if it's not there
 
	if (!user) {
 
		// Admin user is not legacy network user, so do not create User class instance for him
 
		if (m_component->inServerMode()) {
 
			std::vector<std::string> const &x = CONFIG_VECTOR(m_component->getConfig(),"service.admin_jid");
 
			if (std::find(x.begin(), x.end(), presence->getFrom().toBare().toString()) != x.end()) {
 
				// Send admin contact to the user.
 
				Swift::RosterPayload::ref payload = Swift::RosterPayload::ref(new Swift::RosterPayload());
 
				Swift::RosterItemPayload item;
 
				item.setJID(m_component->getJID());
 
				item.setName("Admin");
 
				item.setSubscription(Swift::RosterItemPayload::Both);
 
				payload->addItem(item);
 

	
 
				Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(payload, presence->getFrom(), m_component->getIQRouter());
 
				request->send();
 

	
 
				Swift::Presence::ref response = Swift::Presence::create();
 
				response->setTo(presence->getFrom());
 
				response->setFrom(m_component->getJID());
 
				m_component->getStanzaChannel()->sendPresence(response);
 
				return;
 
		    }
 
		}
 

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

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

	
 
			// bother him with probe presence, just to be
 
			// sure he is subscribed to us.
 
			if (/*registered && */presence->getType() == Swift::Presence::Probe) {
 
				Swift::Presence::ref response = Swift::Presence::create();
 
				response->setTo(presence->getFrom());
 
				response->setFrom(presence->getTo());
 
				response->setType(Swift::Presence::Probe);
 
				m_component->getStanzaChannel()->sendPresence(response);
 
			}
 

	
 
			// Set user offline in database
 
			if (m_storageBackend) {
 
				UserInfo res;
 
				bool registered = m_storageBackend->getUser(userkey, res);
 
				if (registered) {
 
					m_storageBackend->setUserOnline(res.id, false);
 
				}
 
			}
 
			return;
 
		}
 

	
 
		// In server mode, we don't need registration normally, but for networks like IRC
 
		// or Twitter where there's no real authorization using password, we have to force
 
		// registration otherwise some data (like bookmarked rooms) could leak.
 
		if (m_component->inServerMode()) {
 
			if (!registered) {
 
				// If we need registration, stop login process because user is not registered
 
				if (CONFIG_BOOL_DEFAULTED(m_component->getConfig(), "registration.needRegistration", false)) {
 
					m_userRegistry->onPasswordInvalid(presence->getFrom());
 
					return;
 
				}
 
				res.password = "";
 
				res.uin = presence->getFrom().getNode();
 
				res.jid = userkey;
 
				while (res.uin.find_last_of("%") != std::string::npos) { // OK
 
					res.uin.replace(res.uin.find_last_of("%"), 1, "@"); // OK
 
				}
 
				if (m_storageBackend) {
 
					// store user and getUser again to get user ID.
 
					m_storageBackend->setUser(res);
 
					registered = m_storageBackend->getUser(userkey, res);
 
				}
 
				else {
 
					registered = true;
 
				}
 
			}
 
			res.password = m_userRegistry->getUserPassword(userkey);
 
		}
 

	
 
		// We allow auto_register feature in gateway-mode. This allows IRC user to register
 
		// the transport just by joining the room.
 
		if (!m_component->inServerMode()) {
 
			if (!registered && (CONFIG_BOOL(m_component->getConfig(), "registration.auto_register") ||
 
				!CONFIG_BOOL_DEFAULTED(m_component->getConfig(), "registration.needRegistration", true))) {
 
				res.password = "";
 
				res.jid = userkey;
 

	
 
				bool isMUC = presence->getPayload<Swift::MUCPayload>() != NULL || *presence->getTo().getNode().c_str() == '#';
 
				if (isMUC) {
 
					res.uin = presence->getTo().getResource();
 
				}
 
				else {
 
					res.uin = presence->getFrom().toString();
 
				}
 
				LOG4CXX_INFO(logger, "Auto-registering user " << userkey << " with uin=" << res.uin);
 

	
 
				if (m_storageBackend) {
 
					// store user and getUser again to get user ID.
 
					m_storageBackend->setUser(res);
 
					registered = m_storageBackend->getUser(userkey, res);
 
				}
 
				else {
 
					registered = true;
 
				}
 
			}
 
		}
 

	
 
		// Unregistered users are not able to login
 
		if (!registered) {
 
			LOG4CXX_WARN(logger, "Unregistered user " << userkey << " tried to login");
 
			return;
 
		}
 

	
 
		if (CONFIG_BOOL(m_component->getConfig(), "service.vip_only") && res.vip == false) {
 
			if (!CONFIG_STRING(m_component->getConfig(), "service.vip_message").empty()) {
 
				boost::shared_ptr<Swift::Message> msg(new Swift::Message());
 
				msg->setBody(CONFIG_STRING(m_component->getConfig(), "service.vip_message"));
 
				msg->setTo(presence->getFrom());
 
				msg->setFrom(m_component->getJID());
 
				m_component->getStanzaChannel()->sendMessage(msg);
 
			}
 

	
 
			LOG4CXX_WARN(logger, "Non VIP user " << userkey << " tried to login");
 
			if (m_component->inServerMode()) {
 
				m_userRegistry->onPasswordInvalid(presence->getFrom());
 
			}
 
			return;
 
		}
 

	
 
		bool transport_enabled = true;
 
		if (m_storageBackend) {
 
			std::string value = "1";
 
			int type = (int) TYPE_BOOLEAN;
 
			m_storageBackend->getUserSetting(res.id, "enable_transport", type, value);
 
			transport_enabled = value == "1";
 
		}
 
		// User can disabled the transport using adhoc commands
 
		if (!transport_enabled) {
 
			LOG4CXX_INFO(logger, "User " << userkey << " has disabled transport, not logging");
 
			return;
 
		}
 

	
 
		// Create new user class and set storagebackend
 
		user = new User(presence->getFrom(), res, m_component, this);
 
		user->getRosterManager()->setStorageBackend(m_storageBackend);
 
		addUser(user);
 
	}
 

	
 
	// User can be handleDisconnected in addUser callback, so refresh the pointer
 
	user = getUser(userkey);
 
	if (!user) {
 
		m_userRegistry->onPasswordInvalid(presence->getFrom());
 
		return;
 
	}
 

	
 
	// Handle this presence
 
	user->handlePresence(presence);
 

	
 
	// Unavailable MUC presence should not trigger whole account disconnection, so block it here.
 
	bool isMUC = presence->getPayload<Swift::MUCPayload>() != NULL || *presence->getTo().getNode().c_str() == '#';
 
	if (isMUC)
 
		return;
 

	
 
	// Unavailable presence could remove this user, because he could be unavailable
 
	if (presence->getType() == Swift::Presence::Unavailable) {
 
		if (user) {
 
			if (user->getUserSetting("stay_connected") == "1") {
 
				return;
 
			}
 

	
 
			Swift::Presence::ref highest = m_component->getPresenceOracle()->getHighestPriorityPresence(presence->getFrom().toBare());
 
			// There's no presence for this user, so disconnect
 
			if (!highest || (highest && highest->getType() == Swift::Presence::Unavailable)) {
 
				m_removeTimer->onTick.connect(boost::bind(&UserManager::handleRemoveTimeout, this, user->getJID().toBare().toString(), user, false));
 
				m_removeTimer->start();
 
			}
 
		}
 
	}
 
}
 

	
 
void UserManager::handleRemoveTimeout(const std::string jid, User *u, bool reconnect) {
 
	m_removeTimer->onTick.disconnect(boost::bind(&UserManager::handleRemoveTimeout, this, jid, u, reconnect));
 

	
 
	// Maybe this User instance has been deleted in mean time and we would remove new one,
 
	// so better check for it and ignore deletion if "u" does not exist anymore.
 
	User *user = getUser(jid);
 
	if (user != u) {
 
		return;
 
	}
 

	
 
	// Remove user
 
	if (user) {
 
		removeUser(user);
 
	}
 

	
 
	// Connect the user again when we're reconnecting.
 
	if (reconnect) {
 
		connectUser(jid);
 
	}
 
}
 

	
 
void UserManager::handleMessageReceived(Swift::Message::ref message) {
 
	if (message->getType() == Swift::Message::Error) {
 
		return;
 
	}
 

	
 
	// Do not count chatstate notification...
 
	boost::shared_ptr<Swift::ChatState> statePayload = message->getPayload<Swift::ChatState>();
 
	if (!statePayload) {
 
		messageToBackendSent();
 
	}
 

	
 
	if (message->getBody().empty() && !statePayload && message->getSubject().empty()) {
 
		return;
 
	}
 

	
 
	User *user = getUser(message->getFrom().toBare().toString());
 
	if (!user){
 
		return;
 
	}
 

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

	
 
void UserManager::handleGeneralPresenceReceived(Swift::Presence::ref presence) {
 
	switch(presence->getType()) {
 
		case Swift::Presence::Subscribe:
 
		case Swift::Presence::Subscribed:
 
		case Swift::Presence::Unsubscribe:
 
		case Swift::Presence::Unsubscribed:
 
			handleSubscription(presence);
 
			break;
 
		case Swift::Presence::Available:
 
		case Swift::Presence::Unavailable:
 
			handleMUCPresence(presence);
 
			break;
 
		case Swift::Presence::Probe:
 
			handleProbePresence(presence);
 
			break;
 
		case Swift::Presence::Error:
 
			handleErrorPresence(presence);
 
			break;
 
		default:
 
			break;
 
	};
 
}
 

	
 
void UserManager::handleMUCPresence(Swift::Presence::ref presence) {
 
	// Don't let RosterManager to handle presences for us
 
	if (presence->getTo().getNode().empty()) {
 
		return;
 
	}
 

	
 
	if (presence->getType() == Swift::Presence::Available) {
 
		handlePresence(presence);
 
	}
 
	else if (presence->getType() == Swift::Presence::Unavailable) {
 
		std::string userkey = presence->getFrom().toBare().toString();
 
		User *user = getUser(userkey);
 
		if (user) {
 
			user->handlePresence(presence);
 
		}
 
	}
 
}
 

	
 
void UserManager::handleProbePresence(Swift::Presence::ref presence) {
 
	// Don't let RosterManager to handle presences for us
 
	if (presence->getTo().getNode().empty()) {
 
		return;
 
	}
 

	
 
	User *user = getUser(presence->getFrom().toBare().toString());
 

	
 
 	if (user) {
 
 		user->getRosterManager()->sendCurrentPresence(presence->getTo(), presence->getFrom());
 
 	}
 
 	else {
 
		Swift::Presence::ref response = Swift::Presence::create();
 
		response->setFrom(presence->getTo());
 
		response->setTo(presence->getFrom());
 
		response->setType(Swift::Presence::Unavailable);
 
		m_component->getStanzaChannel()->sendPresence(response);
 
	}
 
}
 

	
 
void UserManager::handleErrorPresence(Swift::Presence::ref presence) {
 
	// Don't let RosterManager to handle presences for us
 
	if (!presence->getTo().getNode().empty()) {
 
		return;
 
	}
 

	
 
	if (!presence->getPayload<Swift::ErrorPayload>()) {
 
		return;
 
	}
 

	
 
	if (presence->getPayload<Swift::ErrorPayload>()->getCondition() != Swift::ErrorPayload::SubscriptionRequired) {
 
		return;
 
	}
 

	
 
	std::string userkey = presence->getFrom().toBare().toString();
 
	UserInfo res;
 
	bool registered = m_storageBackend ? m_storageBackend->getUser(userkey, res) : false;
 
	if (registered) {
 
		Swift::Presence::ref response = Swift::Presence::create();
 
		response->setFrom(presence->getTo().toBare());
 
		response->setTo(presence->getFrom().toBare());
 
		response->setType(Swift::Presence::Subscribe);
 
		m_component->getStanzaChannel()->sendPresence(response);
 
	}
 
}
 

	
 
void UserManager::handleSubscription(Swift::Presence::ref presence) {
 
	
 
	// answer to subscibe for transport itself
 
	if (presence->getType() == Swift::Presence::Subscribe && presence->getTo().getNode().empty()) {
 
		Swift::Presence::ref response = Swift::Presence::create();
 
		response->setFrom(presence->getTo().toBare());
 
		response->setTo(presence->getFrom().toBare());
 
		response->setType(Swift::Presence::Subscribed);
 
		m_component->getStanzaChannel()->sendPresence(response);
 

	
 
// 		response = Swift::Presence::create();
 
// 		response->setFrom(presence->getTo());
 
// 		response->setTo(presence->getFrom());
 
// 		response->setType(Swift::Presence::Subscribe);
 
// 		m_component->getStanzaChannel()->sendPresence(response);
 
		return;
 
	}
 
	else if (presence->getType() == Swift::Presence::Unsubscribed && presence->getTo().getNode().empty()) {
 
		std::string userkey = presence->getFrom().toBare().toString();
 
		UserInfo res;
 
		bool registered = m_storageBackend ? m_storageBackend->getUser(userkey, res) : false;
 
		if (registered) {
 
			Swift::Presence::ref response = Swift::Presence::create();
 
			response->setFrom(presence->getTo().toBare());
 
			response->setTo(presence->getFrom().toBare());
 
			response->setType(Swift::Presence::Subscribe);
 
			m_component->getStanzaChannel()->sendPresence(response);
 
		}
 
		return;
 
	}
 

	
 
	// Don't let RosterManager to handle presences for us
 
	if (presence->getTo().getNode().empty()) {
 
		return;
 
	}
 

	
 
	User *user = getUser(presence->getFrom().toBare().toString());
 

	
 
 	if (user) {
 
 		user->handleSubscription(presence);
0 comments (0 inline, 0 general)