This commit is contained in:
Vitaly Takmazov 2012-03-02 23:13:26 +04:00
commit 285502c6ef
87 changed files with 3857 additions and 70 deletions

View file

@ -38,7 +38,7 @@ set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
endif()
find_package(Boost COMPONENTS program_options date_time system filesystem regex thread signals REQUIRED)
find_package(Boost COMPONENTS program_options date_time system filesystem regex signals REQUIRED)
message( STATUS "Found Boost: ${Boost_LIBRARIES}, ${Boost_INCLUDE_DIR}")
set(Protobuf_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
@ -53,6 +53,12 @@ find_package(log4cxx)
set(event_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
find_package(event)
set(pqxx_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
find_package(pqxx)
set(dbus_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
find_package(dbus)
find_package(Doxygen)
INCLUDE(FindQt4)
@ -101,6 +107,16 @@ else (MYSQL_FOUND)
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})
@ -133,12 +149,21 @@ if (PROTOBUF_FOUND)
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)

View file

@ -1,3 +1,28 @@
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

View file

@ -7,8 +7,15 @@ if (PROTOBUF_FOUND)
ADD_SUBDIRECTORY(libcommuni)
endif()
ADD_SUBDIRECTORY(smstools3)
ADD_SUBDIRECTORY(template)
if (NOT WIN32)
ADD_SUBDIRECTORY(frotz)
if (${LIBDBUSGLIB_FOUND})
ADD_SUBDIRECTORY(skype)
endif()
endif()
endif()

View file

@ -6,7 +6,7 @@ FILE(GLOB SRC *.c *.cpp)
ADD_EXECUTABLE(spectrum2_frotz_backend ${SRC})
target_link_libraries(spectrum2_frotz_backend transport pthread transport-plugin ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES})
target_link_libraries(spectrum2_frotz_backend transport pthread ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES})
INSTALL(TARGETS spectrum2_frotz_backend RUNTIME DESTINATION bin)

View file

@ -4,7 +4,7 @@ FILE(GLOB HEADERS *.h)
QT4_WRAP_CPP(SRC ${HEADERS})
ADD_EXECUTABLE(spectrum2_libcommuni_backend ${SRC})
target_link_libraries(spectrum2_libcommuni_backend ${IRC_LIBRARY} ${QT_LIBRARIES} transport-plugin transport pthread)
target_link_libraries(spectrum2_libcommuni_backend ${IRC_LIBRARY} ${QT_LIBRARIES} transport pthread)
INSTALL(TARGETS spectrum2_libcommuni_backend RUNTIME DESTINATION bin)

View file

