merge latest changes

This commit is contained in:
Vitaly Takmazov 2011-10-27 10:22:36 +04:00
commit bfb1488c95
32 changed files with 980 additions and 613 deletions

View file

@ -54,7 +54,7 @@ find_package(event)
find_package(Doxygen)
INCLUDE(FindQt4)
FIND_PACKAGE(Qt4 COMPONENTS QtCore)
FIND_PACKAGE(Qt4 COMPONENTS QtCore QtNetwork REQUIRED)
# ADD_DEFINITIONS(${SWIFTEN_CFLAGS})
ADD_DEFINITIONS(-DSUPPORT_LEGACY_CAPS)
@ -104,6 +104,7 @@ if (PROTOBUF_FOUND)
if(IRC_FOUND)
ADD_DEFINITIONS(-DIRC_SHARED)
message("IRC plugin : yes")
include_directories(${QT_QTNETWORK_INCLUDE_DIR})
include_directories(${IRC_INCLUDE_DIR})
include(${QT_USE_FILE})
else()

View file

@ -0,0 +1,126 @@
#include "ircnetworkplugin.h"
IRCNetworkPlugin::IRCNetworkPlugin(Config *config, Swift::QtEventLoop *loop, const std::string &host, int port) {
this->config = config;
m_socket = new QTcpSocket();
m_socket->connectToHost(QString::fromStdString(host), port);
connect(m_socket, SIGNAL(readyRead()), this, SLOT(readData()));
}
void IRCNetworkPlugin::readData() {
size_t availableBytes = m_socket->bytesAvailable();
if (availableBytes == 0)
return;
std::cout << "READ\n";
std::string d = std::string(m_socket->readAll().data(), availableBytes);
handleDataRead(d);
}
void IRCNetworkPlugin::sendData(const std::string &string) {
m_socket->write(string.c_str(), string.size());
}
void IRCNetworkPlugin::handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) {
// Server is in server-mode, so user is JID of server when we want to connect
if (CONFIG_BOOL(config, "service.server_mode")) {
MyIrcSession *session = new MyIrcSession(user, this);
std::string h = user.substr(0, user.find("@"));
session->setNick(QString::fromStdString(h.substr(0, h.find("%"))));
session->connectToServer(QString::fromStdString(h.substr(h.find("%") + 1)), 6667);
std::cout << "CONNECTING IRC NETWORK " << h.substr(h.find("%") + 1) << "\n";
m_sessions[user] = session;
}
else {
handleConnected(user);
}
}
void IRCNetworkPlugin::handleLogoutRequest(const std::string &user, const std::string &legacyName) {
if (m_sessions[user] == NULL)
return;
m_sessions[user]->disconnectFromServer();
m_sessions[user]->deleteLater();
m_sessions.erase(user);
}
void IRCNetworkPlugin::handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &/*xhtml*/) {
std::string u = user;
std::cout << "AAAAA " << legacyName << "\n";
if (!CONFIG_BOOL(config, "service.server_mode")) {
u = user + legacyName.substr(legacyName.find("@") + 1);
if (u.find("/") != std::string::npos) {
u = u.substr(0, u.find("/"));
}
}
if (m_sessions[u] == NULL) {
std::cout << "No session for " << u << "\n";
return;
}
std::string r = legacyName;
if (!CONFIG_BOOL(config, "service.server_mode")) {
if (legacyName.find("/") == std::string::npos) {
r = legacyName.substr(0, r.find("@"));
}
else {
r = legacyName.substr(legacyName.find("/") + 1);
}
}
std::cout << "MESSAGE " << u << " " << r << "\n";
m_sessions[u]->message(QString::fromStdString(r), QString::fromStdString(message));
std::cout << "SENT\n";
}
void IRCNetworkPlugin::handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &password) {
std::cout << "JOIN\n";
std::string r = room;
std::string u = user;
if (!CONFIG_BOOL(config, "service.server_mode")) {
u = user + room.substr(room.find("@") + 1);
r = room.substr(0, room.find("@"));
}
if (m_sessions[u] == NULL) {
// in gateway mode we want to login this user to network according to legacyName
if (room.find("@") != std::string::npos) {
// suffix is %irc.freenode.net to let MyIrcSession return #room%irc.freenode.net
MyIrcSession *session = new MyIrcSession(user, this, room.substr(room.find("@")));
session->setNick(QString::fromStdString(nickname));
session->connectToServer(QString::fromStdString(room.substr(room.find("@") + 1)), 6667);
std::cout << "CONNECTING IRC NETWORK " << room.substr(room.find("@") + 1) << "\n";
std::cout << "SUFFIX " << room.substr(room.find("@")) << "\n";
m_sessions[u] = session;
}
else {
return;
}
}
std::cout << "JOINING " << r << "\n";
m_sessions[u]->addAutoJoinChannel(QString::fromStdString(r));
m_sessions[u]->join(QString::fromStdString(r), QString::fromStdString(password));
m_sessions[u]->rooms += 1;
// update nickname, because we have nickname per session, no nickname per room.
handleRoomNicknameChanged(user, r, m_sessions[u]->nick().toStdString());
}
void IRCNetworkPlugin::handleLeaveRoomRequest(const std::string &user, const std::string &room) {
std::string r = room;
std::string u = user;
if (!CONFIG_BOOL(config, "service.server_mode")) {
r = room.substr(0, room.find("@"));
u = user + room.substr(room.find("@") + 1);
}
if (m_sessions[u] == NULL)
return;
m_sessions[u]->part(QString::fromStdString(r));
m_sessions[u]->removeAutoJoinChannel(QString::fromStdString(r));
m_sessions[u]->rooms -= 1;
if (m_sessions[u]->rooms <= 0) {
m_sessions[u]->disconnectFromServer();
m_sessions[u]->deleteLater();
m_sessions.erase(u);
}
}

View file

@ -0,0 +1,38 @@
#pragma once
#include "transport/config.h"
#include "transport/networkplugin.h"
#include "session.h"
#include <QtCore>
#include <QtNetwork>
#include "Swiften/EventLoop/Qt/QtEventLoop.h"
#include "ircnetworkplugin.h"
class IRCNetworkPlugin : public QObject, public NetworkPlugin {
Q_OBJECT
public:
IRCNetworkPlugin(Config *config, Swift::QtEventLoop *loop, const std::string &host, int port);
void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password);
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*/);
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);
std::map<std::string, MyIrcSession *> m_sessions;
public slots:
void readData();
void sendData(const std::string &string);
private:
Config *config;
QTcpSocket *m_socket;
};

View file