@ -26,6 +26,7 @@ MyIrcSession::MyIrcSession(const std::string &user, NetworkPlugin *np, const std
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()));
@ -33,6 +34,7 @@ MyIrcSession::MyIrcSession(const std::string &user, NetworkPlugin *np, const std
}
void MyIrcSession::on_connected() {
m_connected = true;
if (suffix.empty()) {
np->handleConnected(user);
}
@ -51,6 +53,7 @@ void MyIrcSession::on_connected() {
void MyIrcSession::on_disconnected() {
if (suffix.empty())
np->handleDisconnected(user, 0, "");
m_connected = false;
}
bool MyIrcSession::correctNickname(std::string &nickname) {
@ -156,6 +159,9 @@ void MyIrcSession::on_messageReceived(IrcMessage *message) {
}
void MyIrcSession::on_numericMessageReceived(IrcMessage *message) {
QString channel;
QStringList members;
IrcNumericMessage *m = (IrcNumericMessage *) message;
switch (m->code()) {
case 332:
@ -165,8 +171,8 @@ void MyIrcSession::on_numericMessageReceived(IrcMessage *message) {
np->handleSubject(user, m->parameters().value(1).toStdString() + suffix, m_topicData, m->parameters().value(2).toStdString());
break;
case 353:
QString channel = m->parameters().value(2);
QStringList members = m->parameters().value(3).split(" ");
channel = m->parameters().value(2);
members = m->parameters().value(3).split(" ");
for (int i = 0; i < members.size(); i++) {
bool flags = 0;
@ -176,6 +182,13 @@ void MyIrcSession::on_numericMessageReceived(IrcMessage *message) {
np->handleParticipantChanged(user, nickname, channel.toStdString() + suffix,(int) flags, pbnetwork::STATUS_ONLINE);
}
break;
case 432:
if (m_connected) {
np->handleDisconnected(user, pbnetwork::CONNECTION_ERROR_INVALID_USERNAME, "Erroneous Nickname");
}
break;
default:
break;
}
//qDebug() << "numeric message received:" << receiver() << origin << code << params;
@ -208,5 +221,6 @@ void MyIrcSession::onMessageReceived(IrcMessage *message) {
case IrcMessage::Numeric:
on_numericMessageReceived(message);
break;
default:break;
}
}

View file

@ -65,6 +65,7 @@ protected:
std::string m_identify;
std::list<std::string> m_autoJoin;
std::string m_topicData;
bool m_connected;
};
//class MyIrcBuffer : public Irc::Buffer

View file

@ -441,6 +441,16 @@ static void * requestInput(const char *title, const char *primary,const char *se
((PurpleRequestInputCb) ok_cb)(user_data, "Please authorize me.");
return NULL;
}
else if (primaryString == "Authorization Request Message:") {
LOG4CXX_INFO(logger, "Authorization Request Message: calling ok_cb(...)");
((PurpleRequestInputCb) ok_cb)(user_data, "Please authorize me.");
return NULL;
}
else if (primaryString == "Authorization Denied Message:") {
LOG4CXX_INFO(logger, "Authorization Deined Message: calling ok_cb(...)");
((PurpleRequestInputCb) ok_cb)(user_data, "Authorization denied.");
return NULL;
}
else {
LOG4CXX_WARN(logger, "Unhandled request input. primary=" << primaryString);
}
@ -604,11 +614,13 @@ class SpectrumNetworkPlugin : public NetworkPlugin {
return;
}
LOG4CXX_INFO(logger, "Creating account with name '" << name.c_str() << "' and protocol '" << protocol << "'");
if (purple_accounts_find(name.c_str(), protocol.c_str()) != NULL){
if (purple_accounts_find(name.c_str(), protocol.c_str()) != NULL) {
LOG4CXX_INFO(logger, "Using previously created account with name '" << name.c_str() << "' and protocol '" << protocol << "'");
account = purple_accounts_find(name.c_str(), protocol.c_str());
}
else {
LOG4CXX_INFO(logger, "Creating account with name '" << name.c_str() << "' and protocol '" << protocol << "'");
account = purple_account_new(name.c_str(), protocol.c_str());
purple_accounts_add(account);
}
@ -903,6 +915,41 @@ class SpectrumNetworkPlugin : public NetworkPlugin {
}
}
void handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &pasword) {
PurpleAccount *account = m_sessions[user];
if (!account) {
return;
}
PurpleConnection *gc = purple_account_get_connection(account);
GHashTable *comps = NULL;
// Check if the PurpleChat is not stored in buddy list
PurpleChat *chat = purple_blist_find_chat(account, room.c_str());
if (chat) {
comps = purple_chat_get_components(chat);
}
else if (PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults != NULL) {
comps = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults(gc, room.c_str());
}
LOG4CXX_INFO(logger, user << ": Joining the room " << room);
if (comps) {
serv_join_chat(gc, comps);
g_hash_table_destroy(comps);
}
}
void handleLeaveRoomRequest(const std::string &user, const std::string &room) {
PurpleAccount *account = m_sessions[user];
if (!account) {
return;
}
PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, room.c_str(), account);
purple_conversation_destroy(conv);
}
void handleFTStartRequest(const std::string &user, const std::string &buddyName, const std::string &fileName, unsigned long size, unsigned long ftID) {
PurpleXfer *xfer = m_unhandledXfers[user + fileName + buddyName];
if (xfer) {
@ -1078,6 +1125,8 @@ static void buddyListNewNode(PurpleBlistNode *node) {
PurpleBuddy *buddy = (PurpleBuddy *) node;
PurpleAccount *account = purple_buddy_get_account(buddy);
LOG4CXX_INFO(logger, "Buddy updated " << np->m_accounts[account] << " " << purple_buddy_get_name(buddy) << " " << getAlias(buddy));
// Status
pbnetwork::StatusType status = pbnetwork::STATUS_NONE;
std::string message;

View file

@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 2.6)
FILE(GLOB SRC *.cpp)
ADD_EXECUTABLE(spectrum2_skype_backend ${SRC})
target_link_libraries(spectrum2_skype_backend ${GLIB2_LIBRARIES} ${EVENT_LIBRARIES} transport pthread ${LIBDBUSGLIB_LIBRARIES})
INSTALL(TARGETS spectrum2_skype_backend RUNTIME DESTINATION bin)

865
backends/skype/main.cpp Normal file
View file

@ -0,0 +1,865 @@
#include "glib.h"
#include <iostream>
#include "transport/config.h"
#include "transport/transport.h"
#include "transport/usermanager.h"
#include "transport/logger.h"
#include "transport/sqlite3backend.h"
#include "transport/userregistration.h"
#include "transport/user.h"
#include "transport/storagebackend.h"
#include "transport/rostermanager.h"
#include "transport/conversation.h"
#include "transport/networkplugin.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");
using namespace Transport;
class SpectrumNetworkPlugin;
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() { 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();
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:
SpectrumNetworkPlugin(Config *config, const std::string &host, int port) : NetworkPlugin() {
this->config = config;
LOG4CXX_INFO(logger, "Starting the backend.");
}
~SpectrumNetworkPlugin() {
for (std::map<Skype *, std::string>::iterator it = m_accounts.begin(); it != m_accounts.end(); it++) {
delete (*it).first;
}
}
void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) {
std::string name = legacyName;
name = name.substr(name.find(".") + 1);
LOG4CXX_INFO(logger, "Creating account with name '" << name << "'");
Skype *skype = new Skype(user, name, password);
m_sessions[user] = skype;
m_accounts[skype] = user;
skype->login();
}
void handleLogoutRequest(const std::string &user, const std::string &legacyName) {
Skype *skype = m_sessions[user];
if (skype) {
skype->logout();
exit(1);
}
}
void handleStatusChangeRequest(const std::string &user, int status, const std::string &statusMessage) {
Skype *skype = m_sessions[user];
if (!skype)
return;
std::string st;
switch(status) {
case Swift::StatusShow::Away: {
st = "AWAY";
break;
}
case Swift::StatusShow::DND: {
st = "DND";
break;
}
case Swift::StatusShow::XA: {
st = "NA";
break;
}
case Swift::StatusShow::None: {
break;
}
case pbnetwork::STATUS_INVISIBLE:
st = "INVISIBLE";
break;
default:
st = "ONLINE";
break;
}
skype->send_command("SET USERSTATUS " + st);
if (!statusMessage.empty()) {
skype->send_command("SET PROFILE MOOD_TEXT " + statusMessage);
}
}
void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml) {
Skype *skype = m_sessions[user];
if (skype) {
skype->send_command("MESSAGE " + legacyName + " " + message);
}
}
void handleVCardRequest(const std::string &user, const std::string &legacyName, unsigned int id) {
Skype *skype = m_sessions[user];
if (skype) {
std::string name = legacyName;
if (name.find("skype.") == 0) {
name = name.substr(6);
}
std::string photo;
gchar *filename = NULL;
gchar *new_filename = NULL;
gchar *image_data = NULL;
gsize image_data_len = 0;
gchar *ret;
int fh;
GError *error;
const gchar *userfiles[] = {"user256", "user1024", "user4096", "user16384", "user32768", "user65536",
"profile256", "profile1024", "profile4096", "profile16384", "profile32768",
NULL};
char *username = g_strdup_printf("\x03\x10%s", name.c_str());
for (fh = 0; userfiles[fh]; fh++) {
filename = g_strconcat("/tmp/skype/", skype->getUsername().c_str(), "/", skype->getUsername().c_str(), "/", userfiles[fh], ".dbb", NULL);
std::cout << "getting filename:" << filename << "\n";
if (g_file_get_contents(filename, &image_data, &image_data_len, NULL))
{
std::cout << "got\n";
char *start = (char *)memmem(image_data, image_data_len, username, strlen(username)+1);
if (start != NULL)
{
char *next = image_data;
char *last = next;
//find last index of l33l
while ((next = (char *)memmem(next+4, start-next-4, "l33l", 4)))
{
last = next;
}
start = last;
if (start != NULL)
{
char *img_start;
//find end of l33l block
char *end = (char *)memmem(start+4, image_data+image_data_len-start-4, "l33l", 4);
if (!end) end = image_data+image_data_len;
//look for start of JPEG block
img_start = (char *)memmem(start, end-start, "\xFF\xD8", 2);
if (img_start)
{
//look for end of JPEG block
char *img_end = (char *)memmem(img_start, end-img_start, "\xFF\xD9", 2);
if (img_end)
{
image_data_len = img_end - img_start + 2;
photo = std::string(img_start, image_data_len);
}
}
}
}
g_free(image_data);
}
g_free(filename);
}
g_free(username);
std::string alias = "";
std::cout << skype->getUsername() << " " << name << "\n";
if (skype->getUsername() == name) {
alias = skype->send_command("GET PROFILE FULLNAME");
alias = alias.substr(17);
}
handleVCard(user, id, legacyName, "", alias, photo);
}
}
void sendData(const std::string &string) {
write(m_sock, string.c_str(), string.size());
// if (writeInput == 0)
// writeInput = purple_input_add(m_sock, PURPLE_INPUT_WRITE, &transportDataReceived, NULL);
}
void handleVCardUpdatedRequest(const std::string &user, const std::string &p, const std::string &nickname) {
}
void handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector<std::string> &groups) {
}
void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector<std::string> &groups) {
}
void handleBuddyBlockToggled(const std::string &user, const std::string &buddyName, bool blocked) {
}
void handleTypingRequest(const std::string &user, const std::string &buddyName) {
}
void handleTypedRequest(const std::string &user, const std::string &buddyName) {
}
void handleStoppedTypingRequest(const std::string &user, const std::string &buddyName) {
}
void handleAttentionRequest(const std::string &user, const std::string &buddyName, const std::string &message) {
}
std::map<std::string, Skype *> m_sessions;
std::map<Skype *, std::string> m_accounts;
std::map<std::string, unsigned int> m_vcards;
Config *config;
};
Skype::Skype(const std::string &user, const std::string &username, const std::string &password) {
m_username = username;
m_user = user;
m_password = password;
m_pid = 0;
m_connection = 0;
m_proxy = 0;
m_timer = -1;
m_counter = 0;
}
static gboolean load_skype_buddies(gpointer data) {
Skype *skype = (Skype *) data;
return skype->loadSkypeBuddies();
}
bool Skype::createDBusProxy() {
if (m_proxy == NULL) {
LOG4CXX_INFO(logger, "Creating DBus proxy for com.Skype.Api.");
m_counter++;
GError *error = NULL;
m_proxy = dbus_g_proxy_new_for_name_owner (m_connection, "com.Skype.API", "/com/Skype", "com.Skype.API", &error);
if (m_proxy == NULL && error != NULL) {
LOG4CXX_INFO(logger, m_username << ":" << error->message);
if (m_counter == 15) {
np->handleDisconnected(m_user, 0, error->message);
logout();
g_error_free(error);
return FALSE;
}
g_error_free(error);
}
if (m_proxy) {
LOG4CXX_INFO(logger, "Proxy created.");
DBusObjectPathVTable vtable;
vtable.message_function = &skype_notify_handler;
dbus_connection_register_object_path(dbus_g_connection_get_connection(m_connection), "/com/Skype/Client", &vtable, this);
m_counter = 0;
m_timer = g_timeout_add_seconds(1, load_skype_buddies, this);
return FALSE;
}
return TRUE;
}
return FALSE;
}
static gboolean create_dbus_proxy(gpointer data) {
Skype *skype = (Skype *) data;
return skype->createDBusProxy();
}
void Skype::login() {
boost::filesystem::path path(std::string("/tmp/skype/") + m_username);
if (!boost::filesystem::exists(path)) {
boost::filesystem::create_directories(path);
boost::filesystem::path path2(std::string("/tmp/skype/") + m_username + "/" + m_username );
boost::filesystem::create_directories(path2);
}
std::string shared_xml = "<?xml version=\"1.0\"?>\n"
"<config version=\"1.0\" serial=\"28\" timestamp=\"" + boost::lexical_cast<std::string>(time(NULL)) + ".0\">\n"
"<UI>\n"
"<Installed>2</Installed>\n"
"<Language>en</Language>\n"
"</UI>\n"
"</config>\n";
g_file_set_contents(std::string(std::string("/tmp/skype/") + m_username + "/shared.xml").c_str(), shared_xml.c_str(), -1, NULL);
std::string config_xml = "<?xml version=\"1.0\"?>\n"
"<config version=\"1.0\" serial=\"7\" timestamp=\"" + boost::lexical_cast<std::string>(time(NULL)) + ".0\">\n"
"<Lib>\n"
"<Account>\n"
"<IdleTimeForAway>30000000</IdleTimeForAway>\n"
"<IdleTimeForNA>300000000</IdleTimeForNA>\n"
"<LastUsed>" + boost::lexical_cast<std::string>(time(NULL)) + "</LastUsed>\n"
"</Account>\n"
"</Lib>\n"
"<UI>\n"
"<API>\n"
"<Authorizations>Spectrum</Authorizations>\n"
"<BlockedPrograms></BlockedPrograms>\n"
"</API>\n"
"</UI>\n"
"</config>\n";
g_file_set_contents(std::string(std::string("/tmp/skype/") + m_username + "/" + m_username +"/config.xml").c_str(), config_xml.c_str(), -1, NULL);
std::string db_path = std::string("/tmp/skype/") + m_username;
char *db = (char *) malloc(db_path.size() + 1);
strcpy(db, db_path.c_str());
LOG4CXX_INFO(logger, m_username << ": Spawning new Skype instance dbpath=" << db);
gchar* argv[6] = {"skype", "--disable-cleanlooks", "--pipelogin", "--dbpath", db, 0};
int fd;
g_spawn_async_with_pipes(NULL,
argv,
NULL /*envp*/,
G_SPAWN_SEARCH_PATH,
NULL /*child_setup*/,
NULL /*user_data*/,
&m_pid /*child_pid*/,
&fd,
NULL,
&fd_output,
NULL /*error*/);
std::string login_data = std::string(m_username + " " + m_password + "\n");
LOG4CXX_INFO(logger, m_username << ": Login data=" << login_data);
write(fd, login_data.c_str(), login_data.size());
close(fd);
fcntl (fd_output, F_SETFL, O_NONBLOCK);
free(db);
//Initialise threading
dbus_threads_init_default();
if (m_connection == NULL)
{
LOG4CXX_INFO(logger, "Creating DBus connection.");
GError *error = NULL;
m_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
if (m_connection == NULL && error != NULL)
{
LOG4CXX_INFO(logger, m_username << ": DBUS Error: " << error->message);
g_error_free(error);
return;
}
}
m_timer = g_timeout_add_seconds(1, create_dbus_proxy, this);
}
bool Skype::loadSkypeBuddies() {
// std::string re = "CONNSTATUS OFFLINE";
// while (re == "CONNSTATUS OFFLINE" || re.empty()) {
// sleep(1);
gchar buffer[1024];
int bytes_read = read(fd_output, buffer, 1023);
if (bytes_read > 0) {
buffer[bytes_read] = 0;
np->handleDisconnected(m_user, 0, buffer);
close(fd_output);
logout();
return FALSE;
}
std::string re = send_command("NAME Spectrum");
if (m_counter++ > 15) {
np->handleDisconnected(m_user, 0, "");
close(fd_output);
logout();
return FALSE;
}
if (re.empty() || re == "CONNSTATUS OFFLINE") {
return TRUE;
}
close(fd_output);
if (send_command("PROTOCOL 7") != "PROTOCOL 7") {
np->handleDisconnected(m_user, 0, "Skype is not ready");
logout();
return FALSE;
}
np->handleConnected(m_user);
std::map<std::string, std::string> group_map;
std::string groups = send_command("SEARCH GROUPS CUSTOM");
groups = groups.substr(groups.find(' ') + 1);
std::vector<std::string> grps;
boost::split(grps, groups, boost::is_any_of(","));
BOOST_FOREACH(std::string grp, grps) {
std::vector<std::string> data;
std::string name = send_command("GET GROUP " + grp + " DISPLAYNAME");
boost::split(data, name, boost::is_any_of(" "));
name = name.substr(name.find("DISPLAYNAME") + 12);
std::string users = send_command("GET GROUP " + data[1] + " USERS");
users = name.substr(name.find("USERS") + 6);
boost::split(data, users, boost::is_any_of(","));
BOOST_FOREACH(std::string u, data) {
group_map[u] = grp;
}
}
std::string friends = send_command("GET AUTH_CONTACTS_PROFILES");
char **full_friends_list = g_strsplit((strchr(friends.c_str(), ' ')+1), ";", 0);
if (full_friends_list && full_friends_list[0])
{
//in the format of: username;full name;phone;office phone;mobile phone;
// online status;friendly name;voicemail;mood
// (comma-seperated lines, usernames can have comma's)
for (int i=0; full_friends_list[i] && full_friends_list[i+1] && *full_friends_list[i] != '\0'; i+=8)
{
std::string buddy = full_friends_list[i];
if (buddy[0] == ',') {
buddy.erase(buddy.begin());
}
if (buddy.rfind(",") != std::string::npos) {
buddy = buddy.substr(buddy.rfind(","));
}
if (buddy[0] == ',') {
buddy.erase(buddy.begin());
}
LOG4CXX_INFO(logger, "Got buddy " << buddy);
std::string st = full_friends_list[i + 5];
pbnetwork::StatusType status = getStatus(st);
std::string alias = full_friends_list[i + 6];
std::string mood_text = "";
if (full_friends_list[i + 8] && *full_friends_list[i + 8] != '\0' && *full_friends_list[i + 8] != ',') {
mood_text = full_friends_list[i + 8];
}
std::vector<std::string> groups;
if (group_map.find(buddy) != group_map.end()) {
groups.push_back(group_map[buddy]);
}
np->handleBuddyChanged(m_user, buddy, alias, groups, status, mood_text);
}
}
g_strfreev(full_friends_list);
send_command("SET AUTOAWAY OFF");
send_command("SET USERSTATUS ONLINE");
return FALSE;
}
void Skype::logout() {
if (m_pid != 0) {
send_command("SET USERSTATUS INVISIBLE");
send_command("SET USERSTATUS OFFLINE");
sleep(2);
g_object_unref(m_proxy);
LOG4CXX_INFO(logger, m_username << ": Killing Skype instance");
kill((int) m_pid, SIGTERM);
m_pid = 0;
}
}
std::string Skype::send_command(const std::string &message) {
GError *error = NULL;
gchar *str = NULL;
// int message_num;
// gchar error_return[30];
if (!dbus_g_proxy_call (m_proxy, "Invoke", &error, G_TYPE_STRING, message.c_str(), G_TYPE_INVALID,
G_TYPE_STRING, &str, G_TYPE_INVALID))
{
if (error && error->message)
{
LOG4CXX_INFO(logger, m_username << ": DBUS Error: " << error->message);
g_error_free(error);
} else {
LOG4CXX_INFO(logger, m_username << ": DBUS no response");
}
}
if (str != NULL)
{
LOG4CXX_INFO(logger, m_username << ": DBUS:" << str);
}
return str ? std::string(str) : std::string();
}
static void handle_skype_message(std::string &message, Skype *sk) {
std::vector<std::string> cmd;
boost::split(cmd, message, boost::is_any_of(" "));
if (cmd[0] == "USER") {
if (cmd[1] == sk->getUsername()) {
return;
}
if (cmd[2] == "ONLINESTATUS") {
if (cmd[3] == "SKYPEOUT" || cmd[3] == "UNKNOWN") {
return;
}
else {
pbnetwork::StatusType status = getStatus(cmd[3]);
std::string mood_text = sk->send_command("GET USER " + cmd[1] + " MOOD_TEXT");
mood_text = mood_text.substr(mood_text.find("MOOD_TEXT") + 10);
std::string alias = sk->send_command("GET USER " + cmd[1] + " FULLNAME");
alias = alias.substr(alias.find("FULLNAME") + 9);
std::vector<std::string> groups;
np->handleBuddyChanged(sk->getUser(), cmd[1], alias, groups, status, mood_text);
}
}
else if (cmd[2] == "MOOD_TEXT") {
std::string st = sk->send_command("GET USER " + cmd[1] + " ONLINESTATUS");
st = st.substr(st.find("ONLINESTATUS") + 13);
pbnetwork::StatusType status = getStatus(st);
std::string mood_text = message.substr(message.find("MOOD_TEXT") + 10);
std::vector<std::string> groups;
np->handleBuddyChanged(sk->getUser(), cmd[1], "", groups, status, mood_text);
}
else if (cmd[2] == "BUDDYSTATUS" && cmd[3] == "3") {
std::string st = sk->send_command("GET USER " + cmd[1] + " ONLINESTATUS");
st = st.substr(st.find("ONLINESTATUS") + 13);
pbnetwork::StatusType status = getStatus(st);
std::string mood_text = message.substr(message.find("MOOD_TEXT") + 10);
std::vector<std::string> groups;
np->handleBuddyChanged(sk->getUser(), cmd[1], "", groups, status, mood_text);
}
else if (cmd[2] == "FULLNAME") {
std::string st = sk->send_command("GET USER " + cmd[1] + " ONLINESTATUS");
st = st.substr(st.find("ONLINESTATUS") + 13);
pbnetwork::StatusType status = getStatus(st);
std::string mood_text = sk->send_command("GET USER " + cmd[1] + " MOOD_TEXT");
mood_text = mood_text.substr(mood_text.find("MOOD_TEXT") + 10);
std::string alias = message.substr(message.find("FULLNAME") + 9);
std::vector<std::string> groups;
np->handleBuddyChanged(sk->getUser(), cmd[1], alias, groups, status, mood_text);
}
}
else if (cmd[0] == "CHATMESSAGE") {
if (cmd[3] == "RECEIVED") {
std::string body = sk->send_command("GET CHATMESSAGE " + cmd[1] + " BODY");
body = body.substr(body.find("BODY") + 5);
std::string chatname = sk->send_command("GET CHATMESSAGE " + cmd[1] + " CHATNAME");
size_t start = chatname.find("$") + 1;
size_t len = chatname.find(";") - start;
std::string from = chatname.substr(start, len);
std::string from_handle = sk->send_command("GET CHATMESSAGE " + cmd[1] + " FROM_HANDLE");
from_handle = from_handle.substr(from_handle.find("FROM_HANDLE") + 12);
// if (from_handle != sk->getUsername()) {
from = from_handle;
// }
if (from_handle == sk->getUsername())
return;
np->handleMessage(sk->getUser(), from, body);
}
}
}
DBusHandlerResult skype_notify_handler(DBusConnection *connection, DBusMessage *message, gpointer user_data) {
DBusMessageIter iterator;
gchar *message_temp;
DBusMessage *temp_message;
temp_message = dbus_message_ref(message);
dbus_message_iter_init(temp_message, &iterator);
if (dbus_message_iter_get_arg_type(&iterator) != DBUS_TYPE_STRING)
{
dbus_message_unref(message);
return (DBusHandlerResult) FALSE;
}
do {
dbus_message_iter_get_basic(&iterator, &message_temp);
std::string m(message_temp);
LOG4CXX_INFO(logger,"DBUS message: " << m);
handle_skype_message(m, (Skype *) user_data);
} while(dbus_message_iter_has_next(&iterator) && dbus_message_iter_next(&iterator));
dbus_message_unref(message);
return DBUS_HANDLER_RESULT_HANDLED;
}
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);
}
}
static int create_socket(char *host, int portno) {
struct sockaddr_in serv_addr;
int m_sock = socket(AF_INET, SOCK_STREAM, 0);
memset((char *) &serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(portno);
hostent *hos; // Resolve name
if ((hos = gethostbyname(host)) == NULL) {
// strerror() will not work for gethostbyname() and hstrerror()
// is supposedly obsolete
exit(1);
}
serv_addr.sin_addr.s_addr = *((unsigned long *) hos->h_addr_list[0]);
if (connect(m_sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
close(m_sock);
m_sock = 0;
}
int flags = fcntl(m_sock, F_GETFL);
flags |= O_NONBLOCK;
fcntl(m_sock, F_SETFL, flags);
return m_sock;
}
static gboolean transportDataReceived(GIOChannel *source, GIOCondition condition, gpointer data) {
char buffer[65535];
char *ptr = buffer;
ssize_t n = read(m_sock, 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);
return TRUE;
}
static void io_destroy(gpointer data) {
exit(1);
}
static void log_glib_error(const gchar *string) {
LOG4CXX_ERROR(logger, "GLIB ERROR:" << string);
}
int main(int argc, char **argv) {
GError *error = NULL;
GOptionContext *context;
context = g_option_context_new("config_file_name or profile name");
g_option_context_add_main_entries(context, options_entries, "");
if (!g_option_context_parse (context, &argc, &argv, &error)) {
std::cout << "option parsing failed: " << error->message << "\n";
return -1;
}
if (ver) {
// std::cout << VERSION << "\n";
std::cout << "verze\n";
g_option_context_free(context);
return 0;
}
if (argc != 2) {
#ifdef WIN32
std::cout << "Usage: spectrum.exe <configuration_file.cfg>\n";
#else
#if GLIB_CHECK_VERSION(2,14,0)
std::cout << g_option_context_get_help(context, FALSE, NULL);
#else
std::cout << "Usage: spectrum <configuration_file.cfg>\n";
std::cout << "See \"man spectrum\" for more info.\n";
#endif
#endif
}
else {
#ifndef WIN32
signal(SIGPIPE, SIG_IGN);
if (signal(SIGCHLD, spectrum_sigchld_handler) == SIG_ERR) {
std::cout << "SIGCHLD handler can't be set\n";
g_option_context_free(context);
return -1;
}
//
// if (signal(SIGINT, spectrum_sigint_handler) == SIG_ERR) {
// std::cout << "SIGINT handler can't be set\n";
// g_option_context_free(context);
// return -1;
// }
//
// if (signal(SIGTERM, spectrum_sigterm_handler) == SIG_ERR) {
// std::cout << "SIGTERM handler can't be set\n";
// g_option_context_free(context);
// return -1;
// }
//
// struct sigaction sa;
// memset(&sa, 0, sizeof(sa));
// sa.sa_handler = spectrum_sighup_handler;
// if (sigaction(SIGHUP, &sa, NULL)) {
// std::cout << "SIGHUP handler can't be set\n";
// g_option_context_free(context);
// return -1;
// }
#endif
Config config;
if (!config.load(argv[1])) {
std::cout << "Can't open " << argv[1] << " configuration file.\n";
return 1;
}
if (CONFIG_STRING(&config, "logging.backend_config").empty()) {
LoggerPtr root = log4cxx::Logger::getRootLogger();
root->addAppender(new ConsoleAppender(new PatternLayout("%d %-5p %c: %m%n")));
}
else {
log4cxx::helpers::Properties p;
log4cxx::helpers::FileInputStream *istream = new log4cxx::helpers::FileInputStream(CONFIG_STRING(&config, "logging.backend_config"));
p.load(istream);
p.setProperty("pid", boost::lexical_cast<std::string>(getpid()));
log4cxx::PropertyConfigurator::configure(p);
}
// initPurple(config);
g_type_init();
m_sock = create_socket(host, port);
g_set_printerr_handler(log_glib_error);
GIOChannel *channel;
GIOCondition cond = (GIOCondition) G_IO_IN;
channel = g_io_channel_unix_new(m_sock);
g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond, transportDataReceived, NULL, io_destroy);
np = new SpectrumNetworkPlugin(&config, host, port);
GMainLoop *m_loop;
m_loop = g_main_loop_new(NULL, FALSE);
if (m_loop) {
g_main_loop_run(m_loop);
}
}
g_option_context_free(context);
}

View file

@ -0,0 +1,10 @@
cmake_minimum_required(VERSION 2.6)
FILE(GLOB SRC *.c *.cpp)
ADD_EXECUTABLE(spectrum2_smstools3_backend ${SRC})
target_link_libraries(spectrum2_smstools3_backend transport pthread ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES})
INSTALL(TARGETS spectrum2_smstools3_backend RUNTIME DESTINATION bin)

397
backends/smstools3/main.cpp Normal file
View file

@ -0,0 +1,397 @@
/*
* 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/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 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;
for (directory_iterator itr(p); itr != end_itr; ++itr) {
try {
if (is_regular(itr->path())) {
handleSMS(itr->path().string());
remove(itr->path());
}
}
catch (const filesystem_error& ex) {
LOG4CXX_ERROR(logger, "Error when removing the SMS: " << ex.what() << ".");
}
}
m_timer->start();
}
void sendSMS(const std::string &to, const std::string &msg) {
// TODO: Probably
std::string data = "To: " + to + "\n";
data += "\n";
data += msg;
// generate random string here...
std::string bucket = "abcdefghijklmnopqrstuvwxyz";
std::string uuid;
for (int i = 0; i < 10; i++) {
uuid += bucket[rand() % bucket.size()];
}
std::ofstream myfile;
myfile.open (std::string("/var/spool/sms/outgoing/spectrum." + uuid).c_str());
myfile << data;
myfile.close();
}
void sendData(const std::string &string) {
m_conn->write(Swift::createSafeByteArray(string));
}
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) {
UserInfo info;
if (!storageBackend->getUser(user, info)) {
handleDisconnected(user, 0, "Not registered user.");
return;
}
std::list<BuddyInfo> roster;
storageBackend->getBuddies(info.id, roster);
// Send available presence to every number in the roster.
BOOST_FOREACH(BuddyInfo &b, roster) {
handleBuddyChanged(user, b.legacyName, b.alias, b.groups, pbnetwork::STATUS_ONLINE);
}
np->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 = "") {
// Remove trailing +, because smstools doesn't use it in "From: " field for received messages.
std::string n = legacyName;
if (n.find("+") == 0) {
n = n.substr(1);
}
// Create GSM Number - XMPP user pair to match the potential response and send it to the proper JID.
BuddyInfo info;
info.legacyName = n;
info.alias = user;
info.id = -1;
info.subscription = "both";
info.flags = 0;
storageBackend->addBuddy(m_internalUser, info);
LOG4CXX_INFO(logger, "Sending SMS from " << user << " to " << n << ".");
sendSMS(n, message);
}
void handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &password) {
}
void handleLeaveRoomRequest(const std::string &user, const std::string &room) {
}
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;
}
// 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;
}
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);
}
#ifdef WITH_SQLITE
if (CONFIG_STRING(&config, "database.type") == "sqlite3") {
storageBackend = new SQLite3Backend(&config);
if (!storageBackend->connect()) {
std::cerr << "Can't connect to database. Check the log to find out the reason.\n";
return -1;
}
}
#else
if (CONFIG_STRING(&config, "database.type") == "sqlite3") {
std::cerr << "Spectrum2 is not compiled with mysql backend.\n";
return -2;
}
#endif
#ifdef WITH_MYSQL
if (CONFIG_STRING(&config, "database.type") == "mysql") {
storageBackend = new MySQLBackend(&config);
if (!storageBackend->connect()) {
std::cerr << "Can't connect to database. Check the log to find out the reason.\n";
return -1;
}
}
#else
if (CONFIG_STRING(&config, "database.type") == "mysql") {
std::cerr << "Spectrum2 is not compiled with mysql backend.\n";
return -2;
}
#endif
#ifdef WITH_PQXX
if (CONFIG_STRING(&config, "database.type") == "pqxx") {
storageBackend = new PQXXBackend(&config);
if (!storageBackend->connect()) {
std::cerr << "Can't connect to database. Check the log to find out the reason.\n";
return -1;
}
}
#else
if (CONFIG_STRING(&config, "database.type") == "pqxx") {
std::cerr << "Spectrum2 is not compiled with pqxx backend.\n";
return -2;
}
#endif
if (CONFIG_STRING(&config, "database.type") != "mysql" && CONFIG_STRING(&config, "database.type") != "sqlite3"
&& CONFIG_STRING(&config, "database.type") != "pqxx" && CONFIG_STRING(&config, "database.type") != "none") {
std::cerr << "Unknown storage backend " << CONFIG_STRING(&config, "database.type") << "\n";
return -2;
}
Swift::SimpleEventLoop eventLoop;
loop_ = &eventLoop;
np = new SMSNetworkPlugin(&config, &eventLoop, host, port);
loop_->run();
return 0;
}

View file

@ -0,0 +1,10 @@
cmake_minimum_required(VERSION 2.6)
FILE(GLOB SRC *.c *.cpp)
ADD_EXECUTABLE(spectrum2_template_backend ${SRC})
target_link_libraries(spectrum2_template_backend transport pthread ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES})
#INSTALL(TARGETS spectrum2_template_backend RUNTIME DESTINATION bin)

1
backends/template/README Normal file
View file

@ -0,0 +1 @@
This is just template for creating new generic spectrum2 backends. It does not do anything!

181
backends/template/main.cpp Normal file
View file

@ -0,0 +1,181 @@
// Transport includes
#include "transport/config.h"
#include "transport/networkplugin.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");
// 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);
}
Swift::SimpleEventLoop eventLoop;
loop_ = &eventLoop;
np = new TemplatePlugin(&config, &eventLoop, host, port);
loop_->run();
return 0;
}

View file

@ -0,0 +1,53 @@
# - Try to find LIBDBUS GLIB Bindings
# Find LIBDBUSGLIB headers, libraries and the answer to all questions.
#
# LIBDBUSGLIB_FOUND True if libdbus-glib got found
# LIBDBUSGLIB_INCLUDE_DIRS Location of libdbus-glib headers
# LIBDBUSGLIB_LIBRARIES List of libraries to use libdbus-glib
#
# Copyright (c) 2008 Bjoern Ricks <bjoern.ricks@googlemail.com>
#
# Redistribution and use is allowed according to the terms of the New
# BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#
INCLUDE( FindPkgConfig )
IF ( LibDbusGlib_FIND_REQUIRED )
SET( _pkgconfig_REQUIRED "REQUIRED" )
ELSE( LibDbusGlib_FIND_REQUIRED )
SET( _pkgconfig_REQUIRED "" )
ENDIF ( LibDbusGlib_FIND_REQUIRED )
IF ( LIBDBUSGLIB_MIN_VERSION )
PKG_SEARCH_MODULE( LIBDBUSGLIB ${_pkgconfig_REQUIRED} dbus-glib-1>=${LIBDBUSGLIB_MIN_VERSION} )
ELSE ( LIBDBUSGLIB_MIN_VERSION )
PKG_SEARCH_MODULE( LIBDBUSGLIB ${_pkgconfig_REQUIRED} dbus-glib-1 )
ENDIF ( LIBDBUSGLIB_MIN_VERSION )
IF( NOT LIBDBUSGLIB_FOUND AND NOT PKG_CONFIG_FOUND )
FIND_PATH( LIBDBUSGLIB_INCLUDE_DIRS dbus/dbus-glib.h PATH_SUFFIXES dbus-1.0 dbus )
FIND_LIBRARY( LIBDBUSGLIB_LIBRARIES dbus-glib dbus-glib-1)
# Report results
IF ( LIBDBUSGLIB_LIBRARIES AND LIBDBUSGLIB_INCLUDE_DIRS )
SET( LIBDBUSGLIB_FOUND 1 )
IF ( NOT LIBDBUSGLIB_FIND_QUIETLY )
MESSAGE( STATUS "Found libdbus-glib: ${LIBDBUSGLIB_LIBRARIES} ${LIBDBUSGLIB_INCLUDE_DIRS}" )
ENDIF ( NOT LIBDBUSGLIB_FIND_QUIETLY )
ELSE ( LIBDBUSGLIB_LIBRARIES AND LIBDBUSGLIB_INCLUDE_DIRS )
IF ( LIBDBUSGLIB_FIND_REQUIRED )
MESSAGE( SEND_ERROR "Could NOT find libdbus-glib" )
ELSE ( LIBDBUSGLIB_FIND_REQUIRED )
IF ( NOT LIBDBUSGLIB_FIND_QUIETLY )
MESSAGE( STATUS "Could NOT find libdbus-glib" )
ENDIF ( NOT LIBDBUSGLIB_FIND_QUIETLY )
ENDIF ( LIBDBUSGLIB_FIND_REQUIRED )
ENDIF ( LIBDBUSGLIB_LIBRARIES AND LIBDBUSGLIB_INCLUDE_DIRS )
else()
MESSAGE( STATUS "Found libdbus-glib: ${LIBDBUSGLIB_LIBRARIES} ${LIBDBUSGLIB_INCLUDE_DIRS}" )
ENDIF()
MARK_AS_ADVANCED( LIBDBUSGLIB_LIBRARIES LIBDBUSGLIB_INCLUDE_DIRS )

View file

@ -0,0 +1,16 @@
FIND_PATH(PQXX_INCLUDE_DIR pqxx/pqxx PATHS)
MARK_AS_ADVANCED(PQXX_INCLUDE_DIR)
FIND_LIBRARY(PQXX_LIBRARY pqxx )
MARK_AS_ADVANCED(PQXX_LIBRARY)
FIND_LIBRARY(PQ_LIBRARY pq )
MARK_AS_ADVANCED(PQ_LIBRARY)
if(PQXX_LIBRARY AND PQ_LIBRARY AND PQXX_INCLUDE_DIR)
set( PQXX_FOUND 1 )
message( STATUS "Found pqxx: ${PQXX_LIBRARY}, ${PQ_LIBRARY}, ${PQXX_INCLUDE_DIR}")
else()
message(STATUS "Could NOT find pqxx and pq library")
endif()

View file

@ -0,0 +1,16 @@
/*
* Copyright (c) 2011 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#include <Swiften/Elements/GatewayPayload.h>
namespace Swift {
GatewayPayload::GatewayPayload(const JID &jid, const std::string &desc, const std::string &prompt) :
jid(jid), desc(desc), prompt(prompt) {
}
}

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2011 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#pragma once
#include <vector>
#include <string>
#include <Swiften/Elements/Payload.h>
#include <Swiften/JID/JID.h>
namespace Swift {
class GatewayPayload : public Payload {
public:
GatewayPayload(const JID &jid = JID(), const std::string &desc = "", const std::string &prompt = "");
void setJID(const JID &jid) {
this->jid = jid;
}
const JID &getJID() const {
return jid;
}
void setDesc(const std::string &desc) {
this->desc = desc;
}
const std::string &getDesc() const {
return desc;
}
void setPrompt(const std::string &prompt) {
this->prompt = prompt;
}
const std::string &getPrompt() const {
return prompt;
}
private:
JID jid;
std::string desc;
std::string prompt;
};
}

View file

@ -0,0 +1,14 @@
/*
* Copyright (c) 2011 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#include <Swiften/Elements/PubSubItem.h>
namespace Swift {
PubSubItem::PubSubItem() {
}
}

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2011 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#pragma once
#include <vector>
#include <string>
#include <Swiften/Elements/Payload.h>
namespace Swift {
class PubSubItem : public Payload {
public:
PubSubItem();
void addPayload(boost::shared_ptr<Payload> payload) {
payloads.push_back(payload);
}
const std::vector<boost::shared_ptr<Payload> > getPayloads() const {
return payloads;
}
template<typename T>
const std::vector<boost::shared_ptr<T> > getPayloads() const {
std::vector<boost::shared_ptr<T> > matched_payloads;
for (std::vector<boost::shared_ptr<Payload> >::const_iterator i = payloads.begin(); i != payloads.end(); ++i) {
boost::shared_ptr<T> result = boost::dynamic_pointer_cast<T>(*i);
if (result) {
matched_payloads.push_back(result);
}
}
return matched_payloads;
}
template<typename T>
const boost::shared_ptr<T> getPayload() const {
boost::shared_ptr<T> result;
for (std::vector<boost::shared_ptr<Payload> >::const_iterator i = payloads.begin(); i != payloads.end(); ++i) {
result = boost::dynamic_pointer_cast<T>(*i);
if (result) {
return result;
}
}
return result;
}
const std::string& getId() const { return id; }
void setId(const std::string& id) {
this->id = id;
}
private:
std::vector<boost::shared_ptr<Payload> > payloads;
std::string id;
};
}

View file

@ -0,0 +1,14 @@
/*
* Copyright (c) 2011 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#include <Swiften/Elements/PubSubPayload.h>
namespace Swift {
PubSubPayload::PubSubPayload() {
}
}

View file

@ -0,0 +1,57 @@
/*
* Copyright (c) 2012 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#pragma once
#include <vector>
#include <string>
#include <Swiften/Elements/Payload.h>
namespace Swift {
class PubSubPayload : public Payload {
public:
PubSubPayload();
void addPayload(boost::shared_ptr<Payload> payload) {
payloads.push_back(payload);
}
const std::vector<boost::shared_ptr<Payload> > getPayloads() const {
return payloads;
}
template<typename T>
const std::vector<boost::shared_ptr<T> > getPayloads() const {
std::vector<boost::shared_ptr<T> > matched_payloads;
for (std::vector<boost::shared_ptr<Payload> >::const_iterator i = payloads.begin(); i != payloads.end(); ++i) {
boost::shared_ptr<T> result = boost::dynamic_pointer_cast<T>(*i);
if (result) {
matched_payloads.push_back(result);
}
}
return matched_payloads;
}
template<typename T>
const boost::shared_ptr<T> getPayload() const {
boost::shared_ptr<T> result;
for (std::vector<boost::shared_ptr<Payload> >::const_iterator i = payloads.begin(); i != payloads.end(); ++i) {
result = boost::dynamic_pointer_cast<T>(*i);
if (result) {
return result;
}
}
return result;
}
private:
std::vector<boost::shared_ptr<Payload> > payloads;
};
}

View file

@ -0,0 +1,16 @@
/*
* Copyright (c) 2011 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#include <Swiften/Elements/PubSubPublishPayload.h>
namespace Swift {
PubSubPublishPayload::PubSubPublishPayload(const std::string &node) :
node(node) {
}
}

View file

@ -0,0 +1,43 @@
/*
* Copyright (c) 2011 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#pragma once
#include <vector>
#include <string>
#include <Swiften/Elements/Payload.h>
#include <Swiften/Elements/PubSubItem.h>
#include <Swiften/JID/JID.h>
namespace Swift {
class PubSubPublishPayload : public Payload {
public:
enum Type { None, Pending, Subscribed, Unconfigured };
PubSubPublishPayload(const std::string &node = "");
void setNode(const std::string &node) {
this->node = node;
}
const std::string &getNode() const {
return node;
}
void addItem(const boost::shared_ptr<Payload> &item) {
items.push_back(item);
}
const std::vector<boost::shared_ptr<Payload> > &getItems() const {
return items;
}
private:
std::string node;
std::vector<boost::shared_ptr<Payload> > items;
};
}

View file

@ -0,0 +1,16 @@
/*
* Copyright (c) 2011 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#include <Swiften/Elements/PubSubSubscribePayload.h>
namespace Swift {
PubSubSubscribePayload::PubSubSubscribePayload(const JID &jid, const std::string &node) :
jid(jid), node(node) {
}
}

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2011 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#pragma once
#include <vector>
#include <string>
#include <Swiften/Elements/Payload.h>
#include <Swiften/JID/JID.h>
namespace Swift {
class PubSubSubscribePayload : public Payload {
public:
PubSubSubscribePayload(const JID &jid = JID(), const std::string &node = "");
void setJID(const JID &jid) {
this->jid = jid;
}
const JID &getJID() const {
return jid;
}
void setNode(const std::string &node) {
this->node = node;
}
const std::string &getNode() const {
return node;
}
private:
JID jid;
std::string node;
};
}

View file

@ -0,0 +1,16 @@
/*
* Copyright (c) 2011 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#include <Swiften/Elements/PubSubSubscriptionPayload.h>
namespace Swift {
PubSubSubscriptionPayload::PubSubSubscriptionPayload(const JID &jid, const std::string &node) :
jid(jid), node(node), type(None) {
}
}

View file

@ -0,0 +1,60 @@
/*
* Copyright (c) 2011 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#pragma once
#include <vector>
#include <string>
#include <Swiften/Elements/Payload.h>
#include <Swiften/JID/JID.h>
namespace Swift {
class PubSubSubscriptionPayload : public Payload {
public:
enum Type { None, Pending, Subscribed, Unconfigured };
PubSubSubscriptionPayload(const JID &jid = JID(), const std::string &node = "");
void setJID(const JID &jid) {
this->jid = jid;
}
const JID &getJID() const {
return jid;
}
void setNode(const std::string &node) {
this->node = node;
}
const std::string &getNode() const {
return node;
}
void setId(const std::string &id) {
this->id = id;
}
const std::string &getId() const {
return id;
}
void setType(const Type &type) {
this->type = type;
}
const Type &getType() const {
return type;
}
private:
JID jid;
std::string node;
std::string id;
Type type;
};
}

View file

@ -18,13 +18,12 @@
#include <Swiften/FileTransfer/SOCKS5BytestreamServer.h>
#include <Swiften/Base/IDGenerator.h>
#include <Swiften/Elements/Presence.h>
#include <Swiften/Presence/PresenceOracle.h>
#include <Swiften/Base/foreach.h>
namespace Swift {
CombinedOutgoingFileTransferManager::CombinedOutgoingFileTransferManager(JingleSessionManager* jingleSessionManager, IQRouter* router, EntityCapsProvider* capsProvider, RemoteJingleTransportCandidateSelectorFactory* remoteFactory, LocalJingleTransportCandidateGeneratorFactory* localFactory, SOCKS5BytestreamRegistry* bytestreamRegistry, SOCKS5BytestreamProxy* bytestreamProxy, PresenceOracle *presOracle, SOCKS5BytestreamServer *bytestreamServer) : jsManager(jingleSessionManager), iqRouter(router), capsProvider(capsProvider), remoteFactory(remoteFactory), localFactory(localFactory), bytestreamRegistry(bytestreamRegistry), bytestreamProxy(bytestreamProxy), presenceOracle(presOracle), bytestreamServer(bytestreamServer) {
CombinedOutgoingFileTransferManager::CombinedOutgoingFileTransferManager(JingleSessionManager* jingleSessionManager, IQRouter* router, EntityCapsProvider* capsProvider, RemoteJingleTransportCandidateSelectorFactory* remoteFactory, LocalJingleTransportCandidateGeneratorFactory* localFactory, SOCKS5BytestreamRegistry* bytestreamRegistry, SOCKS5BytestreamProxy* bytestreamProxy, Transport::PresenceOracle *presOracle, SOCKS5BytestreamServer *bytestreamServer) : jsManager(jingleSessionManager), iqRouter(router), capsProvider(capsProvider), remoteFactory(remoteFactory), localFactory(localFactory), bytestreamRegistry(bytestreamRegistry), bytestreamProxy(bytestreamProxy), presenceOracle(presOracle), bytestreamServer(bytestreamServer) {
idGenerator = new IDGenerator();
}

View file

@ -11,6 +11,8 @@
#include <Swiften/JID/JID.h>
#include "transport/presenceoracle.h"
namespace Swift {
class JingleSessionManager;
@ -30,7 +32,7 @@ class PresenceOracle;
class CombinedOutgoingFileTransferManager {
public:
CombinedOutgoingFileTransferManager(JingleSessionManager* jingleSessionManager, IQRouter* router, EntityCapsProvider* capsProvider, RemoteJingleTransportCandidateSelectorFactory* remoteFactory, LocalJingleTransportCandidateGeneratorFactory* localFactory, SOCKS5BytestreamRegistry* bytestreamRegistry, SOCKS5BytestreamProxy* bytestreamProxy, PresenceOracle* presOracle, SOCKS5BytestreamServer *server);
CombinedOutgoingFileTransferManager(JingleSessionManager* jingleSessionManager, IQRouter* router, EntityCapsProvider* capsProvider, RemoteJingleTransportCandidateSelectorFactory* remoteFactory, LocalJingleTransportCandidateGeneratorFactory* localFactory, SOCKS5BytestreamRegistry* bytestreamRegistry, SOCKS5BytestreamProxy* bytestreamProxy, Transport::PresenceOracle* presOracle, SOCKS5BytestreamServer *server);
~CombinedOutgoingFileTransferManager();
boost::shared_ptr<OutgoingFileTransfer> createOutgoingFileTransfer(const JID& from, const JID& to, boost::shared_ptr<ReadBytestream>, const StreamInitiationFileInfo&);
@ -46,7 +48,7 @@ private:
IDGenerator *idGenerator;
SOCKS5BytestreamRegistry* bytestreamRegistry;
SOCKS5BytestreamProxy* bytestreamProxy;
PresenceOracle* presenceOracle;
Transport::PresenceOracle* presenceOracle;
SOCKS5BytestreamServer *bytestreamServer;
};

View file

@ -18,6 +18,7 @@ DummyNetworkFactories::DummyNetworkFactories(EventLoop* eventLoop) {
domainNameResolver = new PlatformDomainNameResolver(eventLoop);
connectionServerFactory = new DummyConnectionServerFactory(eventLoop);
m_platformXMLParserFactory = new PlatformXMLParserFactory();
this->eventLoop = eventLoop;
}
DummyNetworkFactories::~DummyNetworkFactories() {

View file

@ -41,6 +41,10 @@ namespace Swift {
return m_platformXMLParserFactory;
}
EventLoop *getEventLoop() const {
return eventLoop;
}
Swift::TLSContextFactory* getTLSContextFactory() const {
return 0;
}
@ -55,5 +59,6 @@ namespace Swift {
ConnectionFactory* connectionFactory;
DomainNameResolver* domainNameResolver;
ConnectionServerFactory* connectionServerFactory;
EventLoop *eventLoop;
};
}

View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2012 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#include <Swiften/Parser/PayloadParsers/GatewayPayloadParser.h>
#include <boost/lexical_cast.hpp>
#include <Swiften/Parser/PayloadParserFactoryCollection.h>
#include <Swiften/Parser/PayloadParserFactory.h>
#include <Swiften/Base/foreach.h>
#include <Swiften/Elements/MUCOccupant.h>
#include <Swiften/Parser/Tree/TreeReparser.h>
namespace Swift {
void GatewayPayloadParser::handleTree(ParserElement::ref root) {
foreach (ParserElement::ref child, root->getAllChildren()) {
if (child->getName() == "desc") {
getPayloadInternal()->setDesc(child->getText());
}
else if (child->getName() == "prompt") {
getPayloadInternal()->setPrompt(child->getText());
}
else if (child->getName() == "jid") {
getPayloadInternal()->setJID(child->getText());
}
}
}
}

View file

@ -0,0 +1,21 @@
/*
* Copyright (c) 2012 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#pragma once
#include <boost/optional.hpp>
#include <Swiften/Elements/GatewayPayload.h>
#include <Swiften/Parser/GenericPayloadTreeParser.h>
#include <Swiften/Parser/PayloadParsers/MUCItemParser.h>
namespace Swift {
class GatewayPayloadParser : public GenericPayloadTreeParser<GatewayPayload> {
public:
GatewayPayloadParser() {}
virtual void handleTree(ParserElement::ref root);
};
}

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 2012 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#include <Swiften/Parser/PayloadParsers/PubSubItemParser.h>
#include <boost/lexical_cast.hpp>
#include <Swiften/Parser/PayloadParserFactoryCollection.h>
#include <Swiften/Parser/PayloadParserFactory.h>
#include <Swiften/Base/foreach.h>
#include <Swiften/Elements/MUCOccupant.h>
#include <Swiften/Parser/Tree/TreeReparser.h>
namespace Swift {
void PubSubItemParser::handleTree(ParserElement::ref root) {
std::string id = root->getAttributes().getAttribute("id");
if (!id.empty()) {
getPayloadInternal()->setId(id);
}
foreach (ParserElement::ref child, root->getAllChildren()) {
getPayloadInternal()->addPayload(TreeReparser::parseTree(child, factories));
}
}
}

View file

@ -0,0 +1,24 @@
/*
* Copyright (c) 2012 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#pragma once
#include <boost/optional.hpp>
#include <Swiften/Elements/PubSubItem.h>
#include <Swiften/Parser/GenericPayloadTreeParser.h>
#include <Swiften/Parser/PayloadParsers/MUCItemParser.h>
namespace Swift {
class PayloadParserFactoryCollection;
class PubSubItemParser : public GenericPayloadTreeParser<PubSubItem> {
public:
PubSubItemParser(PayloadParserFactoryCollection* collection) : factories(collection) {}
virtual void handleTree(ParserElement::ref root);
private:
PayloadParserFactoryCollection* factories;
};
}

View file

@ -0,0 +1,25 @@
/*
* Copyright (c) 2012 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#include <Swiften/Parser/PayloadParsers/PubSubPayloadParser.h>
#include <boost/lexical_cast.hpp>
#include <Swiften/Parser/PayloadParserFactoryCollection.h>
#include <Swiften/Parser/PayloadParserFactory.h>
#include <Swiften/Base/foreach.h>
#include <Swiften/Elements/MUCOccupant.h>
#include <Swiften/Parser/Tree/TreeReparser.h>
namespace Swift {
void PubSubPayloadParser::handleTree(ParserElement::ref root) {
foreach (ParserElement::ref child, root->getAllChildren()) {
getPayloadInternal()->addPayload(TreeReparser::parseTree(child, factories));
}
}
}

View file

@ -0,0 +1,24 @@
/*
* Copyright (c) 2012 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#pragma once
#include <boost/optional.hpp>
#include <Swiften/Elements/PubSubPayload.h>
#include <Swiften/Parser/GenericPayloadTreeParser.h>
#include <Swiften/Parser/PayloadParsers/MUCItemParser.h>
namespace Swift {
class PayloadParserFactoryCollection;
class PubSubPayloadParser : public GenericPayloadTreeParser<PubSubPayload> {
public:
PubSubPayloadParser(PayloadParserFactoryCollection* collection) : factories(collection) {}
virtual void handleTree(ParserElement::ref root);
private:
PayloadParserFactoryCollection* factories;
};
}

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 2012 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#include <Swiften/Parser/PayloadParsers/PubSubPublishPayloadParser.h>
#include <boost/lexical_cast.hpp>
#include <Swiften/Parser/PayloadParserFactoryCollection.h>
#include <Swiften/Parser/PayloadParserFactory.h>
#include <Swiften/Base/foreach.h>
#include <Swiften/Elements/MUCOccupant.h>
#include <Swiften/Parser/Tree/TreeReparser.h>
namespace Swift {
void PubSubPublishPayloadParser::handleTree(ParserElement::ref root) {
std::string node = root->getAttributes().getAttribute("node");
if (!node.empty()) {
getPayloadInternal()->setNode(node);
}
foreach (ParserElement::ref child, root->getAllChildren()) {
getPayloadInternal()->addItem(TreeReparser::parseTree(child, factories));
}
}
}

View file

@ -0,0 +1,24 @@
/*
* Copyright (c) 2012 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#pragma once
#include <boost/optional.hpp>
#include <Swiften/Elements/PubSubPublishPayload.h>
#include <Swiften/Parser/GenericPayloadTreeParser.h>
#include <Swiften/Parser/PayloadParsers/MUCItemParser.h>
namespace Swift {
class PayloadParserFactoryCollection;
class PubSubPublishPayloadParser : public GenericPayloadTreeParser<PubSubPublishPayload> {
public:
PubSubPublishPayloadParser(PayloadParserFactoryCollection* collection) : factories(collection) {}
virtual void handleTree(ParserElement::ref root);
private:
PayloadParserFactoryCollection* factories;
};
}

View file

@ -0,0 +1,32 @@
/*
* Copyright (c) 2012 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#include <Swiften/Parser/PayloadParsers/PubSubSubscribePayloadParser.h>
#include <boost/lexical_cast.hpp>
#include <Swiften/Parser/PayloadParserFactoryCollection.h>
#include <Swiften/Parser/PayloadParserFactory.h>
#include <Swiften/Base/foreach.h>
#include <Swiften/Elements/MUCOccupant.h>
#include <Swiften/Parser/Tree/TreeReparser.h>
namespace Swift {
void PubSubSubscribePayloadParser::handleTree(ParserElement::ref root) {
std::string node = root->getAttributes().getAttribute("node");
if (!node.empty()) {
getPayloadInternal()->setNode(node);
}
std::string jid = root->getAttributes().getAttribute("jid");
if (!jid.empty()) {
getPayloadInternal()->setJID(jid);
}
}
}

View file

@ -0,0 +1,24 @@
/*
* Copyright (c) 2012 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#pragma once
#include <boost/optional.hpp>
#include <Swiften/Elements/PubSubSubscribePayload.h>
#include <Swiften/Parser/GenericPayloadTreeParser.h>
#include <Swiften/Parser/PayloadParsers/MUCItemParser.h>
namespace Swift {
class PayloadParserFactoryCollection;
class PubSubSubscribePayloadParser : public GenericPayloadTreeParser<PubSubSubscribePayload> {
public:
PubSubSubscribePayloadParser(PayloadParserFactoryCollection* collection) : factories(collection) {}
virtual void handleTree(ParserElement::ref root);
private:
PayloadParserFactoryCollection* factories;
};
}

View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2012 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#include <Swiften/Parser/PayloadParsers/PubSubSubscriptionPayloadParser.h>
#include <boost/lexical_cast.hpp>
#include <Swiften/Parser/PayloadParserFactoryCollection.h>
#include <Swiften/Parser/PayloadParserFactory.h>
#include <Swiften/Base/foreach.h>
#include <Swiften/Elements/MUCOccupant.h>
#include <Swiften/Parser/Tree/TreeReparser.h>
namespace Swift {
void PubSubSubscriptionPayloadParser::handleTree(ParserElement::ref root) {
std::string node = root->getAttributes().getAttribute("node");
if (!node.empty()) {
getPayloadInternal()->setNode(node);
}
std::string jid = root->getAttributes().getAttribute("jid");
if (!jid.empty()) {
getPayloadInternal()->setJID(jid);
}
std::string id = root->getAttributes().getAttribute("subid");
if (!id.empty()) {
getPayloadInternal()->setId(id);
}
std::string type = root->getAttributes().getAttribute("subscription");
if (type == "none") {
getPayloadInternal()->setType(PubSubSubscriptionPayload::None);
}
else if (type == "subscribed") {
getPayloadInternal()->setType(PubSubSubscriptionPayload::Subscribed);
}
else if (type == "pending") {
getPayloadInternal()->setType(PubSubSubscriptionPayload::Pending);
}
else if (type == "unconfigured") {
getPayloadInternal()->setType(PubSubSubscriptionPayload::Unconfigured);
}
}
}

View file

@ -0,0 +1,24 @@
/*
* Copyright (c) 2012 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#pragma once
#include <boost/optional.hpp>
#include <Swiften/Elements/PubSubSubscriptionPayload.h>
#include <Swiften/Parser/GenericPayloadTreeParser.h>
#include <Swiften/Parser/PayloadParsers/MUCItemParser.h>
namespace Swift {
class PayloadParserFactoryCollection;
class PubSubSubscriptionPayloadParser : public GenericPayloadTreeParser<PubSubSubscriptionPayload> {
public:
PubSubSubscriptionPayloadParser(PayloadParserFactoryCollection* collection) : factories(collection) {}
virtual void handleTree(ParserElement::ref root);
private:
PayloadParserFactoryCollection* factories;
};
}

View file

@ -0,0 +1,41 @@
/*
* Copyright (c) 2011 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#include <Swiften/Serializer/PayloadSerializers/GatewayPayloadSerializer.h>
#include <Swiften/Base/foreach.h>
#include <Swiften/Serializer/XML/XMLRawTextNode.h>
#include <Swiften/Serializer/XML/XMLTextNode.h>
#include <Swiften/Serializer/XML/XMLElement.h>
#include <Swiften/Serializer/PayloadSerializerCollection.h>
namespace Swift {
GatewayPayloadSerializer::GatewayPayloadSerializer()
: GenericPayloadSerializer<GatewayPayload>() {
}
std::string GatewayPayloadSerializer::serializePayload(boost::shared_ptr<GatewayPayload> payload) const {
XMLElement query("query", "jabber:iq:gateway");
if (payload->getJID().isValid()) {
boost::shared_ptr<XMLElement> jid(new XMLElement("jid", "", payload->getJID().toBare().toString()));
query.addNode(jid);
}
if (!payload->getDesc().empty()) {
boost::shared_ptr<XMLElement> desc(new XMLElement("desc", "", payload->getDesc()));
query.addNode(desc);
}
if (!payload->getPrompt().empty()) {
boost::shared_ptr<XMLElement> prompt(new XMLElement("prompt", "", payload->getPrompt()));
query.addNode(prompt);
}
return query.serialize();
}
}

View file

@ -0,0 +1,19 @@
/*
* Copyright (c) 2011 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#pragma once
#include <Swiften/Serializer/GenericPayloadSerializer.h>
#include <Swiften/Elements/GatewayPayload.h>
namespace Swift {
class GatewayPayloadSerializer : public GenericPayloadSerializer<GatewayPayload> {
public:
GatewayPayloadSerializer();
virtual std::string serializePayload(boost::shared_ptr<GatewayPayload> item) const;
};
}

View file

@ -0,0 +1,38 @@
/*
* Copyright (c) 2011 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#include <Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.h>
#include <Swiften/Base/foreach.h>
#include <Swiften/Serializer/XML/XMLRawTextNode.h>
#include <Swiften/Serializer/XML/XMLTextNode.h>
#include <Swiften/Serializer/XML/XMLElement.h>
#include <Swiften/Serializer/PayloadSerializerCollection.h>
namespace Swift {
PubSubItemSerializer::PubSubItemSerializer(PayloadSerializerCollection *serializers) :
GenericPayloadSerializer<PubSubItem>(), serializers(serializers) {
}
std::string PubSubItemSerializer::serializePayload(boost::shared_ptr<PubSubItem> payload) const {
XMLElement item("item");
if (!payload->getId().empty()) {
item.setAttribute("id", payload->getId());
}
if (!payload->getPayloads().empty()) {
foreach(boost::shared_ptr<Payload> subPayload, payload->getPayloads()) {
PayloadSerializer* serializer = serializers->getPayloadSerializer(subPayload);
if (serializer) {
item.addNode(boost::shared_ptr<XMLRawTextNode>(new XMLRawTextNode(serializer->serialize(subPayload))));
}
}
}
return item.serialize();
}
}

View file

@ -0,0 +1,22 @@
/*
* Copyright (c) 2011 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#pragma once
#include <Swiften/Serializer/GenericPayloadSerializer.h>
#include <Swiften/Elements/PubSubItem.h>
namespace Swift {
class PayloadSerializerCollection;
class PubSubItemSerializer : public GenericPayloadSerializer<PubSubItem> {
public:
PubSubItemSerializer(PayloadSerializerCollection *serializers);
virtual std::string serializePayload(boost::shared_ptr<PubSubItem> item) const;
private:
PayloadSerializerCollection *serializers;
};
}

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2011 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#include <Swiften/Serializer/PayloadSerializers/PubSubPayloadSerializer.h>
#include <Swiften/Base/foreach.h>
#include <Swiften/Serializer/XML/XMLRawTextNode.h>
#include <Swiften/Serializer/XML/XMLTextNode.h>
#include <Swiften/Serializer/XML/XMLElement.h>
#include <Swiften/Serializer/PayloadSerializerCollection.h>
namespace Swift {
PubSubPayloadSerializer::PubSubPayloadSerializer(PayloadSerializerCollection *serializers)
: GenericPayloadSerializer<PubSubPayload>(),
serializers(serializers) {
}
std::string PubSubPayloadSerializer::serializePayload(boost::shared_ptr<PubSubPayload> payload) const {
XMLElement pubsub("pubsub", "http://jabber.org/protocol/pubsub");
if (!payload->getPayloads().empty()) {
foreach(boost::shared_ptr<Payload> subPayload, payload->getPayloads()) {
PayloadSerializer* serializer = serializers->getPayloadSerializer(subPayload);
if (serializer) {
pubsub.addNode(boost::shared_ptr<XMLRawTextNode>(new XMLRawTextNode(serializer->serialize(subPayload))));
}
}
}
return pubsub.serialize();
}
}

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2011 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#pragma once
#include <Swiften/Serializer/GenericPayloadSerializer.h>
#include <Swiften/Elements/PubSubPayload.h>
namespace Swift {
class PayloadSerializerCollection;
class PubSubPayloadSerializer : public GenericPayloadSerializer<PubSubPayload> {
public:
PubSubPayloadSerializer(PayloadSerializerCollection *serializers);
virtual std::string serializePayload(boost::shared_ptr<PubSubPayload> item) const;
private:
PayloadSerializerCollection *serializers;
};
}

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2011 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#include <Swiften/Serializer/PayloadSerializers/PubSubPublishPayloadSerializer.h>
#include <Swiften/Base/foreach.h>
#include <Swiften/Serializer/XML/XMLRawTextNode.h>
#include <Swiften/Serializer/XML/XMLTextNode.h>
#include <Swiften/Serializer/XML/XMLElement.h>
#include <Swiften/Serializer/PayloadSerializerCollection.h>
namespace Swift {
PubSubPublishPayloadSerializer::PubSubPublishPayloadSerializer(PayloadSerializerCollection *serializers)
: GenericPayloadSerializer<PubSubPublishPayload>(),
serializers(serializers) {
}
std::string PubSubPublishPayloadSerializer::serializePayload(boost::shared_ptr<PubSubPublishPayload> payload) const {
XMLElement publish("publish");
if (!payload->getNode().empty()) {
publish.setAttribute("node", payload->getNode());
}
if (!payload->getItems().empty()) {
foreach(boost::shared_ptr<Payload> subPayload, payload->getItems()) {
PayloadSerializer* serializer = serializers->getPayloadSerializer(subPayload);
if (serializer) {
publish.addNode(boost::shared_ptr<XMLRawTextNode>(new XMLRawTextNode(serializer->serialize(subPayload))));
}
}
}
return publish.serialize();
}
}

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2011 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#pragma once
#include <Swiften/Serializer/GenericPayloadSerializer.h>
#include <Swiften/Elements/PubSubPublishPayload.h>
namespace Swift {
class PayloadSerializerCollection;
class PubSubPublishPayloadSerializer : public GenericPayloadSerializer<PubSubPublishPayload> {
public:
PubSubPublishPayloadSerializer(PayloadSerializerCollection *serializers);
virtual std::string serializePayload(boost::shared_ptr<PubSubPublishPayload> item) const;
private:
PayloadSerializerCollection *serializers;
};
}

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2011 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#include <Swiften/Serializer/PayloadSerializers/PubSubSubscribePayloadSerializer.h>
#include <Swiften/Base/foreach.h>
#include <Swiften/Serializer/XML/XMLRawTextNode.h>
#include <Swiften/Serializer/XML/XMLTextNode.h>
#include <Swiften/Serializer/XML/XMLElement.h>
#include <Swiften/Serializer/PayloadSerializerCollection.h>
namespace Swift {
PubSubSubscribePayloadSerializer::PubSubSubscribePayloadSerializer()
: GenericPayloadSerializer<PubSubSubscribePayload>() {
}
std::string PubSubSubscribePayloadSerializer::serializePayload(boost::shared_ptr<PubSubSubscribePayload> payload) const {
XMLElement subscribe("subscribe");
if (!payload->getJID().isValid()) {
subscribe.setAttribute("jid", payload->getJID().toBare().toString());
}
if (!payload->getNode().empty()) {
subscribe.setAttribute("node", payload->getNode());
}
return subscribe.serialize();
}
}

View file

@ -0,0 +1,19 @@
/*
* Copyright (c) 2011 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#pragma once
#include <Swiften/Serializer/GenericPayloadSerializer.h>
#include <Swiften/Elements/PubSubSubscribePayload.h>
namespace Swift {
class PubSubSubscribePayloadSerializer : public GenericPayloadSerializer<PubSubSubscribePayload> {
public:
PubSubSubscribePayloadSerializer();
virtual std::string serializePayload(boost::shared_ptr<PubSubSubscribePayload> item) const;
};
}

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2011 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#include <Swiften/Serializer/PayloadSerializers/PubSubSubscriptionPayloadSerializer.h>
#include <Swiften/Base/foreach.h>
#include <Swiften/Serializer/XML/XMLRawTextNode.h>
#include <Swiften/Serializer/XML/XMLTextNode.h>
#include <Swiften/Serializer/XML/XMLElement.h>
#include <Swiften/Serializer/PayloadSerializerCollection.h>
namespace Swift {
PubSubSubscriptionPayloadSerializer::PubSubSubscriptionPayloadSerializer()
: GenericPayloadSerializer<PubSubSubscriptionPayload>() {
}
std::string PubSubSubscriptionPayloadSerializer::serializePayload(boost::shared_ptr<PubSubSubscriptionPayload> payload) const {
XMLElement subscription("subscription");
if (!payload->getJID().isValid()) {
subscription.setAttribute("jid", payload->getJID().toBare().toString());
}
if (!payload->getNode().empty()) {
subscription.setAttribute("node", payload->getNode());
}
switch (payload->getType()) {
case PubSubSubscriptionPayload::None:
subscription.setAttribute("subscription", "none");
break;
case PubSubSubscriptionPayload::Subscribed:
subscription.setAttribute("subscription", "subscribed");
break;
case PubSubSubscriptionPayload::Unconfigured:
subscription.setAttribute("subscription", "unconfigured");
break;
case PubSubSubscriptionPayload::Pending:
subscription.setAttribute("subscription", "pending");
break;
}
return subscription.serialize();
}
}

View file

@ -0,0 +1,19 @@
/*
* Copyright (c) 2011 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#pragma once
#include <Swiften/Serializer/GenericPayloadSerializer.h>
#include <Swiften/Elements/PubSubSubscriptionPayload.h>
namespace Swift {
class PubSubSubscriptionPayloadSerializer : public GenericPayloadSerializer<PubSubSubscriptionPayload> {
public:
PubSubSubscriptionPayloadSerializer();
virtual std::string serializePayload(boost::shared_ptr<PubSubSubscriptionPayload> item) const;
};
}

View file

@ -32,11 +32,13 @@ void ServerStanzaChannel::addSession(boost::shared_ptr<ServerFromClientSession>
sessions[session->getRemoteJID().toBare().toString()].push_back(session);
session->onSessionFinished.connect(boost::bind(&ServerStanzaChannel::handleSessionFinished, this, _1, session));
session->onElementReceived.connect(boost::bind(&ServerStanzaChannel::handleElement, this, _1, session));
session->onDataRead.connect(boost::bind(&ServerStanzaChannel::handleDataRead, this, _1, session));
}
void ServerStanzaChannel::removeSession(boost::shared_ptr<ServerFromClientSession> session) {
session->onSessionFinished.disconnect(boost::bind(&ServerStanzaChannel::handleSessionFinished, this, _1, session));
session->onElementReceived.disconnect(boost::bind(&ServerStanzaChannel::handleElement, this, _1, session));
session->onDataRead.disconnect(boost::bind(&ServerStanzaChannel::handleDataRead, this, _1, session));
std::list<boost::shared_ptr<ServerFromClientSession> > &lst = sessions[session->getRemoteJID().toBare().toString()];
lst.erase(std::remove(lst.begin(), lst.end(), session), lst.end());
}
@ -53,6 +55,15 @@ void ServerStanzaChannel::sendPresence(boost::shared_ptr<Presence> presence) {
send(presence);
}
void ServerStanzaChannel::handleDataRead(const SafeByteArray &data, const boost::shared_ptr<ServerFromClientSession> &session) {
if (safeByteArrayToString(data).find("</stream:stream>") != std::string::npos) {
Swift::Presence::ref presence = Swift::Presence::create();
presence->setFrom(session->getRemoteJID());
presence->setType(Swift::Presence::Unavailable);
onPresenceReceived(presence);
}
}
void ServerStanzaChannel::finishSession(const JID& to, boost::shared_ptr<Element> element, bool last) {
std::vector<boost::shared_ptr<ServerFromClientSession> > candidateSessions;
for (std::list<boost::shared_ptr<ServerFromClientSession> >::const_iterator i = sessions[to.toBare().toString()].begin(); i != sessions[to.toBare().toString()].end(); ++i) {

View file

@ -41,6 +41,7 @@ namespace Swift {
void send(boost::shared_ptr<Stanza> stanza);
void handleSessionFinished(const boost::optional<Session::SessionError>&, const boost::shared_ptr<ServerFromClientSession> &session);
void handleElement(boost::shared_ptr<Element> element, const boost::shared_ptr<ServerFromClientSession> &session);
void handleDataRead(const SafeByteArray &data, const boost::shared_ptr<ServerFromClientSession> &session);
void handleSessionInitialized();
private:

View file

@ -14,6 +14,13 @@
#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 "Swiften/TLS/OpenSSL/OpenSSLServerContext.h"
#include "Swiften/TLS/OpenSSL/OpenSSLCertificate.h"
@ -179,7 +186,7 @@ void OpenSSLServerContext::sendPendingDataToApplication() {
bool OpenSSLServerContext::setServerCertificate(const PKCS12Certificate& certificate) {
if (certificate.isNull()) {
// std::cout << "error 1\n";
LOG4CXX_ERROR(logger, "TLS WILL NOT WORK: Certificate can't be loaded.");
return false;
}
@ -189,7 +196,7 @@ bool OpenSSLServerContext::setServerCertificate(const PKCS12Certificate& certifi
boost::shared_ptr<PKCS12> pkcs12(d2i_PKCS12_bio(bio, NULL), PKCS12_free);
BIO_free(bio);
if (!pkcs12) {
// std::cout << "error 2\n";
LOG4CXX_ERROR(logger, "TLS WILL NOT WORK: Certificate is not in PKCS#12 format.");
return false;
}
@ -199,7 +206,7 @@ bool OpenSSLServerContext::setServerCertificate(const PKCS12Certificate& certifi
STACK_OF(X509)* caCertsPtr = 0;
int result = PKCS12_parse(pkcs12.get(), reinterpret_cast<const char*>(vecptr(certificate.getPassword())), &privateKeyPtr, &certPtr, &caCertsPtr);
if (result != 1) {
// std::cout << "error 3\n";
LOG4CXX_ERROR(logger, "TLS WILL NOT WORK: Certificate is not in PKCS#12 format.");
return false;
}
boost::shared_ptr<X509> cert(certPtr, X509_free);
@ -208,11 +215,11 @@ bool OpenSSLServerContext::setServerCertificate(const PKCS12Certificate& certifi
// Use the key & certificates
if (SSL_CTX_use_certificate(context_, cert.get()) != 1) {
// std::cout << "error 4\n";
LOG4CXX_ERROR(logger, "TLS WILL NOT WORK: Can't use this certificate");
return false;
}
if (SSL_CTX_use_PrivateKey(context_, privateKey.get()) != 1) {
// std::cout << "error 5\n";
LOG4CXX_ERROR(logger, "TLS WILL NOT WORK: Can't use this private key");
return false;
}
return true;

View file

@ -0,0 +1,43 @@
/**
* libtransport -- C++ library for easy XMPP Transports development
*
* Copyright (C) 2011, Jan Kaluza <hanzz.k@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
*/
#pragma once
#include <vector>
#include "Swiften/Swiften.h"
#include "Swiften/Queries/Responder.h"
#include "Swiften/Elements/GatewayPayload.h"
namespace Transport {
class UserManager;
class GatewayResponder : public Swift::Responder<Swift::GatewayPayload> {
public:
GatewayResponder(Swift::IQRouter *router, UserManager *userManager);
~GatewayResponder();
private:
virtual bool handleGetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<Swift::GatewayPayload> payload);
virtual bool handleSetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<Swift::GatewayPayload> payload);
UserManager *m_userManager;
};
}