@ -12,67 +12,15 @@
#include "transport/networkplugin.h"
#include "session.h"
#include <QtCore>
#include <QtNetwork>
#include "Swiften/EventLoop/Qt/QtEventLoop.h"
#include "ircnetworkplugin.h"
using namespace boost::program_options;
using namespace Transport;
class IRCNetworkPlugin;
IRCNetworkPlugin * np = NULL;
class IRCNetworkPlugin : public NetworkPlugin {
public:
IRCNetworkPlugin(Config *config, Swift::QtEventLoop *loop, const std::string &host, int port) : NetworkPlugin() {
this->config = config;
}
void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) {
MyIrcSession *session = new MyIrcSession(user, this);
session->setNick(QString::fromStdString(user.substr(0, user.find("@"))));
session->connectToServer(QString::fromStdString(user.substr(user.find("@") + 1)), 6667);
// std::cout << "CONNECTING IRC NETWORK " << jid.getNode() << " " << jid.getDomain() << "\n";
m_sessions[user] = session;
}
void handleLogoutRequest(const std::string &user, const std::string &legacyName) {
if (m_sessions[user] == NULL)
return;
m_sessions[user]->disconnectFromServer();
m_sessions[user]->deleteLater();
}
void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &/*xhtml*/) {
std::cout << "MESSAGE " << user << " " << legacyName << "\n";
if (m_sessions[user] == NULL)
return;
m_sessions[user]->message(QString::fromStdString(legacyName), QString::fromStdString(message));
std::cout << "SENT\n";
}
void handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &password) {
std::cout << "JOIN\n";
if (m_sessions[user] == NULL)
return;
m_sessions[user]->addAutoJoinChannel(QString::fromStdString(room));
m_sessions[user]->join(QString::fromStdString(room), QString::fromStdString(password));
// update nickname, because we have nickname per session, no nickname per room.
handleRoomNicknameChanged(user, room, m_sessions[user]->nick().toStdString());
}
void handleLeaveRoomRequest(const std::string &user, const std::string &room) {
std::cout << "PART\n";
if (m_sessions[user] == NULL)
return;
m_sessions[user]->part(QString::fromStdString(room));
m_sessions[user]->removeAutoJoinChannel(QString::fromStdString(room));
}
std::map<std::string, MyIrcSession *> m_sessions;
private:
Config *config;
};
int main (int argc, char* argv[]) {
std::string host;
int port;

View file

@ -13,10 +13,12 @@
#include <iostream>
#include "Swiften/Elements/StatusShow.h"
MyIrcSession::MyIrcSession(const std::string &user, NetworkPlugin *np, QObject* parent) : Irc::Session(parent)
MyIrcSession::MyIrcSession(const std::string &user, NetworkPlugin *np, const std::string &suffix, QObject* parent) : Irc::Session(parent)
{
this->np = np;
this->user = user;
this->suffix = suffix;
rooms = 0;
connect(this, SIGNAL(disconnected()), SLOT(on_disconnected()));
}
@ -26,8 +28,9 @@ void MyIrcSession::on_connected(){
void MyIrcSession::on_disconnected()
{
std::cout << "disconnected:\n";
np->handleDisconnected(user, 0, "");
std::cout << "disconnected:\n";
if (suffix.empty())
np->handleDisconnected(user, 0, "");
}
void MyIrcSession::on_bufferAdded(Irc::Buffer* buffer)
@ -42,14 +45,15 @@ void MyIrcSession::on_bufferRemoved(Irc::Buffer* buffer)
Irc::Buffer* MyIrcSession::createBuffer(const QString& receiver)
{
return new MyIrcBuffer(receiver, user, np, this);
return new MyIrcBuffer(receiver, user, np, suffix, this);
}
MyIrcBuffer::MyIrcBuffer(const QString& receiver, const std::string &user, NetworkPlugin *np, Irc::Session* parent)
MyIrcBuffer::MyIrcBuffer(const QString& receiver, const std::string &user, NetworkPlugin *np, const std::string &suffix, Irc::Session* parent)
: Irc::Buffer(receiver, parent)
{
this->np = np;
this->user = user;
this->suffix = suffix;
p = (MyIrcSession *) parent;
connect(this, SIGNAL(receiverChanged(QString)), SLOT(on_receiverChanged(QString)));
connect(this, SIGNAL(joined(QString)), SLOT(on_joined(QString)));
@ -94,7 +98,7 @@ void MyIrcBuffer::on_joined(const QString& origin) {
bool flags = 0;
std::string nickname = origin.toStdString();
flags = correctNickname(nickname);
np->handleParticipantChanged(user, origin.toStdString(), receiver().toStdString(), (int) flags, pbnetwork::STATUS_ONLINE);
np->handleParticipantChanged(user, origin.toStdString(), receiver().toStdString() + suffix, (int) flags, pbnetwork::STATUS_ONLINE);
}
void MyIrcBuffer::on_parted(const QString& origin, const QString& message) {
@ -102,7 +106,7 @@ void MyIrcBuffer::on_parted(const QString& origin, const QString& message) {
bool flags = 0;
std::string nickname = origin.toStdString();
flags = correctNickname(nickname);
np->handleParticipantChanged(user, nickname, receiver().toStdString(),(int) flags, pbnetwork::STATUS_NONE, message.toStdString());
np->handleParticipantChanged(user, nickname, receiver().toStdString() + suffix,(int) flags, pbnetwork::STATUS_NONE, message.toStdString());
}
void MyIrcBuffer::on_quit(const QString& origin, const QString& message)
@ -116,7 +120,7 @@ void MyIrcBuffer::on_nickChanged(const QString& origin, const QString& nick) {
std::string nickname = origin.toStdString();
bool flags = p->m_modes[receiver().toStdString() + nickname];
// std::cout << receiver().toStdString() + nickname << " " << flags << "\n";
np->handleParticipantChanged(user, nickname, receiver().toStdString(),(int) flags, pbnetwork::STATUS_ONLINE, "", nick.toStdString());
np->handleParticipantChanged(user, nickname, receiver().toStdString() + suffix,(int) flags, pbnetwork::STATUS_ONLINE, "", nick.toStdString());
}
void MyIrcBuffer::on_modeChanged(const QString& origin, const QString& mode, const QString& args) {
@ -132,13 +136,13 @@ void MyIrcBuffer::on_modeChanged(const QString& origin, const QString& mode, con
p->m_modes[receiver().toStdString() + nickname] = 0;
}
bool flags = p->m_modes[receiver().toStdString() + nickname];
np->handleParticipantChanged(user, nickname, receiver().toStdString(),(int) flags, pbnetwork::STATUS_ONLINE, "");
np->handleParticipantChanged(user, nickname, receiver().toStdString() + suffix,(int) flags, pbnetwork::STATUS_ONLINE, "");
}
void MyIrcBuffer::on_topicChanged(const QString& origin, const QString& topic) {
//topic changed: "#testik" "HanzZ" "test"
qDebug() << "topic changed:" << receiver() << origin << topic;
np->handleSubject(user, receiver().toStdString(), topic.toStdString(), origin.toStdString());
np->handleSubject(user, receiver().toStdString() + suffix, topic.toStdString(), origin.toStdString());
}
void MyIrcBuffer::on_invited(const QString& origin, const QString& receiver, const QString& channel)
@ -155,7 +159,17 @@ void MyIrcBuffer::on_messageReceived(const QString& origin, const QString& messa
qDebug() << "message received:" << receiver() << origin << message << (flags & Irc::Buffer::IdentifiedFlag ? "(identified!)" : "(not identified)");
if (!receiver().startsWith("#") && (flags & Irc::Buffer::EchoFlag))
return;
np->handleMessage(user, receiver().toStdString(), message.toStdString(), origin.toStdString());
std::string r = receiver().toStdString();
// if (!suffix.empty()) {
// r = receiver().replace('@', '%').toStdString();
// }
if (r.find("#") == 0) {
np->handleMessage(user, r + suffix, message.toStdString(), origin.toStdString());
}
else {
np->handleMessage(user, r + suffix, message.toStdString());
}
}
void MyIrcBuffer::on_noticeReceived(const QString& origin, const QString& notice, Irc::Buffer::MessageFlags flags)
@ -186,13 +200,14 @@ void MyIrcBuffer::on_numericMessageReceived(const QString& origin, uint code, co
{
switch (code) {
case 251:
np->handleConnected(user);
if (suffix.empty())
np->handleConnected(user);
break;
case 332:
m_topicData = params.value(2).toStdString();
break;
case 333:
np->handleSubject(user, params.value(1).toStdString(), m_topicData, params.value(2).toStdString());
np->handleSubject(user, params.value(1).toStdString() + suffix, m_topicData, params.value(2).toStdString());
break;
case 353:
QString channel = params.value(2);
@ -203,12 +218,12 @@ void MyIrcBuffer::on_numericMessageReceived(const QString& origin, uint code, co
std::string nickname = members.at(i).toStdString();
flags = correctNickname(nickname);
p->m_modes[channel.toStdString() + nickname] = flags;
// std::cout << channel.toStdString() + nickname << " " << flags << "\n";
np->handleParticipantChanged(user, nickname, channel.toStdString(),(int) flags, pbnetwork::STATUS_ONLINE);
std::cout << channel.toStdString() + suffix << " " << flags << "\n";
np->handleParticipantChanged(user, nickname, channel.toStdString() + suffix,(int) flags, pbnetwork::STATUS_ONLINE);
}
break;
}
qDebug() << "numeric message received:" << receiver() << origin << code << params;
qDebug() << "numeric message received:" << receiver() << origin << code << params;
}
void MyIrcBuffer::on_unknownMessageReceived(const QString& origin, const QStringList& params)

View file

@ -22,8 +22,10 @@ class MyIrcSession : public Irc::Session
Q_OBJECT
public:
MyIrcSession(const std::string &user, NetworkPlugin *np, QObject* parent = 0);
MyIrcSession(const std::string &user, NetworkPlugin *np, const std::string &suffix = "", QObject* parent = 0);
std::map<std::string, bool> m_modes;
std::string suffix;
int rooms;
protected Q_SLOTS:
void on_connected();
@ -35,6 +37,7 @@ protected Q_SLOTS:
protected:
NetworkPlugin *np;
std::string user;
virtual Irc::Buffer* createBuffer(const QString& receiver);
};
@ -43,11 +46,12 @@ class MyIrcBuffer : public Irc::Buffer
Q_OBJECT
public:
MyIrcBuffer(const QString& receiver, const std::string &user, NetworkPlugin *np, Irc::Session* parent);
MyIrcBuffer(const QString& receiver, const std::string &user, NetworkPlugin *np, const std::string &suffix, Irc::Session* parent);
NetworkPlugin *np;
std::string user;
MyIrcSession *p;
std::string m_topicData;
std::string suffix;
protected Q_SLOTS:
void on_receiverChanged(const QString& receiver);

View file

@ -45,6 +45,7 @@ using namespace log4cxx;
static LoggerPtr logger_libpurple = log4cxx::Logger::getLogger("libpurple");
static LoggerPtr logger = log4cxx::Logger::getLogger("backend");
int m_sock;
static int writeInput;
using namespace Transport;
@ -61,6 +62,8 @@ template <class T> std::string stringOf(T object) {
return (os.str());
}
static void transportDataReceived(gpointer data, gint source, PurpleInputCondition cond);
class SpectrumNetworkPlugin;
GKeyFile *keyfile;
@ -73,6 +76,13 @@ static std::string KEYFILE_STRING(const std::string &cat, const std::string &key
}
std::string ret(str);
free(str);
if (ret.find("#") != std::string::npos) {
ret = ret.substr(0, ret.find("#"));
while(*(ret.end() - 1) == ' ') {
ret.erase(ret.end() - 1);
}
}
return ret;
}
@ -907,6 +917,8 @@ class SpectrumNetworkPlugin : public NetworkPlugin {
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 readyForData() {
@ -1750,6 +1762,10 @@ static void transportDataReceived(gpointer data, gint source, PurpleInputConditi
np->handleDataRead(d);
}
else {
if (writeInput != 0) {
purple_input_remove(writeInput);
writeInput = 0;
}
np->readyForData();
}
}
@ -1852,7 +1868,6 @@ int main(int argc, char **argv) {
m_sock = create_socket(host, port);
purple_input_add(m_sock, PURPLE_INPUT_READ, &transportDataReceived, NULL);
// purple_input_add(m_sock, PURPLE_INPUT_WRITE, &transportDataReceived, NULL);
np = new SpectrumNetworkPlugin(host, port);
bool libev = KEYFILE_STRING("service", "eventloop") == "libev";

View file

@ -1,260 +0,0 @@
# FIND_PACKAGE_HANDLE_STANDARD_ARGS(<name> ... )
#
# This function is intended to be used in FindXXX.cmake modules files.
# It handles the REQUIRED, QUIET and version-related arguments to FIND_PACKAGE().
# It also sets the <UPPERCASED_NAME>_FOUND variable.
# The package is considered found if all variables <var1>... listed contain
# valid results, e.g. valid filepaths.
#
# There are two modes of this function. The first argument in both modes is
# the name of the Find-module where it is called (in original casing).
#
# The first simple mode looks like this:
# FIND_PACKAGE_HANDLE_STANDARD_ARGS(<name> (DEFAULT_MSG|"Custom failure message") <var1>...<varN> )
# If the variables <var1> to <varN> are all valid, then <UPPERCASED_NAME>_FOUND
# will be set to TRUE.
# If DEFAULT_MSG is given as second argument, then the function will generate
# itself useful success and error messages. You can also supply a custom error message
# for the failure case. This is not recommended.
#
# The second mode is more powerful and also supports version checking:
# FIND_PACKAGE_HANDLE_STANDARD_ARGS(NAME [REQUIRED_VARS <var1>...<varN>]
# [VERSION_VAR <versionvar>
# [CONFIG_MODE]
# [FAIL_MESSAGE "Custom failure message"] )
#
# As above, if <var1> through <varN> are all valid, <UPPERCASED_NAME>_FOUND
# will be set to TRUE.
# After REQUIRED_VARS the variables which are required for this package are listed.
# Following VERSION_VAR the name of the variable can be specified which holds
# the version of the package which has been found. If this is done, this version
# will be checked against the (potentially) specified required version used
# in the find_package() call. The EXACT keyword is also handled. The default
# messages include information about the required version and the version
# which has been actually found, both if the version is ok or not.
# Use the option CONFIG_MODE if your FindXXX.cmake module is a wrapper for
# a find_package(... NO_MODULE) call, in this case all the information
# provided by the config-mode of find_package() will be evaluated
# automatically.
# Via FAIL_MESSAGE a custom failure message can be specified, if this is not
# used, the default message will be displayed.
#
# Example for mode 1:
#
# FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibXml2 DEFAULT_MSG LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR)
#
# LibXml2 is considered to be found, if both LIBXML2_LIBRARY and
# LIBXML2_INCLUDE_DIR are valid. Then also LIBXML2_FOUND is set to TRUE.
# If it is not found and REQUIRED was used, it fails with FATAL_ERROR,
# independent whether QUIET was used or not.
# If it is found, success will be reported, including the content of <var1>.
# On repeated Cmake runs, the same message won't be printed again.
#
# Example for mode 2:
#
# FIND_PACKAGE_HANDLE_STANDARD_ARGS(BISON REQUIRED_VARS BISON_EXECUTABLE
# VERSION_VAR BISON_VERSION)
# In this case, BISON is considered to be found if the variable(s) listed
# after REQUIRED_VAR are all valid, i.e. BISON_EXECUTABLE in this case.
# Also the version of BISON will be checked by using the version contained
# in BISON_VERSION.
# Since no FAIL_MESSAGE is given, the default messages will be printed.
#
# Another example for mode 2:
#
# FIND_PACKAGE(Automoc4 QUIET NO_MODULE HINTS /opt/automoc4)
# FIND_PACKAGE_HANDLE_STANDARD_ARGS(Automoc4 CONFIG_MODE)
# In this case, FindAutmoc4.cmake wraps a call to FIND_PACKAGE(Automoc4 NO_MODULE)
# and adds an additional search directory for automoc4.
# The following FIND_PACKAGE_HANDLE_STANDARD_ARGS() call produces a proper
# success/error message.
#=============================================================================
# Copyright 2007-2009 Kitware, Inc.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
INCLUDE(FindPackageMessage)
INCLUDE(CMakeParseArguments)
# internal helper macro
MACRO(_FPHSA_FAILURE_MESSAGE _msg)
IF (${_NAME}_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "${_msg}")
ELSE (${_NAME}_FIND_REQUIRED)
IF (NOT ${_NAME}_FIND_QUIETLY)
MESSAGE(STATUS "${_msg}")
ENDIF (NOT ${_NAME}_FIND_QUIETLY)
ENDIF (${_NAME}_FIND_REQUIRED)
ENDMACRO(_FPHSA_FAILURE_MESSAGE _msg)
# internal helper macro to generate the failure message when used in CONFIG_MODE:
MACRO(_FPHSA_HANDLE_FAILURE_CONFIG_MODE)
# <name>_CONFIG is set, but FOUND is false, this means that some other of the REQUIRED_VARS was not found:
IF(${_NAME}_CONFIG)
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: missing: ${MISSING_VARS} (found ${${_NAME}_CONFIG} ${VERSION_MSG})")
ELSE(${_NAME}_CONFIG)
# If _CONSIDERED_CONFIGS is set, the config-file has been found, but no suitable version.
# List them all in the error message:
IF(${_NAME}_CONSIDERED_CONFIGS)
SET(configsText "")
LIST(LENGTH ${_NAME}_CONSIDERED_CONFIGS configsCount)
MATH(EXPR configsCount "${configsCount} - 1")
FOREACH(currentConfigIndex RANGE ${configsCount})
LIST(GET ${_NAME}_CONSIDERED_CONFIGS ${currentConfigIndex} filename)
LIST(GET ${_NAME}_CONSIDERED_VERSIONS ${currentConfigIndex} version)
SET(configsText "${configsText} ${filename} (version ${version})\n")
ENDFOREACH(currentConfigIndex)
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} ${VERSION_MSG}, checked the following files:\n${configsText}")
ELSE(${_NAME}_CONSIDERED_CONFIGS)
# Simple case: No Config-file was found at all:
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: found neither ${_NAME}Config.cmake nor ${_NAME_LOWER}-config.cmake ${VERSION_MSG}")
ENDIF(${_NAME}_CONSIDERED_CONFIGS)
ENDIF(${_NAME}_CONFIG)
ENDMACRO(_FPHSA_HANDLE_FAILURE_CONFIG_MODE)
FUNCTION(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG)
# set up the arguments for CMAKE_PARSE_ARGUMENTS and check whether we are in
# new extended or in the "old" mode:
SET(options CONFIG_MODE)
SET(oneValueArgs FAIL_MESSAGE VERSION_VAR)
SET(multiValueArgs REQUIRED_VARS)
SET(_KEYWORDS_FOR_EXTENDED_MODE ${options} ${oneValueArgs} ${multiValueArgs} )
LIST(FIND _KEYWORDS_FOR_EXTENDED_MODE "${_FIRST_ARG}" INDEX)
IF(${INDEX} EQUAL -1)
SET(FPHSA_FAIL_MESSAGE ${_FIRST_ARG})
SET(FPHSA_REQUIRED_VARS ${ARGN})
SET(FPHSA_VERSION_VAR)
ELSE(${INDEX} EQUAL -1)
CMAKE_PARSE_ARGUMENTS(FPHSA "${options}" "${oneValueArgs}" "${multiValueArgs}" ${_FIRST_ARG} ${ARGN})
IF(FPHSA_UNPARSED_ARGUMENTS)
MESSAGE(FATAL_ERROR "Unknown keywords given to FIND_PACKAGE_HANDLE_STANDARD_ARGS(): \"${FPHSA_UNPARSED_ARGUMENTS}\"")
ENDIF(FPHSA_UNPARSED_ARGUMENTS)
IF(NOT FPHSA_FAIL_MESSAGE)
SET(FPHSA_FAIL_MESSAGE "DEFAULT_MSG")
ENDIF(NOT FPHSA_FAIL_MESSAGE)
ENDIF(${INDEX} EQUAL -1)
# now that we collected all arguments, process them
IF("${FPHSA_FAIL_MESSAGE}" STREQUAL "DEFAULT_MSG")
SET(FPHSA_FAIL_MESSAGE "Could NOT find ${_NAME}")
ENDIF("${FPHSA_FAIL_MESSAGE}" STREQUAL "DEFAULT_MSG")
# In config-mode, we rely on the variable <package>_CONFIG, which is set by find_package()
# when it successfully found the config-file, including version checking:
IF(FPHSA_CONFIG_MODE)
LIST(INSERT FPHSA_REQUIRED_VARS 0 ${_NAME}_CONFIG)
LIST(REMOVE_DUPLICATES FPHSA_REQUIRED_VARS)
SET(FPHSA_VERSION_VAR ${_NAME}_VERSION)
ENDIF(FPHSA_CONFIG_MODE)
IF(NOT FPHSA_REQUIRED_VARS)
MESSAGE(FATAL_ERROR "No REQUIRED_VARS specified for FIND_PACKAGE_HANDLE_STANDARD_ARGS()")
ENDIF(NOT FPHSA_REQUIRED_VARS)
LIST(GET FPHSA_REQUIRED_VARS 0 _FIRST_REQUIRED_VAR)
STRING(TOUPPER ${_NAME} _NAME_UPPER)
STRING(TOLOWER ${_NAME} _NAME_LOWER)
# collect all variables which were not found, so they can be printed, so the
# user knows better what went wrong (#6375)
SET(MISSING_VARS "")
SET(DETAILS "")
SET(${_NAME_UPPER}_FOUND TRUE)
# check if all passed variables are valid
FOREACH(_CURRENT_VAR ${FPHSA_REQUIRED_VARS})
IF(NOT ${_CURRENT_VAR})
SET(${_NAME_UPPER}_FOUND FALSE)
SET(MISSING_VARS "${MISSING_VARS} ${_CURRENT_VAR}")
ELSE(NOT ${_CURRENT_VAR})
SET(DETAILS "${DETAILS}[${${_CURRENT_VAR}}]")
ENDIF(NOT ${_CURRENT_VAR})
ENDFOREACH(_CURRENT_VAR)
# version handling:
SET(VERSION_MSG "")
SET(VERSION_OK TRUE)
SET(VERSION ${${FPHSA_VERSION_VAR}} )
IF (${_NAME}_FIND_VERSION)
IF(VERSION)
IF(${_NAME}_FIND_VERSION_EXACT) # exact version required
IF (NOT "${${_NAME}_FIND_VERSION}" VERSION_EQUAL "${VERSION}")
SET(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"")
SET(VERSION_OK FALSE)
ELSE (NOT "${${_NAME}_FIND_VERSION}" VERSION_EQUAL "${VERSION}")
SET(VERSION_MSG "(found suitable exact version \"${VERSION}\")")
ENDIF (NOT "${${_NAME}_FIND_VERSION}" VERSION_EQUAL "${VERSION}")
ELSE(${_NAME}_FIND_VERSION_EXACT) # minimum version specified:
IF ("${${_NAME}_FIND_VERSION}" VERSION_GREATER "${VERSION}")
SET(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is at least \"${${_NAME}_FIND_VERSION}\"")
SET(VERSION_OK FALSE)
ELSE ("${${_NAME}_FIND_VERSION}" VERSION_GREATER "${VERSION}")
SET(VERSION_MSG "(found suitable version \"${VERSION}\", required is \"${${_NAME}_FIND_VERSION}\")")
ENDIF ("${${_NAME}_FIND_VERSION}" VERSION_GREATER "${VERSION}")
ENDIF(${_NAME}_FIND_VERSION_EXACT)
ELSE(VERSION)
# if the package was not found, but a version was given, add that to the output:
IF(${_NAME}_FIND_VERSION_EXACT)
SET(VERSION_MSG "(Required is exact version \"${${_NAME}_FIND_VERSION}\")")
ELSE(${_NAME}_FIND_VERSION_EXACT)
SET(VERSION_MSG "(Required is at least version \"${${_NAME}_FIND_VERSION}\")")
ENDIF(${_NAME}_FIND_VERSION_EXACT)
ENDIF(VERSION)
ELSE (${_NAME}_FIND_VERSION)
IF(VERSION)
SET(VERSION_MSG "(found version \"${VERSION}\")")
ENDIF(VERSION)
ENDIF (${_NAME}_FIND_VERSION)
IF(VERSION_OK)
SET(DETAILS "${DETAILS}[v${VERSION}(${${_NAME}_FIND_VERSION})]")
ELSE(VERSION_OK)
SET(${_NAME_UPPER}_FOUND FALSE)
ENDIF(VERSION_OK)
# print the result:
IF (${_NAME_UPPER}_FOUND)
FIND_PACKAGE_MESSAGE(${_NAME} "Found ${_NAME}: ${${_FIRST_REQUIRED_VAR}} ${VERSION_MSG}" "${DETAILS}")
ELSE (${_NAME_UPPER}_FOUND)
IF(FPHSA_CONFIG_MODE)
_FPHSA_HANDLE_FAILURE_CONFIG_MODE()
ELSE(FPHSA_CONFIG_MODE)
IF(NOT VERSION_OK)
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: ${VERSION_MSG} (found ${${_FIRST_REQUIRED_VAR}})")
ELSE(NOT VERSION_OK)
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} (missing: ${MISSING_VARS}) ${VERSION_MSG}")
ENDIF(NOT VERSION_OK)
ENDIF(FPHSA_CONFIG_MODE)
ENDIF (${_NAME_UPPER}_FOUND)
SET(${_NAME_UPPER}_FOUND ${${_NAME_UPPER}_FOUND} PARENT_SCOPE)
ENDFUNCTION(FIND_PACKAGE_HANDLE_STANDARD_ARGS _FIRST_ARG)

View file

@ -229,7 +229,7 @@
set(OPENSSL_VERSION "${OPENSSL_VERSION_MAJOR}.${OPENSSL_VERSION_MINOR}.${OPENSSL_VERSION_PATCH}")
endif (OPENSSL_INCLUDE_DIR)
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
include(FindPackageHandleStandardArgs)
if (OPENSSL_VERSION)
find_package_handle_standard_args(OpenSSL

View file

@ -73,7 +73,7 @@ void ServerStanzaChannel::finishSession(const JID& to, boost::shared_ptr<Element
}
(*i)->finishSession();
std::cout << "FINISH SESSION " << sessions[to.toBare().toString()].size() << "\n";
// std::cout << "FINISH SESSION " << sessions[to.toBare().toString()].size() << "\n";
if (last) {
break;
}

View file

@ -97,9 +97,7 @@ class Conversation {
/// This is used to detect Private messages associated with particular room.
/// \param room room name associated with this Conversation.
void setRoom(const std::string &room) {
m_room = room;
}
void setRoom(const std::string &room);
/// Returns room name associated with this Conversation.

View file

@ -63,6 +63,7 @@ class LocalBuddy : public Buddy {
std::string m_statusMessage;
std::string m_iconHash;
Swift::StatusShow m_status;
bool m_firstSet;
};
}

View file

@ -48,6 +48,7 @@ class MySQLBackend : public StorageBackend
/// automatically.
/// \return true if database is opened successfully.
bool connect();
void disconnect();
/// Creates database structure.
/// \see connect()
@ -100,7 +101,7 @@ class MySQLBackend : public StorageBackend
Statement(MYSQL *conn, const std::string &format, const std::string &statement);
~Statement();
bool execute();
int execute();
int fetch();

View file

@ -217,7 +217,6 @@ class NetworkPlugin {
private:
void connect();
void handleLoginPayload(const std::string &payload);
void handleLogoutPayload(const std::string &payload);
void handleStatusChangedPayload(const std::string &payload);

View file

@ -2,7 +2,11 @@ cmake_minimum_required(VERSION 2.6)
FILE(GLOB SRC *.cpp *.h)
FILE(GLOB HEADERS ../include/transport/*.h)
ADD_LIBRARY(transport-plugin STATIC ${HEADERS} ${SRC} ${PROTOBUF_SRC} ${PROTOBUF_HDRS} ../../src/memoryusage.cpp ${CMAKE_CURRENT_BINARY_DIR}/../../include/transport/protocol.pb.cc)
if (NOT WIN32)
ADD_LIBRARY(transport-plugin SHARED ${HEADERS} ${SRC} ${PROTOBUF_SRC} ${PROTOBUF_HDRS} ../../src/memoryusage.cpp ${CMAKE_CURRENT_BINARY_DIR}/../../include/transport/protocol.pb.cc)
else()
ADD_LIBRARY(transport-plugin STATIC ${HEADERS} ${SRC} ${PROTOBUF_SRC} ${PROTOBUF_HDRS} ../../src/memoryusage.cpp ${CMAKE_CURRENT_BINARY_DIR}/../../include/transport/protocol.pb.cc)
endif()
ADD_DEPENDENCIES(transport-plugin pb)
SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/../../include/transport/protocol.pb.cc PROPERTIES GENERATED 1)

View file

@ -4,7 +4,8 @@ password = secret
server = 127.0.0.1
port = 5222
server_mode = 1
backend_host=localhost # < this option doesn't work yet
backend_host=localhost
# < this option doesn't work yet
backend_port=10001
admin_username=admin
admin_password=test
@ -14,7 +15,7 @@ users_per_backend=10
backend=/home/hanzz/code/libtransport/backends/libpurple/spectrum2_libpurple_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=../../backends/libircclient-qt/spectrum2_libircclient-qt_backend
#backend=/home/hanzz/code/libtransport/backends/libircclient-qt/spectrum2_libircclient-qt_backend
#protocol=prpl-msn
protocol=any
#protocol=prpl-icq
@ -25,7 +26,7 @@ protocol=any
[logging]
#config=logging.cfg # log4cxx/log4j logging configuration file
#backend_config=backend_logging.cfg # log4cxx/log4j logging configuration file for backends
#backend_config=/home/hanzz/code/libtransport/spectrum/src/backend-logging.cfg # log4cxx/log4j logging configuration file for backends
[database]
type = none # or "none" without database backend

View file

@ -65,7 +65,7 @@ type=xmpp
config = /etc/spectrum2/logging.cfg
# log4cxx/log4j logging configuration file in ini format used for backends.
backend_config = /etc/spectrum2/backend_logging.cfg # log4cxx/log4j logging configuration file for backends
backend_config = /etc/spectrum2/backend-logging.cfg # log4cxx/log4j logging configuration file for backends
[database]
# Database backend type

View file

@ -26,26 +26,26 @@ using namespace boost;
static int finished;
static std::string *m;
static void handleDisconnected(Swift::Client *client, const boost::optional<Swift::ClientError> &) {
std::cout << "[ DISCONNECTED ] " << client->getJID().getDomain() << "\n";
static void handleDisconnected(Swift::Client *client, const boost::optional<Swift::ClientError> &, const std::string &server) {
std::cout << "[ DISCONNECTED ] " << server << "\n";
if (--finished == 0) {
exit(0);
}
}
static void handleConnected(Swift::Client *client) {
static void handleConnected(Swift::Client *client, const std::string &server) {
boost::shared_ptr<Swift::Message> message(new Swift::Message());
message->setTo(client->getJID().getDomain());
message->setTo(server);
message->setFrom(client->getJID());
message->setBody(*m);
client->sendMessage(message);
}
static void handleMessageReceived(Swift::Client *client, Swift::Message::ref message) {
static void handleMessageReceived(Swift::Client *client, Swift::Message::ref message, const std::string &server) {
std::string body = message->getBody();
boost::replace_all(body, "\n", "\n[ OK ] " + client->getJID().getDomain() + ": ");
std::cout << "[ OK ] " << client->getJID().getDomain() << ": " << body << "\n";
boost::replace_all(body, "\n", "\n[ OK ] " + server + ": ");
std::cout << "[ OK ] " << server << ": " << body << "\n";
if (--finished == 0) {
exit(0);
}
@ -205,6 +205,47 @@ static void stop_all_instances(ManagerConfig *config) {
}
}
void ask_local_servers(ManagerConfig *config, Swift::BoostNetworkFactories &networkFactories, const std::string &message) {
path p(CONFIG_STRING(config, "service.config_directory"));
try {
if (!exists(p)) {
std::cerr << "Config directory " << CONFIG_STRING(config, "service.config_directory") << " does not exist\n";
exit(6);
}
if (!is_directory(p)) {
std::cerr << "Config directory " << CONFIG_STRING(config, "service.config_directory") << " does not exist\n";
exit(7);
}
directory_iterator end_itr;
for (directory_iterator itr(p); itr != end_itr; ++itr) {
if (is_regular(itr->path()) && extension(itr->path()) == ".cfg") {
Config cfg;
if (cfg.load(itr->path().string()) == false) {
std::cerr << "Can't load config file " << itr->path().string() << ". Skipping...\n";
}
finished++;
Swift::Client *client = new Swift::Client(CONFIG_STRING(&cfg, "service.admin_username"), CONFIG_STRING(&cfg, "service.admin_password"), &networkFactories);
client->setAlwaysTrustCertificates();
client->onConnected.connect(boost::bind(&handleConnected, client, CONFIG_STRING(&cfg, "service.jid")));
client->onDisconnected.connect(bind(&handleDisconnected, client, _1, CONFIG_STRING(&cfg, "service.jid")));
client->onMessageReceived.connect(bind(&handleMessageReceived, client, _1, CONFIG_STRING(&cfg, "service.jid")));
Swift::ClientOptions opt;
opt.allowPLAINWithoutTLS = true;
client->connect(opt);
}
}
}
catch (const filesystem_error& ex) {
std::cerr << "boost filesystem error\n";
exit(5);
}
}
int main(int argc, char **argv)
{
ManagerConfig config;
@ -215,7 +256,7 @@ int main(int argc, char **argv)
boost::program_options::options_description desc("Usage: spectrum [OPTIONS] <COMMAND>\nAllowed options");
desc.add_options()
("help,h", "Show help output")
("config,c", boost::program_options::value<std::string>(&config_file)->default_value("/etc/spectrum2/spectrum-manager.cfg"), "Spectrum manager config file")
("config,c", boost::program_options::value<std::string>(&config_file)->default_value("/etc/spectrum2/spectrum_manager.cfg"), "Spectrum manager config file")
("command", boost::program_options::value<std::string>(&command)->default_value(""), "Command")
;
try
@ -243,12 +284,16 @@ int main(int argc, char **argv)
return 3;
}
if (!config.load(config_file)) {
std::cerr << "Can't load configuration file.\n";
return 4;
}
if (command.empty()) {
std::cout << desc << "\n";
return 1;
}
if (command == "start") {
start_all_instances(&config);
}
@ -259,17 +304,19 @@ int main(int argc, char **argv)
Swift::SimpleEventLoop eventLoop;
Swift::BoostNetworkFactories networkFactories(&eventLoop);
std::string message = argv[1];
std::string message = command;
m = &message;
ask_local_servers(&config, networkFactories, message);
std::vector<std::string> servers = CONFIG_VECTOR(&config, "servers.server");
for (std::vector<std::string>::const_iterator it = servers.begin(); it != servers.end(); it++) {
finished++;
Swift::Client *client = new Swift::Client(CONFIG_STRING(&config, "service.admin_username") + "@" + (*it), CONFIG_STRING(&config, "service.admin_password"), &networkFactories);
Swift::Client *client = new Swift::Client(CONFIG_STRING(&config, "service.admin_username") + "@" + *it, CONFIG_STRING(&config, "service.admin_password"), &networkFactories);
client->setAlwaysTrustCertificates();
client->onConnected.connect(boost::bind(&handleConnected, client));
client->onDisconnected.connect(bind(&handleDisconnected, client, _1));
client->onMessageReceived.connect(bind(&handleMessageReceived, client, _1));
client->onConnected.connect(boost::bind(&handleConnected, client, *it));
client->onDisconnected.connect(bind(&handleDisconnected, client, _1, *it));
client->onMessageReceived.connect(bind(&handleMessageReceived, client, _1, *it));
Swift::ClientOptions opt;
opt.allowPLAINWithoutTLS = true;
client->connect(opt);

View file

@ -61,8 +61,8 @@ void AdminInterface::handleMessageReceived(Swift::Message::ref message) {
if (!message->getTo().getNode().empty())
return;
if (message->getFrom().getNode() != CONFIG_STRING(m_component->getConfig(), "service.admin_username")) {
LOG4CXX_WARN(logger, "Message not from admin user, but from " << message->getFrom().getNode());
if (message->getFrom().toBare().toString() != CONFIG_STRING(m_component->getConfig(), "service.admin_jid")) {
LOG4CXX_WARN(logger, "Message not from admin user, but from " << message->getFrom().toBare().toString());
return;
}

View file

@ -69,7 +69,7 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description
("service.backend_port", value<std::string>()->default_value("10000"), "Port to bind backend server to")
("service.cert", value<std::string>()->default_value(""), "PKCS#12 Certificate.")
("service.cert_password", value<std::string>()->default_value(""), "PKCS#12 Certificate password.")
("service.admin_username", value<std::string>()->default_value(""), "Administrator username.")
("service.admin_jid", value<std::string>()->default_value(""), "Administrator jid.")
("service.admin_password", value<std::string>()->default_value(""), "Administrator password.")
("service.reuse_old_backends", value<bool>()->default_value(true), "True if Spectrum should use old backends which were full in the past.")
("service.idle_reconnect_time", value<int>()->default_value(0), "Time in seconds after which idle users are reconnected to let their backend die.")

View file

@ -42,6 +42,11 @@ Conversation::Conversation(ConversationManager *conversationManager, const std::
Conversation::~Conversation() {
}
void Conversation::setRoom(const std::string &room) {
m_room = room;
m_legacyName = m_room + "/" + m_legacyName;
}
void Conversation::handleMessage(boost::shared_ptr<Swift::Message> &message, const std::string &nickname) {
if (m_muc) {
message->setType(Swift::Message::Groupchat);
@ -74,8 +79,12 @@ void Conversation::handleMessage(boost::shared_ptr<Swift::Message> &message, con
m_conversationManager->getComponent()->getStanzaChannel()->sendMessage(message);
}
else {
std::string legacyName = m_legacyName;
if (legacyName.find_last_of("@") != std::string::npos) {
legacyName.replace(legacyName.find_last_of("@"), 1, "%"); // OK
}
message->setTo(m_conversationManager->getUser()->getJID().toString());
message->setFrom(Swift::JID(m_legacyName, m_conversationManager->getComponent()->getJID().toBare(), nickname));
message->setFrom(Swift::JID(legacyName, m_conversationManager->getComponent()->getJID().toBare(), nickname));
m_conversationManager->getComponent()->getStanzaChannel()->sendMessage(message);
}
}
@ -83,7 +92,13 @@ void Conversation::handleMessage(boost::shared_ptr<Swift::Message> &message, con
void Conversation::handleParticipantChanged(const std::string &nick, int flag, int status, const std::string &statusMessage, const std::string &newname) {
std::string nickname = nick;
Swift::Presence::ref presence = Swift::Presence::create();
presence->setFrom(Swift::JID(m_legacyName, m_conversationManager->getComponent()->getJID().toBare(), nickname));
std::string legacyName = m_legacyName;
if (m_muc) {
if (legacyName.find_last_of("@") != std::string::npos) {
legacyName.replace(legacyName.find_last_of("@"), 1, "%"); // OK
}
}
presence->setFrom(Swift::JID(legacyName, m_conversationManager->getComponent()->getJID().toBare(), nickname));
presence->setTo(m_conversationManager->getUser()->getJID().toString());
presence->setType(Swift::Presence::Available);

View file

@ -25,12 +25,18 @@ namespace Transport {
LocalBuddy::LocalBuddy(RosterManager *rosterManager, long id) : Buddy(rosterManager, id) {
m_status = Swift::StatusShow::None;
m_firstSet = true;
}
LocalBuddy::~LocalBuddy() {
}
void LocalBuddy::setAlias(const std::string &alias) {
if (m_firstSet) {
m_firstSet = false;
m_alias = alias;
return;
}
bool changed = m_alias != alias;
m_alias = alias;

View file

@ -29,7 +29,7 @@ using namespace log4cxx;
#define MYSQL_DB_VERSION 2
#define CHECK_DB_RESPONSE(stmt) \
if(stmt) { \
sqlite3_exec(m_db, "ROLLBACK;", NULL, NULL, NULL); \
sqlite3_EXEC(m_db, "ROLLBACK;", NULL, NULL, NULL); \
return 0; \
}
@ -72,11 +72,27 @@ using namespace log4cxx;
LOG4CXX_ERROR(logger, NAME << " " << mysql_error(&m_conn)); \
}
#define EXEC(STMT, METHOD) \
{\
int ret = STMT->execute(); \
if (ret == 0) \
exec_ok = true; \
else if (ret == 2013) { \
LOG4CXX_INFO(logger, "MySQL connection lost. Reconnecting...");\
disconnect(); \
connect(); \
return METHOD; \
} \
else \
exec_ok = false; \
}
using namespace boost;
namespace Transport {
static LoggerPtr logger = Logger::getLogger("MySQLBackend");
static bool exec_ok;
MySQLBackend::Statement::Statement(MYSQL *conn, const std::string &format, const std::string &statement) {
m_resultOffset = -1;
@ -184,7 +200,7 @@ MySQLBackend::Statement::~Statement() {
FINALIZE_STMT(m_stmt);
}
bool MySQLBackend::Statement::execute() {
int MySQLBackend::Statement::execute() {
// If statement has some input and doesn't have any output, we have
// to clear the offset now, because operator>> will not be called.
m_offset = 0;
@ -193,9 +209,9 @@ bool MySQLBackend::Statement::execute() {
if ((ret = mysql_stmt_execute(m_stmt)) != 0) {
LOG4CXX_ERROR(logger, m_string << " " << mysql_stmt_error(m_stmt) << "; " << mysql_error(m_conn));
return false;
return mysql_stmt_errno(m_stmt);
}
return true;
return 0;
}
int MySQLBackend::Statement::fetch() {
@ -256,13 +272,18 @@ MySQLBackend::Statement& MySQLBackend::Statement::operator >> (std::string& t) {
MySQLBackend::MySQLBackend(Config *config) {
m_config = config;
m_prefix = CONFIG_STRING(m_config, "database.prefix");
mysql_init(&m_conn);
my_bool my_true = 1;
mysql_options(&m_conn, MYSQL_OPT_RECONNECT, &my_true);
m_prefix = CONFIG_STRING(m_config, "database.prefix");
}
MySQLBackend::~MySQLBackend(){
disconnect();
}
void MySQLBackend::disconnect() {
LOG4CXX_INFO(logger, "Disconnecting");
delete m_setUser;
delete m_getUser;
delete m_removeUser;
@ -286,7 +307,7 @@ bool MySQLBackend::connect() {
CONFIG_STRING(m_config, "database.user") << ", database " << CONFIG_STRING(m_config, "database.database") <<
", port " << CONFIG_INT(m_config, "database.port")
);
if (!mysql_real_connect(&m_conn, CONFIG_STRING(m_config, "database.server").c_str(),
CONFIG_STRING(m_config, "database.user").c_str(),
CONFIG_STRING(m_config, "database.password").c_str(),
@ -389,12 +410,13 @@ bool MySQLBackend::exec(const std::string &query) {
void MySQLBackend::setUser(const UserInfo &user) {
*m_setUser << user.jid << user.uin << user.password << user.language << user.encoding << user.vip << user.password;
m_setUser->execute();
EXEC(m_setUser, setUser(user));
}
bool MySQLBackend::getUser(const std::string &barejid, UserInfo &user) {
*m_getUser << barejid;
if (!m_getUser->execute())
EXEC(m_getUser, getUser(barejid, user));
if (!exec_ok)
return false;
int ret = false;
@ -408,7 +430,7 @@ bool MySQLBackend::getUser(const std::string &barejid, UserInfo &user) {
void MySQLBackend::setUserOnline(long id, bool online) {
*m_setUserOnline << online << id;
m_setUserOnline->execute();
EXEC(m_setUserOnline, setUserOnline(id, online));
}
long MySQLBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) {
@ -417,14 +439,14 @@ long MySQLBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) {
*m_addBuddy << (buddyInfo.groups.size() == 0 ? "" : buddyInfo.groups[0]);
*m_addBuddy << buddyInfo.alias << buddyInfo.flags;
m_addBuddy->execute();
EXEC(m_addBuddy, addBuddy(userId, 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()) {
*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;
m_updateBuddySetting->execute();
EXEC(m_updateBuddySetting, addBuddy(userId, buddyInfo));
}
return id;
@ -436,7 +458,7 @@ void MySQLBackend::updateBuddy(long userId, const BuddyInfo &buddyInfo) {
*m_updateBuddy << buddyInfo.alias << buddyInfo.flags << buddyInfo.subscription;
*m_updateBuddy << userId << buddyInfo.legacyName;
m_updateBuddy->execute();
EXEC(m_updateBuddy, updateBuddy(userId, buddyInfo));
}
bool MySQLBackend::getBuddies(long id, std::list<BuddyInfo> &roster) {
@ -450,7 +472,8 @@ bool MySQLBackend::getBuddies(long id, std::list<BuddyInfo> &roster) {
long buddy_id = -1;
std::string key;
if (!m_getBuddies->execute())
EXEC(m_getBuddies, getBuddies(id, roster));
if (!exec_ok)
return false;
while (m_getBuddies->fetch() == 0) {
@ -465,7 +488,8 @@ bool MySQLBackend::getBuddies(long id, std::list<BuddyInfo> &roster) {
roster.push_back(b);
}
if (!m_getBuddiesSettings->execute())
EXEC(m_getBuddiesSettings, getBuddies(id, roster));
if (!exec_ok)
return false;
BOOST_FOREACH(BuddyInfo &b, roster) {
@ -511,19 +535,23 @@ bool MySQLBackend::getBuddies(long id, std::list<BuddyInfo> &roster) {
bool MySQLBackend::removeUser(long id) {
*m_removeUser << (int) id;
if (!m_removeUser->execute())
EXEC(m_removeUser, removeUser(id));
if (!exec_ok)
return false;
*m_removeUserSettings << (int) id;
if (!m_removeUserSettings->execute())
EXEC(m_removeUserSettings, removeUser(id));
if (!exec_ok)
return false;
*m_removeUserBuddies << (int) id;
if (!m_removeUserBuddies->execute())
EXEC(m_removeUserBuddies, removeUser(id));
if (!exec_ok)
return false;
*m_removeUserBuddiesSettings << (int) id;
if (!m_removeUserBuddiesSettings->execute())
EXEC(m_removeUserBuddiesSettings, removeUser(id));
if (!exec_ok)
return false;
return true;
@ -532,11 +560,11 @@ bool MySQLBackend::removeUser(long id) {
void MySQLBackend::getUserSetting(long id, const std::string &variable, int &type, std::string &value) {
// "SELECT type, value FROM " + m_prefix + "users_settings WHERE user_id=? AND var=?"
*m_getUserSetting << id << variable;
m_getUserSetting->execute();
EXEC(m_getUserSetting, getUserSetting(id, variable, type, value));
if (m_getUserSetting->fetch() != 0) {
// "INSERT INTO " + m_prefix + "users_settings (user_id, var, type, value) VALUES (?,?,?,?)"
*m_setUserSetting << id << variable << type << value;
m_setUserSetting->execute();
EXEC(m_setUserSetting, getUserSetting(id, variable, type, value));
}
else {
*m_getUserSetting >> type >> value;
@ -546,7 +574,7 @@ void MySQLBackend::getUserSetting(long id, const std::string &variable, int &typ
void MySQLBackend::updateUserSetting(long id, const std::string &variable, const std::string &value) {
// "UPDATE " + m_prefix + "users_settings SET value=? WHERE user_id=? AND var=?"
*m_updateUserSetting << value << id << variable;
m_updateUserSetting->execute();
EXEC(m_updateUserSetting, updateUserSetting(id, variable, value));
}
void MySQLBackend::beginTransaction() {

View file

@ -355,6 +355,7 @@ void NetworkPluginServer::handleConnectedPayload(const std::string &data) {
User *user = m_userManager->getUser(payload.user());
if (!user) {
LOG4CXX_ERROR(logger, "Connected payload received for unknown user " << payload.user());
return;
}
@ -1300,7 +1301,8 @@ void NetworkPluginServer::handleFTRejected(User *user, const std::string &buddyN
void NetworkPluginServer::handleFTStateChanged(Swift::FileTransfer::State state, const std::string &userName, const std::string &buddyName, const std::string &fileName, unsigned long size, unsigned long id) {
User *user = m_userManager->getUser(userName);
if (!user) {
// TODO: reject and remove filetransfer
// TODO: FIXME We have to remove filetransfer when use disconnects
return;
}
if (state.state == Swift::FileTransfer::State::Transferring) {
handleFTAccepted(user, buddyName, fileName, size, id);

99
src/tests/basictest.cpp Normal file
View file

@ -0,0 +1,99 @@
#include "basictest.h"
#include "transport/userregistry.h"
#include "transport/config.h"
#include "transport/storagebackend.h"
#include "transport/user.h"
#include "transport/transport.h"
#include "transport/conversation.h"
#include "transport/usermanager.h"
#include "transport/localbuddy.h"
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
#include <Swiften/Swiften.h>
#include <Swiften/EventLoop/DummyEventLoop.h>
#include <Swiften/Server/Server.h>
#include <Swiften/Network/DummyNetworkFactories.h>
#include <Swiften/Network/DummyConnectionServer.h>
#include "Swiften/Server/ServerStanzaChannel.h"
#include "Swiften/Server/ServerFromClientSession.h"
#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h"
using namespace Transport;
void BasicTest::setMeUp (void) {
streamEnded = false;
std::istringstream ifs("service.server_mode = 1\nservice.jid=localhost");
cfg = new Config();
cfg->load(ifs);
factory = new TestingFactory();
loop = new Swift::DummyEventLoop();
factories = new Swift::DummyNetworkFactories(loop);
userRegistry = new UserRegistry(cfg, factories);
component = new Component(loop, factories, cfg, factory, userRegistry);
component->start();
userManager = new UserManager(component, userRegistry);
payloadSerializers = new Swift::FullPayloadSerializerCollection();
payloadParserFactories = new Swift::FullPayloadParserFactoryCollection();
parser = new Swift::XMPPParser(this, payloadParserFactories, factories->getXMLParserFactory());
serverFromClientSession = boost::shared_ptr<Swift::ServerFromClientSession>(new Swift::ServerFromClientSession("id", factories->getConnectionFactory()->createConnection(),
payloadParserFactories, payloadSerializers, userRegistry, factories->getXMLParserFactory(), Swift::JID("user@localhost/resource")));
serverFromClientSession->startSession();
serverFromClientSession->onDataWritten.connect(boost::bind(&BasicTest::handleDataReceived, this, _1));
dynamic_cast<Swift::ServerStanzaChannel *>(component->getStanzaChannel())->addSession(serverFromClientSession);
parser->parse("<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='localhost' version='1.0'>");
received.clear();
loop->processEvents();
}
void BasicTest::tearMeDown (void) {
dynamic_cast<Swift::ServerStanzaChannel *>(component->getStanzaChannel())->removeSession(serverFromClientSession);
delete component;
delete userRegistry;
delete factories;
delete factory;
delete loop;
delete cfg;
delete parser;
received.clear();
}
void BasicTest::handleDataReceived(const Swift::SafeByteArray &data) {
// std::cout << safeByteArrayToString(data) << "\n";
parser->parse(safeByteArrayToString(data));
}
void BasicTest::handleStreamStart(const Swift::ProtocolHeader&) {
}
void BasicTest::handleElement(boost::shared_ptr<Swift::Element> element) {
received.push_back(element);
}
void BasicTest::handleStreamEnd() {
streamEnded = true;
}
void BasicTest::injectPresence(boost::shared_ptr<Swift::Presence> &response) {
dynamic_cast<Swift::ServerStanzaChannel *>(component->getStanzaChannel())->onPresenceReceived(response);
}
void BasicTest::injectIQ(boost::shared_ptr<Swift::IQ> iq) {
dynamic_cast<Swift::ServerStanzaChannel *>(component->getStanzaChannel())->onIQReceived(iq);
}
Swift::Stanza *BasicTest::getStanza(boost::shared_ptr<Swift::Element> element) {
Swift::Stanza *stanza = dynamic_cast<Swift::Stanza *>(element.get());
CPPUNIT_ASSERT(stanza);
return stanza;
}

120
src/tests/basictest.h Normal file
View file

@ -0,0 +1,120 @@
/**
* 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/SetResponder.h"
#include "transport/conversation.h"
#include "transport/conversationmanager.h"
#include "transport/userregistry.h"
#include "transport/config.h"
#include "transport/storagebackend.h"
#include "transport/user.h"
#include "transport/transport.h"
#include "transport/conversation.h"
#include "transport/usermanager.h"
#include "transport/localbuddy.h"
#include <Swiften/Swiften.h>
#include <Swiften/EventLoop/DummyEventLoop.h>
#include <Swiften/Server/Server.h>
#include <Swiften/Network/DummyNetworkFactories.h>
#include <Swiften/Network/DummyConnectionServer.h>
#include "Swiften/Server/ServerStanzaChannel.h"
#include "Swiften/Server/ServerFromClientSession.h"
#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h"
using namespace Transport;
class TestingConversation : public Conversation {
public:
TestingConversation(ConversationManager *conversationManager, const std::string &legacyName, bool muc = false) : Conversation(conversationManager, legacyName, muc) {
}
// Called when there's new message to legacy network from XMPP network
void sendMessage(boost::shared_ptr<Swift::Message> &message) {
}
};
class TestingFactory : public Factory {
public:
TestingFactory() {
}
// Creates new conversation (NetworkConversation in this case)
Conversation *createConversation(ConversationManager *conversationManager, const std::string &legacyName) {
Conversation *nc = new TestingConversation(conversationManager, legacyName);
return nc;
}
// Creates new LocalBuddy
Buddy *createBuddy(RosterManager *rosterManager, const BuddyInfo &buddyInfo) {
LocalBuddy *buddy = new LocalBuddy(rosterManager, buddyInfo.id);
buddy->setAlias(buddyInfo.alias);
buddy->setName(buddyInfo.legacyName);
buddy->setSubscription(buddyInfo.subscription);
buddy->setGroups(buddyInfo.groups);
buddy->setFlags((BuddyFlag) buddyInfo.flags);
if (buddyInfo.settings.find("icon_hash") != buddyInfo.settings.end())
buddy->setIconHash(buddyInfo.settings.find("icon_hash")->second.s);
return buddy;
}
};
class BasicTest : public Swift::XMPPParserClient {
public:
void setMeUp (void);
void tearMeDown (void);
void handleDataReceived(const Swift::SafeByteArray &data);
void handleStreamStart(const Swift::ProtocolHeader&);
void handleElement(boost::shared_ptr<Swift::Element> element);
void handleStreamEnd();
void injectPresence(boost::shared_ptr<Swift::Presence> &response);
void injectIQ(boost::shared_ptr<Swift::IQ> iq);
Swift::Stanza *getStanza(boost::shared_ptr<Swift::Element> element);
protected:
bool streamEnded;
UserManager *userManager;
boost::shared_ptr<Swift::ServerFromClientSession> serverFromClientSession;
Swift::FullPayloadSerializerCollection* payloadSerializers;
Swift::FullPayloadParserFactoryCollection* payloadParserFactories;
Swift::XMPPParser *parser;
UserRegistry *userRegistry;
Config *cfg;
Swift::Server *server;
Swift::DummyNetworkFactories *factories;
Swift::DummyEventLoop *loop;
TestingFactory *factory;
Component *component;
std::vector<boost::shared_ptr<Swift::Element> > received;
};

View file

@ -14,45 +14,11 @@
#include "Swiften/Server/ServerFromClientSession.h"
#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h"
#include "basictest.h"
using namespace Transport;
class TestingConversation : public Conversation {
public:
TestingConversation(ConversationManager *conversationManager, const std::string &legacyName, bool muc = false) : Conversation(conversationManager, legacyName, muc) {
}
// Called when there's new message to legacy network from XMPP network
void sendMessage(boost::shared_ptr<Swift::Message> &message) {
}
};
class TestingFactory : public Factory {
public:
TestingFactory() {
}
// Creates new conversation (NetworkConversation in this case)
Conversation *createConversation(ConversationManager *conversationManager, const std::string &legacyName) {
Conversation *nc = new TestingConversation(conversationManager, legacyName);
return nc;
}
// Creates new LocalBuddy
Buddy *createBuddy(RosterManager *rosterManager, const BuddyInfo &buddyInfo) {
LocalBuddy *buddy = new LocalBuddy(rosterManager, buddyInfo.id);
buddy->setAlias(buddyInfo.alias);
buddy->setName(buddyInfo.legacyName);
buddy->setSubscription(buddyInfo.subscription);
buddy->setGroups(buddyInfo.groups);
buddy->setFlags((BuddyFlag) buddyInfo.flags);
if (buddyInfo.settings.find("icon_hash") != buddyInfo.settings.end())
buddy->setIconHash(buddyInfo.settings.find("icon_hash")->second.s);
return buddy;
}
};
class ComponentTest : public CPPUNIT_NS :: TestFixture, public Swift::XMPPParserClient {
class ComponentTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
CPPUNIT_TEST_SUITE(ComponentTest);
CPPUNIT_TEST(handlePresenceWithNode);
CPPUNIT_TEST(handlePresenceWithoutNode);
@ -62,48 +28,14 @@ class ComponentTest : public CPPUNIT_NS :: TestFixture, public Swift::XMPPParser
void setUp (void) {
onUserPresenceReceived = false;
onUserDiscoInfoReceived = false;
std::istringstream ifs("service.server_mode = 1\n");
cfg = new Config();
cfg->load(ifs);
factory = new TestingFactory();
loop = new Swift::DummyEventLoop();
factories = new Swift::DummyNetworkFactories(loop);
userRegistry = new UserRegistry(cfg, factories);
component = new Component(loop, factories, cfg, factory, userRegistry);
setMeUp();
component->onUserPresenceReceived.connect(boost::bind(&ComponentTest::handleUserPresenceReceived, this, _1));
component->onUserDiscoInfoReceived.connect(boost::bind(&ComponentTest::handleUserDiscoInfoReceived, this, _1, _2));
component->start();
payloadSerializers = new Swift::FullPayloadSerializerCollection();
payloadParserFactories = new Swift::FullPayloadParserFactoryCollection();
parser = new Swift::XMPPParser(this, payloadParserFactories, factories->getXMLParserFactory());
serverFromClientSession = boost::shared_ptr<Swift::ServerFromClientSession>(new Swift::ServerFromClientSession("id", factories->getConnectionFactory()->createConnection(),
payloadParserFactories, payloadSerializers, userRegistry, factories->getXMLParserFactory(), Swift::JID("user@localhost/resource")));
serverFromClientSession->startSession();
serverFromClientSession->onDataWritten.connect(boost::bind(&ComponentTest::handleDataReceived, this, _1));
dynamic_cast<Swift::ServerStanzaChannel *>(component->getStanzaChannel())->addSession(serverFromClientSession);
parser->parse("<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='localhost' version='1.0'>");
received.clear();
loop->processEvents();
}
void tearDown (void) {
dynamic_cast<Swift::ServerStanzaChannel *>(component->getStanzaChannel())->removeSession(serverFromClientSession);
delete component;
delete userRegistry;
delete factories;
delete factory;
delete loop;
delete cfg;
delete parser;
received.clear();
tearMeDown();
}
void handleUserDiscoInfoReceived(const Swift::JID& jid, boost::shared_ptr<Swift::DiscoInfo> info) {
@ -114,22 +46,6 @@ class ComponentTest : public CPPUNIT_NS :: TestFixture, public Swift::XMPPParser
onUserPresenceReceived = true;
}
void handleDataReceived(const Swift::SafeByteArray &data) {
parser->parse(safeByteArrayToString(data));
}
void handleStreamStart(const Swift::ProtocolHeader&) {
}
void handleElement(boost::shared_ptr<Swift::Element> element) {
received.push_back(element);
}
void handleStreamEnd() {
}
void handlePresenceWithNode() {
Swift::Presence::ref response = Swift::Presence::create();
response->setTo("somebody@localhost");
@ -151,27 +67,9 @@ class ComponentTest : public CPPUNIT_NS :: TestFixture, public Swift::XMPPParser
CPPUNIT_ASSERT(onUserPresenceReceived);
}
Swift::Stanza *getStanza(boost::shared_ptr<Swift::Element> element) {
Swift::Stanza *stanza = dynamic_cast<Swift::Stanza *>(element.get());
CPPUNIT_ASSERT(stanza);
return stanza;
}
private:
bool onUserPresenceReceived;
bool onUserDiscoInfoReceived;
boost::shared_ptr<Swift::ServerFromClientSession> serverFromClientSession;
Swift::FullPayloadSerializerCollection* payloadSerializers;
Swift::FullPayloadParserFactoryCollection* payloadParserFactories;
Swift::XMPPParser *parser;
UserRegistry *userRegistry;
Config *cfg;
Swift::Server *server;
Swift::DummyNetworkFactories *factories;
Swift::DummyEventLoop *loop;
TestingFactory *factory;
Component *component;
std::vector<boost::shared_ptr<Swift::Element> > received;
};
CPPUNIT_TEST_SUITE_REGISTRATION (ComponentTest);

156
src/tests/rostermanager.cpp Normal file
View file

@ -0,0 +1,156 @@
#include "transport/userregistry.h"
#include "transport/config.h"
#include "transport/storagebackend.h"
#include "transport/user.h"
#include "transport/transport.h"
#include "transport/conversation.h"
#include "transport/usermanager.h"
#include "transport/localbuddy.h"
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
#include <Swiften/Swiften.h>
#include <Swiften/EventLoop/DummyEventLoop.h>
#include <Swiften/Server/Server.h>
#include <Swiften/Network/DummyNetworkFactories.h>
#include <Swiften/Network/DummyConnectionServer.h>
#include "Swiften/Server/ServerStanzaChannel.h"
#include "Swiften/Server/ServerFromClientSession.h"
#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h"
#include "basictest.h"
using namespace Transport;
class RosterManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
CPPUNIT_TEST_SUITE(RosterManagerTest);
CPPUNIT_TEST(setBuddy);
CPPUNIT_TEST(sendCurrentPresences);
CPPUNIT_TEST_SUITE_END();
public:
void setUp (void) {
setMeUp();
userManager->onUserCreated.connect(boost::bind(&RosterManagerTest::handleUserCreated, this, _1));
connectUser();
received.clear();
}
void tearDown (void) {
received.clear();
disconnectUser();
tearMeDown();
}
void handleUserCreated(User *user) {
}
void connectUser() {
CPPUNIT_ASSERT_EQUAL(0, userManager->getUserCount());
userRegistry->isValidUserPassword(Swift::JID("user@localhost/resource"), serverFromClientSession.get(), Swift::createSafeByteArray("password"));
loop->processEvents();
CPPUNIT_ASSERT_EQUAL(1, userManager->getUserCount());
User *user = userManager->getUser("user@localhost");
CPPUNIT_ASSERT(user);
UserInfo userInfo = user->getUserInfo();
CPPUNIT_ASSERT_EQUAL(std::string("password"), userInfo.password);
CPPUNIT_ASSERT(user->isReadyToConnect() == true);
CPPUNIT_ASSERT(user->isConnected() == false);
user->setConnected(true);
CPPUNIT_ASSERT(user->isConnected() == true);
CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
CPPUNIT_ASSERT(getStanza(received[0])->getPayload<Swift::DiscoInfo>());
received.clear();
}
void add2Buddies() {
User *user = userManager->getUser("user@localhost");
CPPUNIT_ASSERT(user);
LocalBuddy *buddy = new LocalBuddy(user->getRosterManager(), -1);
buddy->setFlags(BUDDY_JID_ESCAPING);
buddy->setName("buddy1");
buddy->setAlias("Buddy 1");
std::vector<std::string> grp;
grp.push_back("group1");
buddy->setGroups(grp);
buddy->setStatus(Swift::StatusShow(Swift::StatusShow::Away), "status1");
user->getRosterManager()->setBuddy(buddy);
buddy = new LocalBuddy(user->getRosterManager(), -1);
buddy->setFlags(BUDDY_JID_ESCAPING);
buddy->setName("buddy2");
buddy->setAlias("Buddy 2");
std::vector<std::string> grp2;
grp2.push_back("group2");
buddy->setGroups(grp2);
buddy->setStatus(Swift::StatusShow(Swift::StatusShow::Away), "status2");
user->getRosterManager()->setBuddy(buddy);
}
void setBuddy() {
add2Buddies();
CPPUNIT_ASSERT_EQUAL(2, (int) received.size());
Swift::RosterPayload::ref payload1 = getStanza(received[0])->getPayload<Swift::RosterPayload>();
CPPUNIT_ASSERT(payload1);
CPPUNIT_ASSERT_EQUAL(1, (int) payload1->getItems().size());
Swift::RosterItemPayload item = payload1->getItems()[0];
CPPUNIT_ASSERT_EQUAL(std::string("buddy1"), Buddy::JIDToLegacyName(item.getJID()));
CPPUNIT_ASSERT_EQUAL(std::string("Buddy 1"), item.getName());
Swift::RosterPayload::ref payload2 = getStanza(received[1])->getPayload<Swift::RosterPayload>();
CPPUNIT_ASSERT(payload2);
CPPUNIT_ASSERT_EQUAL(1, (int) payload2->getItems().size());
item = payload2->getItems()[0];
CPPUNIT_ASSERT_EQUAL(std::string("buddy2"), Buddy::JIDToLegacyName(item.getJID()));
CPPUNIT_ASSERT_EQUAL(std::string("Buddy 2"), item.getName());
// send responses back
injectIQ(Swift::IQ::createResult(getStanza(received[0])->getFrom(), getStanza(received[0])->getTo(), getStanza(received[0])->getID()));
injectIQ(Swift::IQ::createResult(getStanza(received[1])->getFrom(), getStanza(received[1])->getTo(), getStanza(received[1])->getID()));
// we should get presences
CPPUNIT_ASSERT_EQUAL(4, (int) received.size());
CPPUNIT_ASSERT(dynamic_cast<Swift::Presence *>(getStanza(received[2])));
CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::Away, dynamic_cast<Swift::Presence *>(getStanza(received[2]))->getShow());
CPPUNIT_ASSERT_EQUAL(std::string("status1"), dynamic_cast<Swift::Presence *>(getStanza(received[2]))->getStatus());
CPPUNIT_ASSERT(dynamic_cast<Swift::Presence *>(getStanza(received[3])));
CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::Away, dynamic_cast<Swift::Presence *>(getStanza(received[3]))->getShow());
CPPUNIT_ASSERT_EQUAL(std::string("status2"), dynamic_cast<Swift::Presence *>(getStanza(received[3]))->getStatus());
}
void sendCurrentPresences() {
setBuddy();
received.clear();
User *user = userManager->getUser("user@localhost");
user->getRosterManager()->sendCurrentPresences("user@localhost/resource");
CPPUNIT_ASSERT_EQUAL(2, (int) received.size());
// CPPUNIT_ASSERT(dynamic_cast<Swift::Presence *>(getStanza(received[2])));
// CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::Away, dynamic_cast<Swift::Presence *>(getStanza(received[2]))->getShow());
// CPPUNIT_ASSERT_EQUAL(std::string("status1"), dynamic_cast<Swift::Presence *>(getStanza(received[2]))->getStatus());
//
// CPPUNIT_ASSERT(dynamic_cast<Swift::Presence *>(getStanza(received[3])));
// CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::Away, dynamic_cast<Swift::Presence *>(getStanza(received[3]))->getShow());
// CPPUNIT_ASSERT_EQUAL(std::string("status2"), dynamic_cast<Swift::Presence *>(getStanza(received[3]))->getStatus());
}
void disconnectUser() {
userManager->disconnectUser("user@localhost");
dynamic_cast<Swift::DummyTimerFactory *>(factories->getTimerFactory())->setTime(10);
loop->processEvents();
CPPUNIT_ASSERT_EQUAL(0, userManager->getUserCount());
CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
CPPUNIT_ASSERT(dynamic_cast<Swift::Presence *>(getStanza(received[0])));
}
};
CPPUNIT_TEST_SUITE_REGISTRATION (RosterManagerTest);

206
src/tests/user.cpp Normal file
View file

@ -0,0 +1,206 @@
#include "transport/userregistry.h"
#include "transport/config.h"
#include "transport/storagebackend.h"
#include "transport/user.h"
#include "transport/transport.h"
#include "transport/conversation.h"
#include "transport/usermanager.h"
#include "transport/localbuddy.h"
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
#include <Swiften/Swiften.h>
#include <Swiften/EventLoop/DummyEventLoop.h>
#include <Swiften/Server/Server.h>
#include <Swiften/Network/DummyNetworkFactories.h>
#include <Swiften/Network/DummyConnectionServer.h>
#include "Swiften/Server/ServerStanzaChannel.h"
#include "Swiften/Server/ServerFromClientSession.h"
#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h"
#include "basictest.h"
using namespace Transport;
class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
CPPUNIT_TEST_SUITE(UserTest);
CPPUNIT_TEST(sendCurrentPresence);
CPPUNIT_TEST(handlePresence);
CPPUNIT_TEST(handlePresenceJoinRoom);
CPPUNIT_TEST(handlePresenceLeaveRoom);
CPPUNIT_TEST(handleDisconnected);
CPPUNIT_TEST_SUITE_END();
public:
std::string room;
std::string roomNickname;
std::string roomPassword;
bool readyToConnect;
bool disconnected;
Swift::Presence::ref changedPresence;
void setUp (void) {
disconnected = false;
readyToConnect = false;
changedPresence = Swift::Presence::ref();
room = "";
roomNickname = "";
roomPassword = "";
setMeUp();
userManager->onUserCreated.connect(boost::bind(&UserTest::handleUserCreated, this, _1));
connectUser();
received.clear();
}
void tearDown (void) {
received.clear();
disconnectUser();
tearMeDown();
}
void handleUserCreated(User *user) {
user->onReadyToConnect.connect(boost::bind(&UserTest::handleUserReadyToConnect, this, user));
user->onPresenceChanged.connect(boost::bind(&UserTest::handleUserPresenceChanged, this, user, _1));
user->onRoomJoined.connect(boost::bind(&UserTest::handleRoomJoined, this, user, _1, _2, _3));
user->onRoomLeft.connect(boost::bind(&UserTest::handleRoomLeft, this, user, _1));
}
void handleUserReadyToConnect(User *user) {
readyToConnect = true;
}
void handleUserPresenceChanged(User *user, Swift::Presence::ref presence) {
changedPresence = presence;
}
void handleRoomJoined(User *user, const std::string &r, const std::string &nickname, const std::string &password) {
room = r;
roomNickname = nickname;
roomPassword = password;
}
void handleRoomLeft(User *user, const std::string &r) {
room = r;
}
void connectUser() {
CPPUNIT_ASSERT_EQUAL(0, userManager->getUserCount());
userRegistry->isValidUserPassword(Swift::JID("user@localhost/resource"), serverFromClientSession.get(), Swift::createSafeByteArray("password"));
loop->processEvents();
CPPUNIT_ASSERT_EQUAL(1, userManager->getUserCount());
User *user = userManager->getUser("user@localhost");
CPPUNIT_ASSERT(user);
UserInfo userInfo = user->getUserInfo();
CPPUNIT_ASSERT_EQUAL(std::string("password"), userInfo.password);
CPPUNIT_ASSERT(user->isReadyToConnect() == true);
CPPUNIT_ASSERT(user->isConnected() == false);
CPPUNIT_ASSERT_EQUAL(true, readyToConnect);
user->setConnected(true);
CPPUNIT_ASSERT(user->isConnected() == true);
CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
CPPUNIT_ASSERT(getStanza(received[0])->getPayload<Swift::DiscoInfo>());
received.clear();
}
void sendCurrentPresence() {
User *user = userManager->getUser("user@localhost");
user->sendCurrentPresence();
// We're not forwarding current presence in server-mode
CPPUNIT_ASSERT_EQUAL(0, (int) received.size());
}
void handlePresence() {
Swift::Presence::ref response = Swift::Presence::create();
response->setTo("localhost");
response->setFrom("user@localhost/resource");
response->setShow(Swift::StatusShow::Away);
injectPresence(response);
loop->processEvents();
// no presence received in server mode, just disco#info
CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
CPPUNIT_ASSERT(getStanza(received[0])->getPayload<Swift::DiscoInfo>());
CPPUNIT_ASSERT(changedPresence);
CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::Away, changedPresence->getShow());
}
void handlePresenceJoinRoom() {
Swift::Presence::ref response = Swift::Presence::create();
response->setTo("#room@localhost/hanzz");
response->setFrom("user@localhost/resource");
Swift::MUCPayload *payload = new Swift::MUCPayload();
payload->setPassword("password");
response->addPayload(boost::shared_ptr<Swift::Payload>(payload));
injectPresence(response);
loop->processEvents();
// no presence received in server mode, just disco#info
CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
CPPUNIT_ASSERT(getStanza(received[0])->getPayload<Swift::DiscoInfo>());
CPPUNIT_ASSERT_EQUAL(std::string("#room"), room);
CPPUNIT_ASSERT_EQUAL(std::string("hanzz"), roomNickname);
CPPUNIT_ASSERT_EQUAL(std::string("password"), roomPassword);
}
void handlePresenceLeaveRoom() {
Swift::Presence::ref response = Swift::Presence::create();
response->setTo("#room@localhost/hanzz");
response->setFrom("user@localhost/resource");
response->setType(Swift::Presence::Unavailable);
Swift::MUCPayload *payload = new Swift::MUCPayload();
payload->setPassword("password");
response->addPayload(boost::shared_ptr<Swift::Payload>(payload));
injectPresence(response);
loop->processEvents();
CPPUNIT_ASSERT_EQUAL(0, (int) received.size());
CPPUNIT_ASSERT_EQUAL(std::string("#room"), room);
CPPUNIT_ASSERT_EQUAL(std::string(""), roomNickname);
CPPUNIT_ASSERT_EQUAL(std::string(""), roomPassword);
}
void handleDisconnected() {
User *user = userManager->getUser("user@localhost");
user->handleDisconnected("Connection error");
loop->processEvents();
CPPUNIT_ASSERT(streamEnded);
user = userManager->getUser("user@localhost");
CPPUNIT_ASSERT(!user);
CPPUNIT_ASSERT_EQUAL(2, (int) received.size());
Swift::Message *m = dynamic_cast<Swift::Message *>(getStanza(received[0]));
CPPUNIT_ASSERT_EQUAL(std::string("Connection error"), m->getBody());
CPPUNIT_ASSERT(dynamic_cast<Swift::StreamError *>(received[1].get()));
CPPUNIT_ASSERT_EQUAL(std::string("Connection error"), dynamic_cast<Swift::StreamError *>(received[1].get())->getText());
disconnected = true;
}
void disconnectUser() {
if (disconnected)
return;
userManager->disconnectUser("user@localhost");
dynamic_cast<Swift::DummyTimerFactory *>(factories->getTimerFactory())->setTime(10);
loop->processEvents();
CPPUNIT_ASSERT_EQUAL(0, userManager->getUserCount());
CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
CPPUNIT_ASSERT(dynamic_cast<Swift::Presence *>(getStanza(received[0])));
}
};
CPPUNIT_TEST_SUITE_REGISTRATION (UserTest);

View file

@ -16,46 +16,11 @@
#include "Swiften/Server/ServerStanzaChannel.h"
#include "Swiften/Server/ServerFromClientSession.h"
#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h"
#include "basictest.h"
using namespace Transport;
class TestingConversation : public Conversation {
public:
TestingConversation(ConversationManager *conversationManager, const std::string &legacyName, bool muc = false) : Conversation(conversationManager, legacyName, muc) {
}
// Called when there's new message to legacy network from XMPP network
void sendMessage(boost::shared_ptr<Swift::Message> &message) {
}
};
class TestingFactory : public Factory {
public:
TestingFactory() {
}
// Creates new conversation (NetworkConversation in this case)
Conversation *createConversation(ConversationManager *conversationManager, const std::string &legacyName) {
Conversation *nc = new TestingConversation(conversationManager, legacyName);
return nc;
}
// Creates new LocalBuddy
Buddy *createBuddy(RosterManager *rosterManager, const BuddyInfo &buddyInfo) {
LocalBuddy *buddy = new LocalBuddy(rosterManager, buddyInfo.id);
buddy->setAlias(buddyInfo.alias);
buddy->setName(buddyInfo.legacyName);
buddy->setSubscription(buddyInfo.subscription);
buddy->setGroups(buddyInfo.groups);
buddy->setFlags((BuddyFlag) buddyInfo.flags);
if (buddyInfo.settings.find("icon_hash") != buddyInfo.settings.end())
buddy->setIconHash(buddyInfo.settings.find("icon_hash")->second.s);
return buddy;
}
};
class UserManagerTest : public CPPUNIT_NS :: TestFixture, public Swift::XMPPParserClient {
class UserManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
CPPUNIT_TEST_SUITE(UserManagerTest);
CPPUNIT_TEST(connectUser);
CPPUNIT_TEST(handleProbePresence);
@ -64,67 +29,13 @@ class UserManagerTest : public CPPUNIT_NS :: TestFixture, public Swift::XMPPPars
public:
void setUp (void) {
streamEnded = false;
std::istringstream ifs("service.server_mode = 1\n");
cfg = new Config();
cfg->load(ifs);
factory = new TestingFactory();
loop = new Swift::DummyEventLoop();
factories = new Swift::DummyNetworkFactories(loop);
userRegistry = new UserRegistry(cfg, factories);
component = new Component(loop, factories, cfg, factory, userRegistry);
component->start();
userManager = new UserManager(component, userRegistry);
payloadSerializers = new Swift::FullPayloadSerializerCollection();
payloadParserFactories = new Swift::FullPayloadParserFactoryCollection();
parser = new Swift::XMPPParser(this, payloadParserFactories, factories->getXMLParserFactory());
serverFromClientSession = boost::shared_ptr<Swift::ServerFromClientSession>(new Swift::ServerFromClientSession("id", factories->getConnectionFactory()->createConnection(),
payloadParserFactories, payloadSerializers, userRegistry, factories->getXMLParserFactory(), Swift::JID("user@localhost/resource")));
serverFromClientSession->startSession();
serverFromClientSession->onDataWritten.connect(boost::bind(&UserManagerTest::handleDataReceived, this, _1));
dynamic_cast<Swift::ServerStanzaChannel *>(component->getStanzaChannel())->addSession(serverFromClientSession);
parser->parse("<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='localhost' version='1.0'>");
received.clear();
loop->processEvents();
setMeUp();
}
void tearDown (void) {
dynamic_cast<Swift::ServerStanzaChannel *>(component->getStanzaChannel())->removeSession(serverFromClientSession);
delete component;
delete userRegistry;
delete factories;
delete factory;
delete loop;
delete cfg;
delete parser;
received.clear();
tearMeDown();
}
void handleDataReceived(const Swift::SafeByteArray &data) {
parser->parse(safeByteArrayToString(data));
}
void handleStreamStart(const Swift::ProtocolHeader&) {
}
void handleElement(boost::shared_ptr<Swift::Element> element) {
received.push_back(element);
}
void handleStreamEnd() {
streamEnded = true;
}
void connectUser() {
CPPUNIT_ASSERT_EQUAL(0, userManager->getUserCount());
userRegistry->isValidUserPassword(Swift::JID("user@localhost/resource"), serverFromClientSession.get(), Swift::createSafeByteArray("password"));
@ -169,30 +80,12 @@ class UserManagerTest : public CPPUNIT_NS :: TestFixture, public Swift::XMPPPars
CPPUNIT_ASSERT_EQUAL(2, (int) received.size());
CPPUNIT_ASSERT(getStanza(received[0])->getPayload<Swift::DiscoInfo>());
CPPUNIT_ASSERT(dynamic_cast<Swift::Presence *>(getStanza(received[1])));
Swift::Presence *presence = dynamic_cast<Swift::Presence *>(getStanza(received[1]));
CPPUNIT_ASSERT(presence);
CPPUNIT_ASSERT_EQUAL(Swift::Presence::Unavailable, presence->getType());
}
Swift::Stanza *getStanza(boost::shared_ptr<Swift::Element> element) {
Swift::Stanza *stanza = dynamic_cast<Swift::Stanza *>(element.get());
CPPUNIT_ASSERT(stanza);
return stanza;
}
private:
bool streamEnded;
UserManager *userManager;
boost::shared_ptr<Swift::ServerFromClientSession> serverFromClientSession;
Swift::FullPayloadSerializerCollection* payloadSerializers;
Swift::FullPayloadParserFactoryCollection* payloadParserFactories;
Swift::XMPPParser *parser;
UserRegistry *userRegistry;
Config *cfg;
Swift::Server *server;
Swift::DummyNetworkFactories *factories;
Swift::DummyEventLoop *loop;
TestingFactory *factory;
Component *component;
std::vector<boost::shared_ptr<Swift::Element> > received;
};
CPPUNIT_TEST_SUITE_REGISTRATION (UserManagerTest);

View file

@ -194,7 +194,8 @@ void User::handlePresence(Swift::Presence::ref presence) {
if (isMUC) {
if (presence->getType() == Swift::Presence::Unavailable) {
LOG4CXX_INFO(logger, m_jid.toString() << ": Going to left room " << presence->getTo().getNode());
onRoomLeft(presence->getTo().getNode());
std::string room = Buddy::JIDToLegacyName(presence->getTo());
onRoomLeft(room);
}
else {
// force connection to legacy network to let backend to handle auto-join on connect.
@ -204,7 +205,12 @@ void User::handlePresence(Swift::Presence::ref presence) {
onReadyToConnect();
}
LOG4CXX_INFO(logger, m_jid.toString() << ": Going to join room " << presence->getTo().getNode() << " as " << presence->getTo().getResource());
onRoomJoined(presence->getTo().getNode(), presence->getTo().getResource(), "");
std::string room = Buddy::JIDToLegacyName(presence->getTo());
std::string password = "";
if (presence->getPayload<Swift::MUCPayload>() != NULL) {
password = presence->getPayload<Swift::MUCPayload>()->getPassword() ? *presence->getPayload<Swift::MUCPayload>()->getPassword() : "";
}
onRoomJoined(room, presence->getTo().getResource(), password);
}
return;
}
@ -298,7 +304,7 @@ void User::handleDisconnected(const std::string &error) {
// We can't be sure finishSession sends unavailable presence everytime, so check if user gets removed
// in finishSession(...) call and if not, remove it here.
std::string jid = m_jid.toBare().toString();
dynamic_cast<Swift::ServerStanzaChannel *>(m_component->getStanzaChannel())->finishSession(m_jid, boost::shared_ptr<Swift::Element>(new Swift::StreamError(Swift::StreamError::UndefinedCondition, "test")));
dynamic_cast<Swift::ServerStanzaChannel *>(m_component->getStanzaChannel())->finishSession(m_jid, boost::shared_ptr<Swift::Element>(new Swift::StreamError(Swift::StreamError::UndefinedCondition, error)));
if (m_userManager->getUser(jid) != NULL) {
m_userManager->removeUser(this);
}

View file

@ -40,7 +40,7 @@ UserRegistry::UserRegistry(Config *cfg, Swift::NetworkFactories *factories) {
UserRegistry::~UserRegistry() { m_removeTimer->stop(); }
void UserRegistry::isValidUserPassword(const Swift::JID& user, Swift::ServerFromClientSession *session, const Swift::SafeByteArray& password) {
if (!CONFIG_STRING(config, "service.admin_username").empty() && user.getNode() == CONFIG_STRING(config, "service.admin_username")) {
if (!CONFIG_STRING(config, "service.admin_jid").empty() && user.toBare().toString() == CONFIG_STRING(config, "service.admin_jid")) {
if (Swift::safeByteArrayToString(password) == CONFIG_STRING(config, "service.admin_password")) {
session->handlePasswordValid();
}