View file

@ -0,0 +1,112 @@
/**
* 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
#ifdef WITH_PQXX
#include <string>
#include <map>
#include "Swiften/Swiften.h"
#include "transport/storagebackend.h"
#include "transport/config.h"
#include <pqxx/pqxx>
namespace Transport {
/// Used to store transport data into SQLite3 database.
class PQXXBackend : public StorageBackend
{
public:
/// Creates new PQXXBackend instance.
/// \param config cofiguration, this class uses following Config values:
/// - database.database - path to SQLite3 database file, database file is created automatically
/// - service.prefix - prefix for tables created by createDatabase method
PQXXBackend(Config *config);
/// Destructor.
~PQXXBackend();
/// Connects to the database and creates it if it's needed. This method call createDatabase() function
/// automatically.
/// \return true if database is opened successfully.
bool connect();
void disconnect();
/// Creates database structure.
/// \see connect()
/// \return true if database structure has been created successfully. Note that it returns True also if database structure
/// already exists.
bool createDatabase();
/// Stores user into database.
/// \param user user struct containing all information about user which have to be stored
void setUser(const UserInfo &user);
/// Gets user data from database and stores them into user reference.
/// \param barejid barejid of user
/// \param user UserInfo object where user data will be stored
/// \return true if user has been found in database
bool getUser(const std::string &barejid, UserInfo &user);
/// Changes users online state variable in database.
/// \param id id of user - UserInfo.id
/// \param online online state
void setUserOnline(long id, bool online);
/// Removes user and all connected data from database.
/// \param id id of user - UserInfo.id
/// \return true if user has been found in database and removed
bool removeUser(long id);
/// Returns JIDs of all buddies in user's roster.
/// \param id id of user - UserInfo.id
/// \param roster string list used to store user's roster
/// \return true if user has been found in database and roster has been fetched
bool getBuddies(long id, std::list<BuddyInfo> &roster);
bool getOnlineUsers(std::vector<std::string> &users);
long addBuddy(long userId, const BuddyInfo &buddyInfo);
void updateBuddy(long userId, const BuddyInfo &buddyInfo);
void removeBuddy(long id) {}
void getUserSetting(long userId, const std::string &variable, int &type, std::string &value);
void updateUserSetting(long userId, const std::string &variable, const std::string &value);
void beginTransaction();
void commitTransaction();
private:
bool exec(const std::string &query, bool show_error = true);
bool exec(pqxx::nontransaction &txn, const std::string &query, bool show_error = true);
template<typename T>
std::string quote(pqxx::nontransaction &txn, const T &t);
Config *m_config;
std::string m_prefix;
pqxx::connection *m_conn;
};
}
#endif

View file

@ -0,0 +1,57 @@
/**
* XMPP - libpurple transport
*
* Copyright (C) 2009, Jan Kaluza <hanzz@soc.pidgin.im>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
*/
#pragma once
#include <map>
#include <string>
#include <Swiften/Elements/Presence.h>
#include <Swiften/Client/StanzaChannel.h>
#include <Swiften/Base/boost_bsignals.h>
namespace Transport {
class PresenceOracle {
public:
PresenceOracle(Swift::StanzaChannel* stanzaChannel);
~PresenceOracle();
Swift::Presence::ref getLastPresence(const Swift::JID&) const;
Swift::Presence::ref getHighestPriorityPresence(const Swift::JID& bareJID) const;
std::vector<Swift::Presence::ref> getAllPresence(const Swift::JID& bareJID) const;
public:
boost::signal<void (Swift::Presence::ref)> onPresenceChange;
private:
void handleIncomingPresence(Swift::Presence::ref presence);
void handleStanzaChannelAvailableChanged(bool);
private:
typedef std::map<Swift::JID, Swift::Presence::ref> PresenceMap;
typedef std::map<Swift::JID, PresenceMap> PresencesMap;
PresencesMap entries_;
Swift::StanzaChannel* stanzaChannel_;
};
}

View file

@ -27,7 +27,6 @@
#include "Swiften/Disco/EntityCapsManager.h"
#include "Swiften/Disco/CapsManager.h"
#include "Swiften/Disco/CapsMemoryStorage.h"
#include "Swiften/Presence/PresenceOracle.h"
#include "Swiften/Network/BoostTimerFactory.h"
#include "Swiften/Network/BoostIOServiceThread.h"
#include "Swiften/Server/UserRegistry.h"
@ -37,6 +36,7 @@
#include <boost/bind.hpp>
#include "transport/config.h"
#include "transport/factory.h"
#include "transport/presenceoracle.h"
namespace Transport {
// typedef enum { CLIENT_FEATURE_ROSTERX = 2,
@ -92,7 +92,7 @@ namespace Transport {
/// You can use it to check current resource connected for particular user.
/// \return Swift::PresenceOracle associated with this Transport::Component.
Swift::PresenceOracle *getPresenceOracle();
PresenceOracle *getPresenceOracle();
/// Returns True if the component is in server mode.
@ -179,7 +179,7 @@ namespace Transport {
Swift::EntityCapsManager *m_entityCapsManager;
Swift::CapsManager *m_capsManager;
Swift::CapsMemoryStorage *m_capsMemoryStorage;
Swift::PresenceOracle *m_presenceOracle;
PresenceOracle *m_presenceOracle;
Swift::StanzaChannel *m_stanzaChannel;
Swift::IQRouter *m_iqRouter;

View file

@ -22,7 +22,6 @@
#include <time.h>
#include "Swiften/Swiften.h"
#include "Swiften/Presence/PresenceOracle.h"
#include "Swiften/Disco/EntityCapsManager.h"
#include "Swiften/Disco/EntityCapsProvider.h"
#include "storagebackend.h"
@ -35,6 +34,7 @@ class Component;
class RosterManager;
class ConversationManager;
class UserManager;
class PresenceOracle;
struct UserInfo;
/// Represents online XMPP user.
@ -125,7 +125,7 @@ class User : public Swift::EntityCapsProvider {
UserManager *m_userManager;
ConversationManager *m_conversationManager;
Swift::EntityCapsManager *m_entityCapsManager;
Swift::PresenceOracle *m_presenceOracle;
PresenceOracle *m_presenceOracle;
UserInfo m_userInfo;
void *m_data;
bool m_connected;

View file

@ -104,6 +104,10 @@ class UserManager : public Swift::EntityCapsProvider {
return m_userRegistry;
}
Component *getComponent() {
return m_component;
}
/// Connects user manually.
/// \param user JID of user.
void connectUser(const Swift::JID &user);

View file

@ -40,6 +40,8 @@ std::string serializeGroups(const std::vector<std::string> &groups);
std::vector<std::string> deserializeGroups(std::string &groups);
int getRandomPort(const std::string &s);
}
}

View file

@ -5,12 +5,14 @@
#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 "Swiften/EventLoop/SimpleEventLoop.h"
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
@ -379,7 +381,23 @@ int main(int argc, char **argv)
}
#endif
if (CONFIG_STRING(&config, "database.type") != "mysql" && CONFIG_STRING(&config, "database.type") != "sqlite3") {
#ifdef WITH_PQXX
if (CONFIG_STRING(&config, "database.type") == "pqxx") {
storageBackend = new PQXXBackend(&config);
if (!storageBackend->connect()) {
std::cerr << "Can't connect to database. Check the log to find out the reason.\n";
return -1;
}
}
#else
if (CONFIG_STRING(&config, "database.type") == "pqxx") {
std::cerr << "Spectrum2 is not compiled with pqxx backend.\n";
return -2;
}
#endif
if (CONFIG_STRING(&config, "database.type") != "mysql" && CONFIG_STRING(&config, "database.type") != "sqlite3"
&& CONFIG_STRING(&config, "database.type") != "pqxx" && CONFIG_STRING(&config, "database.type") != "none") {
std::cerr << "Unknown storage backend " << CONFIG_STRING(&config, "database.type") << "\n";
return -2;
}
@ -404,6 +422,9 @@ int main(int argc, char **argv)
StatsResponder statsResponder(&transport, &userManager, &plugin, storageBackend);
statsResponder.start();
GatewayResponder gatewayResponder(transport.getIQRouter(), &userManager);
gatewayResponder.start();
eventLoop_ = &eventLoop;
eventLoop.run();

View file

@ -14,6 +14,7 @@ admin_password=test
#cert_password=test #password to that certificate if any
users_per_backend=10
backend=/home/hanzz/code/libtransport/backends/libpurple/spectrum2_libpurple_backend
#backend=/home/hanzz/code/libtransport/backends/smstools3/spectrum2_smstools3_backend
#backend=/usr/bin/mono /home/hanzz/code/networkplugin-csharp/msnp-sharp-backend/bin/Debug/msnp-sharp-backend.exe
#backend=/home/hanzz/code/libtransport/backends/frotz/spectrum2_frotz_backend
#backend=/home/hanzz/code/libtransport/backends/libircclient-qt/spectrum2_libircclient-qt_backend
@ -21,10 +22,12 @@ backend=/home/hanzz/code/libtransport/backends/libpurple/spectrum2_libpurple_bac
protocol=any
#protocol=prpl-icq
irc_server=irc.freenode.org
working_dir=./
[backend]
#default_avatar=catmelonhead.jpg
#no_vcard_fetch=true
incoming_dir=/var/spool/sms/incoming
[logging]
#config=logging.cfg # log4cxx/log4j logging configuration file
@ -34,3 +37,9 @@ irc_server=irc.freenode.org
type = none # or "none" without database backend
database = test.sql
prefix=icq
#type = mysql # or "none" without database backend.......................................................................................................................
#database = test
#prefix=
#user=root
#password=yourrootsqlpassword
#encryption_key=hanzzik

View file

@ -24,7 +24,9 @@ port = 5222
backend_host = localhost
# Port on which Spectrum listens for backends.
backend_port=10001
# By default Spectrum chooses random backend port and there's
# no need to change it normally
#backend_port=10001
# Full path to PKCS#12 cetficiate used for TLS in server mode.
#cert=
@ -38,6 +40,8 @@ users_per_backend=10
# Full path to backend binary.
backend=/usr/bin/spectrum2_libpurple_backend
#backend=/usr/bin/spectrum2_libircclient-qt_backend
# For skype:
#backend=/usr/bin/xvfb-run -n BACKEND_ID -s "-screen 0 10x10x8" -f /tmp/x-skype-gw /usr/bin/spectrum2_skype_backend
# Libpurple protocol-id for spectrum_libpurple_backend
protocol=prpl-jabber
@ -69,11 +73,11 @@ backend_config = /etc/spectrum2/backend-logging.cfg
[database]
# Database backend type
# "sqlite3", "mysql" or "none" without database backend
# "sqlite3", "mysql", "pqxx", or "none" without database backend
type = none
# For SQLite3: Full path to database
# For MySQL: name of database
# For MySQL and PostgreSQL: name of database
# default database = /var/lib/spectrum2/$jid/database.sql
#database = jabber_transport
@ -91,3 +95,20 @@ type = none
# Prefix used for tables
#prefix = jabber_
[registration]
# Enable public registrations
enable_public_registration=1
# Text to display upon user registration form
#username_label=Jabber JID (e.g. user@server.tld):
#instructions=Enter your remote jabber JID and password as well as your local username and password
# If True a local jabber account on <local_account_server> is needed
# for transport registration, the idea is to enable public registration
# from other servers, but only for users, who have already local accounts
#require_local_account=1
#local_username_label=Local username (without @server.tld):
#local_account_server=localhost
#local_account_server_timeout=10000

View file

@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 2.6)
FILE(GLOB SRC *.cpp)
ADD_EXECUTABLE(spectrum2_manager ${SRC} ../../src/config.cpp)
ADD_EXECUTABLE(spectrum2_manager ${SRC} ../../src/config.cpp ../../src/util.cpp)
target_link_libraries(spectrum2_manager ${SWIFTEN_LIBRARY})

View file

@ -20,11 +20,11 @@ endif()
if (PROTOBUF_FOUND)
if (CMAKE_COMPILER_IS_GNUCXX)
ADD_LIBRARY(transport SHARED ${HEADERS} ${SRC} ${SWIFTEN_SRC} ${CMAKE_CURRENT_BINARY_DIR}/../include/transport/protocol.pb.cc)
ADD_LIBRARY(transport SHARED ${HEADERS} ${SRC} ${SWIFTEN_SRC})
else(CMAKE_COMPILER_IS_GNUCXX)
ADD_LIBRARY(transport STATIC ${HEADERS} ${SRC} ${SWIFTEN_SRC} ${CMAKE_CURRENT_BINARY_DIR}/../include/transport/protocol.pb.cc)
ADD_LIBRARY(transport STATIC ${HEADERS} ${SRC} ${SWIFTEN_SRC})
endif(CMAKE_COMPILER_IS_GNUCXX)
SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/../include/transport/protocol.pb.cc PROPERTIES GENERATED 1)
# 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})
@ -35,9 +35,9 @@ if (CMAKE_COMPILER_IS_GNUCXX)
endif()
if (WIN32)
TARGET_LINK_LIBRARIES(transport ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES} ${LOG4CXX_LIBRARIES})
TARGET_LINK_LIBRARIES(transport transport-plugin ${PQXX_LIBRARY} ${PQ_LIBRARY} ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES} ${LOG4CXX_LIBRARIES})
else (WIN32)
TARGET_LINK_LIBRARIES(transport ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES} ${LOG4CXX_LIBRARIES} ${POPT_LIBRARY})
TARGET_LINK_LIBRARIES(transport transport-plugin ${PQXX_LIBRARY} ${PQ_LIBRARY} ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES} ${LOG4CXX_LIBRARIES} ${POPT_LIBRARY})
endif(WIN32)
SET_TARGET_PROPERTIES(transport PROPERTIES

View file

@ -19,6 +19,7 @@
*/
#include "transport/config.h"
#include "transport/util.h"
#include <fstream>
#ifdef _MSC_VER
#include <direct.h>
@ -86,8 +87,12 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description
("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(""), "Database used to store data")
("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.")
@ -106,6 +111,7 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description
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") {
@ -120,13 +126,7 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description
else if (opt.string_key == "service.backend_port") {
found_backend_port = true;
if (opt.value[0] == "0") {
unsigned long r = 0;
BOOST_FOREACH(char c, _jid) {
r += (int) c;
}
srand(time(NULL) + r);
int randomPort = 30000 + rand() % 10000;
opt.value[0] = boost::lexical_cast<std::string>(randomPort);
opt.value[0] = boost::lexical_cast<std::string>(Util::getRandomPort(_jid.empty() ? jid : _jid));
}
}
else if (opt.string_key == "service.working_dir") {
@ -135,6 +135,9 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description
else if (opt.string_key == "service.pidfile") {
found_pidfile = true;
}
else if (opt.string_key == "database.database") {
found_database = true;
}
}
if (!found_working) {
@ -148,16 +151,16 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description
parsed.options.push_back(boost::program_options::basic_option<char>("service.pidfile", value));
}
if (!found_backend_port) {
unsigned long r = 0;
BOOST_FOREACH(char c, _jid) {
r += (int) c;
}
srand(time(NULL) + r);
int randomPort = 30000 + rand() % 10000;
std::vector<std::string> value;
value.push_back(boost::lexical_cast<std::string>(randomPort));
std::string p = boost::lexical_cast<std::string>(Util::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) {

63
src/gatewayresponder.cpp Normal file
View file

@ -0,0 +1,63 @@
/**
* 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;
using namespace Swift;
using namespace boost;
namespace Transport {
static LoggerPtr logger = Logger::getLogger("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;
}
}

View file

@ -32,11 +32,11 @@ LocalBuddy::~LocalBuddy() {
}
void LocalBuddy::setAlias(const std::string &alias) {
if (m_firstSet) {
m_firstSet = false;
m_alias = alias;
return;
}
// if (m_firstSet) {
// m_firstSet = false;
// m_alias = alias;
// return;
// }
bool changed = m_alias != alias;
m_alias = alias;

View file

@ -470,7 +470,7 @@ long MySQLBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) {
long id = (long) mysql_insert_id(&m_conn);
// INSERT OR REPLACE INTO " + m_prefix + "buddies_settings (user_id, buddy_id, var, type, value) VALUES (?, ?, ?, ?, ?)
if (!buddyInfo.settings.find("icon_hash")->second.s.empty()) {
if (buddyInfo.settings.find("icon_hash") != buddyInfo.settings.end() && !buddyInfo.settings.find("icon_hash")->second.s.empty()) {
*m_updateBuddySetting << userId << id << buddyInfo.settings.find("icon_hash")->first << (int) TYPE_STRING << buddyInfo.settings.find("icon_hash")->second.s << buddyInfo.settings.find("icon_hash")->second.s;
EXEC(m_updateBuddySetting, addBuddy(userId, buddyInfo));
}
@ -597,6 +597,10 @@ void MySQLBackend::getUserSetting(long id, const std::string &variable, int &typ
else {
*m_getUserSetting >> type >> value;
}
while (m_getUserSetting->fetch() == 0) {
}
}
void MySQLBackend::updateUserSetting(long id, const std::string &variable, const std::string &value) {
@ -606,11 +610,11 @@ void MySQLBackend::updateUserSetting(long id, const std::string &variable, const
}
void MySQLBackend::beginTransaction() {
exec("START TRANSACTION;");
//exec("START TRANSACTION;");
}
void MySQLBackend::commitTransaction() {
exec("COMMIT;");
//exec("COMMIT;");
}
}

View file

@ -157,6 +157,7 @@ static unsigned long exec_(std::string path, const char *host, const char *port,
// fork and exec
pid_t pid = fork();
if ( pid == 0 ) {
setsid();
// child process
exit(execv(argv[0], argv));
} else if ( pid < 0 ) {
@ -174,7 +175,7 @@ static void SigCatcher(int n) {
int status;
// Read exit code from all children to not have zombies arround
// WARNING: Do not put LOG4CXX_ here, because it can lead to deadlock
while ((result = waitpid(0, &status, WNOHANG)) > 0) {
while ((result = waitpid(-1, &status, WNOHANG)) > 0) {
if (result != 0) {
if (WIFEXITED(status)) {
if (WEXITSTATUS(status) != 0) {
@ -194,6 +195,7 @@ static void handleBuddyPayload(LocalBuddy *buddy, const pbnetwork::Buddy &payloa
// Set alias only if it's not empty. Backends are allowed to send empty alias if it has
// not changed.
if (!payload.alias().empty()) {
LOG4CXX_INFO(logger, "Setting alias to " << payload.alias() << " " << buddy->getAlias());
buddy->setAlias(payload.alias());
}
@ -257,6 +259,7 @@ NetworkPluginServer::NetworkPluginServer(Component *component, Config *config, U
#endif
exec_(CONFIG_STRING(m_config, "service.backend"), CONFIG_STRING(m_config, "service.backend_host").c_str(), CONFIG_STRING(m_config, "service.backend_port").c_str(), m_config->getConfigFile().c_str());
LOG4CXX_INFO(logger, "Backend should now connect to Spectrum2 instance. Spectrum2 won't accept any connection before backend connects");
}
NetworkPluginServer::~NetworkPluginServer() {
@ -476,6 +479,8 @@ void NetworkPluginServer::handleBuddyChangedPayload(const std::string &data) {
if (!user)
return;
LOG4CXX_INFO(logger, "HANDLE BUDDY CHANGED " << payload.buddyname() << "-" << payload.alias());
LocalBuddy *buddy = (LocalBuddy *) user->getRosterManager()->getBuddy(payload.buddyname());
if (buddy) {
handleBuddyPayload(buddy, payload);

391
src/pqxxbackend.cpp Normal file
View file

@ -0,0 +1,391 @@
/**
* 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_PQXX
#include "transport/pqxxbackend.h"
#include "transport/util.h"
#include <boost/bind.hpp>
#include "log4cxx/logger.h"
using namespace log4cxx;
using namespace boost;
namespace Transport {
static LoggerPtr logger = Logger::getLogger("PQXXBackend");
PQXXBackend::PQXXBackend(Config *config) {
m_config = config;
m_prefix = CONFIG_STRING(m_config, "database.prefix");
}
PQXXBackend::~PQXXBackend(){
disconnect();
}
void PQXXBackend::disconnect() {
LOG4CXX_INFO(logger, "Disconnecting");
delete m_conn;
}
bool PQXXBackend::connect() {
LOG4CXX_INFO(logger, "Connecting PostgreSQL server " << CONFIG_STRING(m_config, "database.server") << ", user " <<
CONFIG_STRING(m_config, "database.user") << ", database " << CONFIG_STRING(m_config, "database.database") <<
", port " << CONFIG_INT(m_config, "database.port")
);
std::string str = "dbname=";
str += CONFIG_STRING(m_config, "database.database") + " ";
str += "user=" + CONFIG_STRING(m_config, "database.user") + " ";
try {
m_conn = new pqxx::connection(str);
}
catch (std::exception& e) {
LOG4CXX_ERROR(logger, e.what());
return false;
}
createDatabase();
return true;
}
bool PQXXBackend::createDatabase() {
int exist = exec("SELECT * FROM " + m_prefix + "buddies_settings LIMIT 1;", false);
if (!exist) {
exec("CREATE TABLE " + m_prefix + "buddies_settings ("
"user_id integer NOT NULL,"
"buddy_id integer NOT NULL,"
"var varchar(50) NOT NULL,"
"type smallint NOT NULL,"
"value varchar(255) NOT NULL,"
"PRIMARY KEY (buddy_id,var)"
");");
exec("CREATE TYPE Subscription AS ENUM ('to','from','both','ask','none');");
exec("CREATE TABLE " + m_prefix + "buddies ("
"id SERIAL,"
"user_id integer NOT NULL,"
"uin varchar(255) NOT NULL,"
"subscription Subscription NOT NULL,"
"nickname varchar(255) NOT NULL,"
"groups varchar(255) NOT NULL,"
"flags smallint NOT NULL DEFAULT '0',"
"PRIMARY KEY (id),"
"UNIQUE (user_id,uin)"
");");
exec("CREATE TABLE " + m_prefix + "users ("
"id SERIAL,"
"jid varchar(255) NOT NULL,"
"uin varchar(4095) NOT NULL,"
"password varchar(255) NOT NULL,"
"language varchar(25) NOT NULL,"
"encoding varchar(50) NOT NULL default 'utf8',"
"last_login timestamp,"
"vip boolean NOT NULL default 'false',"
"online boolean NOT NULL default 'false',"
"PRIMARY KEY (id),"
"UNIQUE (jid)"
");");
exec("CREATE TABLE " + m_prefix + "users_settings ("
"user_id integer NOT NULL,"
"var varchar(50) NOT NULL,"
"type smallint NOT NULL,"
"value varchar(255) NOT NULL,"
"PRIMARY KEY (user_id,var)"
");");
exec("CREATE TABLE " + m_prefix + "db_version ("
"ver integer NOT NULL default '1',"
"UNIQUE (ver)"
");");
exec("INSERT INTO db_version (ver) VALUES ('1');");
}
return true;
}
template<typename T>
std::string PQXXBackend::quote(pqxx::nontransaction &txn, const T &t) {
return "'" + txn.esc(pqxx::to_string(t)) + "'";
}
bool PQXXBackend::exec(const std::string &query, bool show_error) {
pqxx::nontransaction txn(*m_conn);
return exec(txn, query, show_error);
}
bool PQXXBackend::exec(pqxx::nontransaction &txn, const std::string &query, bool show_error) {
try {
txn.exec(query);
txn.commit();
}
catch (std::exception& e) {
if (show_error)
LOG4CXX_ERROR(logger, e.what());
return false;
}
return true;
}
void PQXXBackend::setUser(const UserInfo &user) {
std::string encrypted = user.password;
if (!CONFIG_STRING(m_config, "database.encryption_key").empty()) {
encrypted = Util::encryptPassword(encrypted, CONFIG_STRING(m_config, "database.encryption_key"));
}
try {
pqxx::nontransaction txn(*m_conn);
txn.exec("INSERT INTO " + m_prefix + "users (jid, uin, password, language, encoding, last_login, vip) VALUES "
+ "(" + quote(txn, user.jid) + ","
+ quote(txn, user.uin) + ","
+ quote(txn, encrypted) + ","
+ quote(txn, user.language) + ","
+ quote(txn, user.encoding) + ","
+ "NOW(),"
+ (user.vip ? "'true'" : "'false'") +")");
}
catch (std::exception& e) {
LOG4CXX_ERROR(logger, e.what());
}
}
bool PQXXBackend::getUser(const std::string &barejid, UserInfo &user) {
try {
pqxx::nontransaction txn(*m_conn);
pqxx::result r = txn.exec("SELECT id, jid, uin, password, encoding, language, vip FROM " + m_prefix + "users WHERE jid="
+ quote(txn, barejid));
if (r.size() == 0) {
return false;
}
user.id = r[0][0].as<int>();
user.jid = r[0][1].as<std::string>();
user.uin = r[0][2].as<std::string>();
user.password = r[0][3].as<std::string>();
user.encoding = r[0][4].as<std::string>();
user.language = r[0][5].as<std::string>();
user.vip = r[0][6].as<bool>();
}
catch (std::exception& e) {
LOG4CXX_ERROR(logger, e.what());
return false;
}
return true;
}
void PQXXBackend::setUserOnline(long id, bool online) {
try {
pqxx::nontransaction txn(*m_conn);
txn.exec("UPDATE " + m_prefix + "users SET online=" + (online ? "'true'" : "'false'") + ", last_login=NOW() WHERE id=" + pqxx::to_string(id));
}
catch (std::exception& e) {
LOG4CXX_ERROR(logger, e.what());
}
}
bool PQXXBackend::getOnlineUsers(std::vector<std::string> &users) {
try {
pqxx::nontransaction txn(*m_conn);
pqxx::result r = txn.exec("SELECT jid FROM " + m_prefix + "users WHERE online='true'");
for (pqxx::result::const_iterator it = r.begin(); it != r.end(); it++) {
users.push_back((*it)[0].as<std::string>());
}
}
catch (std::exception& e) {
LOG4CXX_ERROR(logger, e.what());
return false;
}
return true;
}
long PQXXBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) {
try {
pqxx::nontransaction txn(*m_conn);
pqxx::result r = txn.exec("INSERT INTO " + m_prefix + "buddies (user_id, uin, subscription, groups, nickname, flags) VALUES "
+ "(" + pqxx::to_string(userId) + ","
+ quote(txn, buddyInfo.legacyName) + ","
+ quote(txn, buddyInfo.subscription) + ","
+ quote(txn, Util::serializeGroups(buddyInfo.groups)) + ","
+ quote(txn, buddyInfo.alias) + ","
+ pqxx::to_string(buddyInfo.flags) + ") RETURNING id");
long id = r[0][0].as<long>();
r = txn.exec("UPDATE " + m_prefix + "buddies_settings SET var = " + quote(txn, buddyInfo.settings.find("icon_hash")->first) + ", type = " + pqxx::to_string((int)TYPE_STRING) + ", value = " + quote(txn, buddyInfo.settings.find("icon_hash")->second.s) + " WHERE user_id = " + pqxx::to_string(userId) + " AND buddy_id = " + pqxx::to_string(id));
if (r.affected_rows() == 0) {
txn.exec("INSERT INTO " + m_prefix + "buddies_settings (user_id, buddy_id, var, type, value) VALUES "
+ "(" + pqxx::to_string(userId) + ","
+ pqxx::to_string(id) + ","
+ quote(txn, buddyInfo.settings.find("icon_hash")->first) + ","
+ pqxx::to_string((int)TYPE_STRING) + ","
+ quote(txn, buddyInfo.settings.find("icon_hash")->second.s) + ")");
}
return id;
}
catch (std::exception& e) {
LOG4CXX_ERROR(logger, e.what());
return -1;
}
}
void PQXXBackend::updateBuddy(long userId, const BuddyInfo &buddyInfo) {
try {
pqxx::nontransaction txn(*m_conn);
txn.exec("UPDATE " + m_prefix + "buddies SET groups=" + quote(txn, Util::serializeGroups(buddyInfo.groups)) + ", nickname=" + quote(txn, buddyInfo.alias) + ", flags=" + pqxx::to_string(buddyInfo.flags) + ", subscription=" + quote(txn, buddyInfo.subscription) + " WHERE user_id=" + pqxx::to_string(userId) + " AND uin=" + quote(txn, buddyInfo.legacyName));
}
catch (std::exception& e) {
LOG4CXX_ERROR(logger, e.what());
}
}
bool PQXXBackend::getBuddies(long id, std::list<BuddyInfo> &roster) {
try {
pqxx::nontransaction txn(*m_conn);
pqxx::result r = txn.exec("SELECT id, uin, subscription, nickname, groups, flags FROM " + m_prefix + "buddies WHERE user_id=" + pqxx::to_string(id) + " ORDER BY id ASC");
for (pqxx::result::const_iterator it = r.begin(); it != r.end(); it++) {
BuddyInfo b;
std::string group;
b.id = r[0][0].as<long>();
b.legacyName = r[0][1].as<std::string>();
b.subscription = r[0][2].as<std::string>();
b.alias = r[0][3].as<std::string>();
group = r[0][4].as<std::string>();
b.flags = r[0][5].as<long>();
if (!group.empty()) {
b.groups = Util::deserializeGroups(group);
}
roster.push_back(b);
}
r = txn.exec("SELECT buddy_id, type, var, value FROM " + m_prefix + "buddies_settings WHERE user_id=" + pqxx::to_string(id) + " ORDER BY buddy_id ASC");
for (pqxx::result::const_iterator it = r.begin(); it != r.end(); it++) {
SettingVariableInfo var;
long buddy_id = -1;
std::string key;
std::string val;
buddy_id = r[0][0].as<long>();
var.type = r[0][1].as<long>();
key = r[0][2].as<std::string>();
val = r[0][3].as<std::string>();
switch (var.type) {
case TYPE_BOOLEAN:
var.b = atoi(val.c_str());
break;
case TYPE_STRING:
var.s = val;
break;
default:
continue;
break;
}
BOOST_FOREACH(BuddyInfo &b, roster) {
if (buddy_id == b.id) {
b.settings[key] = var;
break;
}
}
}
return true;
}
catch (std::exception& e) {
LOG4CXX_ERROR(logger, e.what());
}
return false;
}
bool PQXXBackend::removeUser(long id) {
try {
pqxx::nontransaction txn(*m_conn);
txn.exec("DELETE FROM " + m_prefix + "users SET id=" + pqxx::to_string(id));
txn.exec("DELETE FROM " + m_prefix + "buddies SET user_id=" + pqxx::to_string(id));
txn.exec("DELETE FROM " + m_prefix + "user_settings SET user_id=" + pqxx::to_string(id));
txn.exec("DELETE FROM " + m_prefix + "buddies_settings SET user_id=" + pqxx::to_string(id));
return true;
}
catch (std::exception& e) {
LOG4CXX_ERROR(logger, e.what());
}
return false;
}
void PQXXBackend::getUserSetting(long id, const std::string &variable, int &type, std::string &value) {
try {
pqxx::nontransaction txn(*m_conn);
pqxx::result r = txn.exec("SELECT type, value FROM " + m_prefix + "users_settings WHERE user_id=" + pqxx::to_string(id) + " AND var=" + quote(txn, variable));
if (r.size() == 0) {
txn.exec("INSERT INTO " + m_prefix + "users_settings (user_id, var, type, value) VALUES(" + pqxx::to_string(id) + "," + quote(txn, variable) + "," + pqxx::to_string((int)type) + "," + quote(txn, value) + ")");
}
else {
type = r[0][0].as<int>();
value = r[0][1].as<std::string>();
}
}
catch (std::exception& e) {
LOG4CXX_ERROR(logger, e.what());
}
}
void PQXXBackend::updateUserSetting(long id, const std::string &variable, const std::string &value) {
try {
pqxx::nontransaction txn(*m_conn);
txn.exec("UPDATE " + m_prefix + "users_settings SET value=" + quote(txn, value) + " WHERE user_id=" + pqxx::to_string(id) + " AND var=" + quote(txn, variable));
}
catch (std::exception& e) {
LOG4CXX_ERROR(logger, e.what());
}
}
void PQXXBackend::beginTransaction() {
exec("BEGIN;");
}
void PQXXBackend::commitTransaction() {
exec("COMMIT;");
}
}
#endif

136
src/presenceoracle.cpp Normal file
View file

@ -0,0 +1,136 @@
/**
* 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/presenceoracle.h"
#include "Swiften/Swiften.h"
#include <boost/bind.hpp>
using namespace Swift;
namespace Transport {
PresenceOracle::PresenceOracle(StanzaChannel* stanzaChannel) {
stanzaChannel_ = stanzaChannel;
stanzaChannel_->onPresenceReceived.connect(boost::bind(&PresenceOracle::handleIncomingPresence, this, _1));
stanzaChannel_->onAvailableChanged.connect(boost::bind(&PresenceOracle::handleStanzaChannelAvailableChanged, this, _1));
}
PresenceOracle::~PresenceOracle() {
stanzaChannel_->onPresenceReceived.disconnect(boost::bind(&PresenceOracle::handleIncomingPresence, this, _1));
stanzaChannel_->onAvailableChanged.disconnect(boost::bind(&PresenceOracle::handleStanzaChannelAvailableChanged, this, _1));
}
void PresenceOracle::handleStanzaChannelAvailableChanged(bool available) {
if (available) {
entries_.clear();
}
}
void PresenceOracle::handleIncomingPresence(Presence::ref presence) {
// ignore presences for some contact, we're checking only presences for the transport itself here.
bool isMUC = presence->getPayload<MUCPayload>() != NULL || *presence->getTo().getNode().c_str() == '#';
// filter out login/logout presence spam
if (!presence->getTo().getNode().empty() && isMUC == false)
return;
JID bareJID(presence->getFrom().toBare());
if (presence->getType() == Presence::Subscribe || presence->getType() == Presence::Subscribed) {
}
else {
Presence::ref passedPresence = presence;
if (presence->getType() == Presence::Unsubscribe || presence->getType() == Presence::Unsubscribed) {
/* 3921bis says that we don't follow up with an unavailable, so simulate this ourselves */
passedPresence = Presence::ref(new Presence());
passedPresence->setType(Presence::Unavailable);
passedPresence->setFrom(bareJID);
passedPresence->setStatus(presence->getStatus());
}
std::map<JID, boost::shared_ptr<Presence> > jidMap = entries_[bareJID];
if (passedPresence->getFrom().isBare() && presence->getType() == Presence::Unavailable) {
/* Have a bare-JID only presence of offline */
jidMap.clear();
} else if (passedPresence->getType() == Presence::Available) {
/* Don't have a bare-JID only offline presence once there are available presences */
jidMap.erase(bareJID);
}
if (passedPresence->getType() == Presence::Unavailable && jidMap.size() > 1) {
jidMap.erase(passedPresence->getFrom());
} else {
jidMap[passedPresence->getFrom()] = passedPresence;
}
entries_[bareJID] = jidMap;
onPresenceChange(passedPresence);
}
}
Presence::ref PresenceOracle::getLastPresence(const JID& jid) const {
PresencesMap::const_iterator i = entries_.find(jid.toBare());
if (i == entries_.end()) {
return Presence::ref();
}
PresenceMap presenceMap = i->second;
PresenceMap::const_iterator j = presenceMap.find(jid);
if (j != presenceMap.end()) {
return j->second;
}
else {
return Presence::ref();
}
}
std::vector<Presence::ref> PresenceOracle::getAllPresence(const JID& bareJID) const {
std::vector<Presence::ref> results;
PresencesMap::const_iterator i = entries_.find(bareJID);
if (i == entries_.end()) {
return results;
}
PresenceMap presenceMap = i->second;
PresenceMap::const_iterator j = presenceMap.begin();
for (; j != presenceMap.end(); ++j) {
Presence::ref current = j->second;
results.push_back(current);
}
return results;
}
Presence::ref PresenceOracle::getHighestPriorityPresence(const JID& bareJID) const {
PresencesMap::const_iterator i = entries_.find(bareJID);
if (i == entries_.end()) {
return Presence::ref();
}
PresenceMap presenceMap = i->second;
PresenceMap::const_iterator j = presenceMap.begin();
Presence::ref highest;
for (; j != presenceMap.end(); ++j) {
Presence::ref current = j->second;
if (!highest
|| current->getPriority() > highest->getPriority()
|| (current->getPriority() == highest->getPriority()
&& StatusShow::typeToAvailabilityOrdering(current->getShow()) > StatusShow::typeToAvailabilityOrdering(highest->getShow()))) {
highest = current;
}
}
return highest;
}
}

View file

@ -110,7 +110,12 @@ void RosterManager::sendBuddyRosterPush(Buddy *buddy) {
Swift::RosterPayload::ref payload = Swift::RosterPayload::ref(new Swift::RosterPayload());
Swift::RosterItemPayload item;
item.setJID(buddy->getJID().toBare());
item.setName(buddy->getAlias());
if (buddy->getAlias().empty()) {
item.setName(buddy->getJID().toBare().toString());
}
else {
item.setName(buddy->getAlias());
}
item.setGroups(buddy->getGroups());
item.setSubscription(Swift::RosterItemPayload::Both);
@ -285,8 +290,8 @@ void RosterManager::handleSubscription(Swift::Presence::ref presence) {
// using roster pushes.
if (m_component->inServerMode()) {
Swift::Presence::ref response = Swift::Presence::create();
response->setTo(presence->getFrom());
response->setFrom(presence->getTo());
response->setTo(presence->getFrom().toBare());
response->setFrom(presence->getTo().toBare());
Buddy *buddy = getBuddy(Buddy::JIDToLegacyName(presence->getTo()));
if (buddy) {
LOG4CXX_INFO(logger, m_user->getJID().toString() << ": Subscription received and buddy " << Buddy::JIDToLegacyName(presence->getTo()) << " is already there => answering");
@ -342,7 +347,7 @@ void RosterManager::handleSubscription(Swift::Presence::ref presence) {
Swift::Presence::ref response = Swift::Presence::create();
Swift::Presence::ref currentPresence;
response->setTo(presence->getFrom().toBare());
response->setFrom(presence->getTo().toBare().toString() + "/bot");
response->setFrom(presence->getTo().toBare());
Buddy *buddy = getBuddy(Buddy::JIDToLegacyName(presence->getTo()));
if (buddy) {

View file

@ -111,6 +111,8 @@ bool SQLite3Backend::connect() {
return false;
}
sqlite3_busy_timeout(m_db, 1500);
if (createDatabase() == false)
return false;
@ -234,6 +236,8 @@ bool SQLite3Backend::getUser(const std::string &barejid, UserInfo &user) {
user.encoding = (const char *) sqlite3_column_text(m_getUser, 4);
user.language = (const char *) sqlite3_column_text(m_getUser, 5);
user.vip = sqlite3_column_int(m_getUser, 6) != 0;
while((ret = sqlite3_step(m_getUser)) == SQLITE_ROW) {
}
return true;
}
@ -388,6 +392,9 @@ bool SQLite3Backend::getBuddies(long id, std::list<BuddyInfo> &roster) {
roster.push_back(b);
}
while((ret = sqlite3_step(m_getBuddiesSettings)) == SQLITE_ROW) {
}
if (ret != SQLITE_DONE) {
LOG4CXX_ERROR(logger, "getBuddies query"<< (sqlite3_errmsg(m_db) == NULL ? "" : sqlite3_errmsg(m_db)));
return false;
@ -444,6 +451,10 @@ void SQLite3Backend::getUserSetting(long id, const std::string &variable, int &t
type = GET_INT(m_getUserSetting);
value = GET_STR(m_getUserSetting);
}
int ret;
while((ret = sqlite3_step(m_getUserSetting)) == SQLITE_ROW) {
}
}
void SQLite3Backend::updateUserSetting(long id, const std::string &variable, const std::string &value) {

View file

@ -71,11 +71,19 @@ bool StorageResponder::handleSetRequest(const Swift::JID& from, const Swift::JID
return true;
}
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>());
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;
}

View file

@ -36,6 +36,8 @@
#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"
@ -45,6 +47,7 @@
#include "log4cxx/consoleappender.h"
#include "log4cxx/patternlayout.h"
#include "log4cxx/propertyconfigurator.h"
#include "Swiften/Swiften.h"
using namespace Swift;
using namespace boost;
@ -94,6 +97,7 @@ Component::Component(Swift::EventLoop *loop, Swift::NetworkFactories *factories,
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());
@ -101,6 +105,7 @@ Component::Component(Swift::EventLoop *loop, Swift::NetworkFactories *factories,
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));
@ -120,6 +125,7 @@ Component::Component(Swift::EventLoop *loop, Swift::NetworkFactories *factories,
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());
@ -127,6 +133,7 @@ Component::Component(Swift::EventLoop *loop, Swift::NetworkFactories *factories,
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();
@ -137,7 +144,7 @@ Component::Component(Swift::EventLoop *loop, Swift::NetworkFactories *factories,
m_entityCapsManager = new EntityCapsManager(m_capsManager, m_stanzaChannel);
m_entityCapsManager->onCapsChanged.connect(boost::bind(&Component::handleCapsChanged, this, _1));
m_presenceOracle = new PresenceOracle(m_stanzaChannel);
m_presenceOracle = new Transport::PresenceOracle(m_stanzaChannel);
m_presenceOracle->onPresenceChange.connect(bind(&Component::handlePresence, this, _1));
m_discoInfoResponder = new DiscoInfoResponder(m_iqRouter, m_config);
@ -170,7 +177,7 @@ Swift::StanzaChannel *Component::getStanzaChannel() {
return m_stanzaChannel;
}
Swift::PresenceOracle *Component::getPresenceOracle() {
Transport::PresenceOracle *Component::getPresenceOracle() {
return m_presenceOracle;
}

View file

@ -24,6 +24,7 @@
#include "transport/rostermanager.h"
#include "transport/usermanager.h"
#include "transport/conversationmanager.h"
#include "transport/presenceoracle.h"
#include "Swiften/Swiften.h"
#include "Swiften/Server/ServerStanzaChannel.h"
#include "Swiften/Elements/StreamError.h"
@ -212,8 +213,8 @@ void User::handlePresence(Swift::Presence::ref presence) {
bool isMUC = presence->getPayload<Swift::MUCPayload>() != NULL || *presence->getTo().getNode().c_str() == '#';
if (isMUC) {
if (presence->getType() == Swift::Presence::Unavailable) {
LOG4CXX_INFO(logger, m_jid.toString() << ": Going to left room " << presence->getTo().getNode());
std::string room = Buddy::JIDToLegacyName(presence->getTo());
LOG4CXX_INFO(logger, m_jid.toString() << ": Going to left room " << room);
onRoomLeft(room);
}
else {
@ -223,8 +224,8 @@ void User::handlePresence(Swift::Presence::ref presence) {
m_readyForConnect = true;
onReadyToConnect();
}
LOG4CXX_INFO(logger, m_jid.toString() << ": Going to join room " << presence->getTo().getNode() << " as " << presence->getTo().getResource());
std::string room = Buddy::JIDToLegacyName(presence->getTo());
LOG4CXX_INFO(logger, m_jid.toString() << ": Going to join room " << room << " as " << presence->getTo().getResource());
std::string password = "";
if (presence->getPayload<Swift::MUCPayload>() != NULL) {
password = presence->getPayload<Swift::MUCPayload>()->getPassword() ? *presence->getPayload<Swift::MUCPayload>()->getPassword() : "";

View file

@ -306,8 +306,8 @@ 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());
response->setTo(presence->getFrom());
response->setFrom(presence->getTo().toBare());
response->setTo(presence->getFrom().toBare());
response->setType(Swift::Presence::Subscribed);
m_component->getStanzaChannel()->sendPresence(response);

View file

@ -26,6 +26,8 @@
#include "transport/user.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;
@ -241,6 +243,20 @@ bool UserRegistration::handleGetRequest(const Swift::JID& from, const Swift::JID
boolean->setLabel((("Remove your registration")));
boolean->setValue(0);
form->addField(boolean);
} else {
if (CONFIG_BOOL(m_config,"registration.require_local_account")) {
std::string localUsernameField = CONFIG_STRING(m_config, "registration.local_username_label");
TextSingleFormField::ref local_username = TextSingleFormField::create();
local_username->setName("local_username");
local_username->setLabel((localUsernameField));
local_username->setRequired(true);
form->addField(local_username);
TextPrivateFormField::ref local_password = TextPrivateFormField::create();
local_password->setName("local_password");
local_password->setLabel((("Local Password")));
local_password->setRequired(true);
form->addField(local_password);
}
}
reg->setForm(form);
@ -273,6 +289,8 @@ bool UserRegistration::handleSetRequest(const Swift::JID& from, const Swift::JID
std::string encoding;
std::string language;
std::string local_username("");
std::string local_password("");
Form::ref form = payload->getForm();
if (form) {
@ -286,6 +304,17 @@ bool UserRegistration::handleSetRequest(const Swift::JID& from, const Swift::JID
else if (textSingle->getName() == "encoding") {
encoding = textSingle->getValue();
}
// Pidgin sends it as textSingle, not sure why...
else if (textSingle->getName() == "password") {
payload->setPassword(textSingle->getValue());
}
else if (textSingle->getName() == "local_username") {
local_username = textSingle->getValue();
}
// Pidgin sends it as textSingle, not sure why...
else if (textSingle->getName() == "local_password") {
local_password = textSingle->getValue();
}
continue;
}
@ -294,6 +323,9 @@ bool UserRegistration::handleSetRequest(const Swift::JID& from, const Swift::JID
if (textPrivate->getName() == "password") {
payload->setPassword(textPrivate->getValue());
}
else if (textPrivate->getName() == "local_password") {
local_password = textPrivate->getValue();
}
continue;
}
@ -323,6 +355,50 @@ bool UserRegistration::handleSetRequest(const Swift::JID& from, const Swift::JID
return true;
}
if (CONFIG_BOOL(m_config,"registration.require_local_account")) {
/* if (!local_username || !local_password) {
sendResponse(from, id, InBandRegistrationPayload::ref());
return true
} else */ if (local_username == "" || local_password == "") {
sendResponse(from, id, InBandRegistrationPayload::ref());
return true;
}
// Swift::logging = true;
bool validLocal = false;
std::string localLookupServer = CONFIG_STRING(m_config, "registration.local_account_server");
std::string localLookupJID = local_username + std::string("@") + localLookupServer;
SimpleEventLoop localLookupEventLoop;
BoostNetworkFactories localLookupNetworkFactories(&localLookupEventLoop);
Client localLookupClient(localLookupJID, local_password, &localLookupNetworkFactories);
// TODO: this is neccessary on my server ... but should maybe omitted
localLookupClient.setAlwaysTrustCertificates();
localLookupClient.connect();
class SimpleLoopRunner {
public:
SimpleLoopRunner() {};
static void run(SimpleEventLoop * loop) {
loop->run();
};
};
// TODO: Really ugly and hacky solution, any other ideas more than welcome!
boost::thread thread(boost::bind(&(SimpleLoopRunner::run), &localLookupEventLoop));
thread.timed_join(boost::posix_time::millisec(CONFIG_INT(m_config, "registration.local_account_server_timeout")));
localLookupEventLoop.stop();
thread.join();
validLocal = localLookupClient.isAvailable();
localLookupClient.disconnect();
if (!validLocal) {
sendError(from, id, ErrorPayload::NotAuthorized, ErrorPayload::Modify);
return true;
}
}
printf("here\n");
if (!payload->getUsername() || !payload->getPassword()) {
sendError(from, id, ErrorPayload::NotAcceptable, ErrorPayload::Modify);
return true;

View file

@ -128,6 +128,15 @@ std::vector<std::string> deserializeGroups(std::string &groups) {
return ret;
}
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;
}
}
}