Merge remote branch 'upstream/master'

This commit is contained in:
Daniel Henninger 2012-10-04 13:06:33 -04:00
commit 8152282868
32 changed files with 708 additions and 428 deletions

View file

@ -145,7 +145,12 @@ else(WIN32)
message(STATUS "Using non-multithreaded boost")
set(Boost_USE_MULTITHREADED 0)
endif(contains)
find_package(Boost COMPONENTS program_options date_time system filesystem regex thread-mt signals REQUIRED)
set(Boost_FIND_QUIETLY ON)
find_package(Boost COMPONENTS program_options date_time system filesystem regex thread-mt signals)
if (NOT Boost_FOUND)
set(Boost_FIND_QUIETLY OFF)
find_package(Boost COMPONENTS program_options date_time system filesystem regex thread signals REQUIRED)
endif()
endif(WIN32)
message( STATUS "Found Boost: ${Boost_LIBRARIES}, ${Boost_INCLUDE_DIR}")

View file

@ -10,9 +10,37 @@ DEFINE_LOGGER(logger, "IRCNetworkPlugin");
IRCNetworkPlugin::IRCNetworkPlugin(Config *config, Swift::QtEventLoop *loop, const std::string &host, int port) {
this->config = config;
m_currentServer = 0;
m_socket = new QTcpSocket();
m_socket->connectToHost(FROM_UTF8(host), port);
connect(m_socket, SIGNAL(readyRead()), this, SLOT(readData()));
std::string server = CONFIG_STRING_DEFAULTED(config, "service.irc_server", "");
if (!server.empty()) {
m_servers.push_back(server);
}
else {
std::list<std::string> list;
list = CONFIG_LIST_DEFAULTED(config, "service.irc_server", list);
m_servers.insert(m_servers.begin(), list.begin(), list.end());
}
if (CONFIG_HAS_KEY(config, "service.irc_identify")) {
m_identify = CONFIG_STRING(config, "service.irc_identify");
}
else {
m_identify = "NickServ identify $name $password";
}
}
void IRCNetworkPlugin::tryNextServer() {
if (!m_servers.empty()) {
int nextServer = (m_currentServer + 1) % m_servers.size();
LOG4CXX_INFO(logger, "Server " << m_servers[m_currentServer] << " disconnected user. Next server to try will be " << m_servers[nextServer]);
m_currentServer = nextServer;
}
}
void IRCNetworkPlugin::readData() {
@ -28,114 +56,156 @@ void IRCNetworkPlugin::sendData(const std::string &string) {
m_socket->write(string.c_str(), string.size());
}
MyIrcSession *IRCNetworkPlugin::createSession(const std::string &user, const std::string &hostname, const std::string &nickname, const std::string &password, const std::string &suffix) {
MyIrcSession *session = new MyIrcSession(user, this, suffix);
session->setUserName(FROM_UTF8(nickname));
session->setNickName(FROM_UTF8(nickname));
session->setRealName(FROM_UTF8(nickname));
session->setHost(FROM_UTF8(hostname));
session->setPort(6667);
session->setEncoding( "utf-8" );
if (!password.empty()) {
std::string identify = m_identify;
boost::replace_all(identify, "$password", password);
boost::replace_all(identify, "$name", nickname);
session->setIdentify(identify);
}
LOG4CXX_INFO(logger, user << ": Connecting " << hostname << " as " << nickname << ", suffix=" << suffix);
session->open();
return session;
}
void IRCNetworkPlugin::handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) {
// In server mode, hostname of the server we want to connect to is stored in "user" JID.
// In component mode we will connect user to the IRC network once he joins the room.
if (CONFIG_BOOL(config, "service.server_mode")) {
MyIrcSession *session = new MyIrcSession(user, this);
std::string h = user.substr(0, user.find("@"));
session->setNickName(FROM_UTF8(h.substr(0, h.find("%"))));
session->setHost(FROM_UTF8(h.substr(h.find("%") + 1)));
session->setPort(6667);
session->open();
LOG4CXX_INFO(logger, user << ": Connecting IRC network " << h.substr(h.find("%") + 1));
m_sessions[user] = session;
if (!m_servers.empty()) {
// legacy name is users nickname
if (m_sessions[user] != NULL) {
LOG4CXX_WARN(logger, user << ": Already logged in.");
return;
}
m_sessions[user] = createSession(user, m_servers[m_currentServer], legacyName, password, "");
}
else {
// We are waiting for first room join to connect user to IRC network, because we don't know which
// network he choose...
LOG4CXX_INFO(logger, user << ": Ready for connections");
handleConnected(user);
}
}
void IRCNetworkPlugin::handleLogoutRequest(const std::string &user, const std::string &legacyName) {
if (m_sessions[user] == NULL)
if (m_sessions[user] == NULL) {
LOG4CXX_WARN(logger, user << ": Already disconnected.");
return;
}
LOG4CXX_INFO(logger, user << ": Disconnecting.");
m_sessions[user]->close();
m_sessions[user]->deleteLater();
m_sessions.erase(user);
}
void IRCNetworkPlugin::handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &/*xhtml*/) {
std::string IRCNetworkPlugin::getSessionName(const std::string &user, const std::string &legacyName) {
std::string u = user;
if (!CONFIG_BOOL(config, "service.server_mode")) {
if (!CONFIG_BOOL(config, "service.server_mode") && m_servers.empty()) {
u = user + legacyName.substr(legacyName.find("@") + 1);
if (u.find("/") != std::string::npos) {
u = u.substr(0, u.find("/"));
}
}
if (m_sessions[u] == NULL) {
LOG4CXX_WARN(logger, user << ": Session name: " << u << ", No session for user");
return;
}
return u;
}
std::string IRCNetworkPlugin::getTargetName(const std::string &legacyName) {
std::string r = legacyName;
if (!CONFIG_BOOL(config, "service.server_mode")) {
// 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);
}
// }
return r;
}
void IRCNetworkPlugin::handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &/*xhtml*/) {
std::string session = getSessionName(user, legacyName);
if (m_sessions[session] == NULL) {
LOG4CXX_WARN(logger, user << ": Session name: " << session << ", No session for user");
return;
}
LOG4CXX_INFO(logger, user << ": Session name: " << u << ", message to " << r);
m_sessions[u]->sendCommand(IrcCommand::createMessage(FROM_UTF8(r), FROM_UTF8(message)));
std::string target = getTargetName(legacyName);
LOG4CXX_INFO(logger, user << ": Session name: " << session << ", message to " << target);
m_sessions[session]->sendCommand(IrcCommand::createMessage(FROM_UTF8(target), FROM_UTF8(message)));
if (target.find("#") == 0) {
handleMessage(user, legacyName, message, TO_UTF8(m_sessions[session]->nickName()));
}
}
void IRCNetworkPlugin::handleRoomSubjectChangedRequest(const std::string &user, const std::string &room, const std::string &message) {
std::string session = getSessionName(user, room);
if (m_sessions[session] == NULL) {
LOG4CXX_WARN(logger, user << ": Session name: " << session << ", No session for user");
return;
}
std::string target = getTargetName(room);
m_sessions[session]->sendCommand(IrcCommand::createTopic(FROM_UTF8(target), FROM_UTF8(message)));
}
void IRCNetworkPlugin::handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &password) {
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("@"));
}
std::string session = getSessionName(user, room);
std::string target = getTargetName(room);
LOG4CXX_INFO(logger, user << ": Session name: " << u << ", Joining room " << r);
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->setNickName(FROM_UTF8(nickname));
session->setHost(FROM_UTF8(room.substr(room.find("@") + 1)));
session->setPort(6667);
session->open();
LOG4CXX_INFO(logger, user << ": Connecting IRC network " << room.substr(room.find("@") + 1));
m_sessions[u] = session;
LOG4CXX_INFO(logger, user << ": Session name: " << session << ", Joining room " << target);
if (m_sessions[session] == NULL) {
if (m_servers.empty()) {
// 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
m_sessions[session] = createSession(user, room.substr(room.find("@") + 1), nickname, "", room.substr(room.find("@")));
}
else {
LOG4CXX_WARN(logger, user << ": There's no proper server defined in room to which this user wants to join: " << room);
return;
}
}
else {
LOG4CXX_WARN(logger, user << ": There's no proper server defined in room to which this user wants to join: " << room);
LOG4CXX_WARN(logger, user << ": Join room requested for unconnected user");
return;
}
}
m_sessions[u]->addAutoJoinChannel(r, password);
m_sessions[u]->sendCommand(IrcCommand::createJoin(FROM_UTF8(r), FROM_UTF8(password)));
m_sessions[u]->rooms += 1;
m_sessions[session]->addAutoJoinChannel(target, password);
m_sessions[session]->sendCommand(IrcCommand::createJoin(FROM_UTF8(target), FROM_UTF8(password)));
m_sessions[session]->rooms += 1;
// update nickname, because we have nickname per session, no nickname per room.
handleRoomNicknameChanged(user, r, TO_UTF8(m_sessions[u]->nickName()));
handleRoomNicknameChanged(user, target, TO_UTF8(m_sessions[session]->nickName()));
}
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);
}
std::string session = getSessionName(user, room);
std::string target = getTargetName(room);
if (m_sessions[u] == NULL)
LOG4CXX_INFO(logger, user << ": Session name: " << session << ", Leaving room " << target);
if (m_sessions[session] == NULL)
return;
LOG4CXX_INFO(logger, user << ": Session name: " << u << ", Leaving room " << r);
m_sessions[session]->sendCommand(IrcCommand::createPart(FROM_UTF8(target)));
m_sessions[session]->removeAutoJoinChannel(target);
m_sessions[session]->rooms -= 1;
m_sessions[u]->sendCommand(IrcCommand::createPart(FROM_UTF8(r)));
m_sessions[u]->removeAutoJoinChannel(r);
m_sessions[u]->rooms -= 1;
if (m_sessions[u]->rooms <= 0) {
LOG4CXX_INFO(logger, user << ": Session name: " << u << ", User is not in room, disconnecting from network");
m_sessions[u]->close();
m_sessions[u]->deleteLater();
m_sessions.erase(u);
if (m_sessions[session]->rooms <= 0 && m_servers.empty()) {
LOG4CXX_INFO(logger, user << ": Session name: " << session << ", User is not in any room, disconnecting from network");
m_sessions[session]->close();
m_sessions[session]->deleteLater();
m_sessions.erase(session);
}
}

View file

@ -26,12 +26,24 @@ class IRCNetworkPlugin : public QObject, public NetworkPlugin {
void handleLeaveRoomRequest(const std::string &user, const std::string &room);
void handleRoomSubjectChangedRequest(const std::string &user, const std::string &room, const std::string &message);
void tryNextServer();
public slots:
void readData();
void sendData(const std::string &string);
private:
MyIrcSession *createSession(const std::string &user, const std::string &hostname, const std::string &nickname, const std::string &password, const std::string &suffix = "");
std::string getSessionName(const std::string &user, const std::string &legacyName);
std::string getTargetName(const std::string &legacyName);
private:
Config *config;
QTcpSocket *m_socket;
std::map<std::string, MyIrcSession *> m_sessions;
std::vector<std::string> m_servers;
int m_currentServer;
std::string m_identify;
};

View file

@ -16,7 +16,6 @@
#include <QtNetwork>
#include "Swiften/EventLoop/Qt/QtEventLoop.h"
#include "ircnetworkplugin.h"
#include "singleircnetworkplugin.h"
using namespace boost::program_options;
using namespace Transport;
@ -40,12 +39,7 @@ int main (int argc, char* argv[]) {
Swift::QtEventLoop eventLoop;
if (!CONFIG_HAS_KEY(cfg, "service.irc_server")) {
np = new IRCNetworkPlugin(cfg, &eventLoop, host, port);
}
else {
np = new SingleIRCNetworkPlugin(cfg, &eventLoop, host, port);
}
np = new IRCNetworkPlugin(cfg, &eventLoop, host, port);
return app.exec();
}

View file

@ -14,6 +14,8 @@
#include <IrcCommand>
#include <IrcMessage>
#include "ircnetworkplugin.h"
#define FROM_UTF8(WHAT) QString::fromUtf8((WHAT).c_str(), (WHAT).size())
#define TO_UTF8(WHAT) std::string((WHAT).toUtf8().data(), (WHAT).toUtf8().size())
@ -21,7 +23,7 @@
DEFINE_LOGGER(logger, "IRCSession");
MyIrcSession::MyIrcSession(const std::string &user, NetworkPlugin *np, const std::string &suffix, QObject* parent) : IrcSession(parent)
MyIrcSession::MyIrcSession(const std::string &user, IRCNetworkPlugin *np, const std::string &suffix, QObject* parent) : IrcSession(parent)
{
this->np = np;
this->user = user;
@ -29,6 +31,7 @@ MyIrcSession::MyIrcSession(const std::string &user, NetworkPlugin *np, const std
m_connected = false;
rooms = 0;
connect(this, SIGNAL(disconnected()), SLOT(on_disconnected()));
connect(this, SIGNAL(socketError(QAbstractSocket::SocketError)), SLOT(on_socketError(QAbstractSocket::SocketError)));
connect(this, SIGNAL(connected()), SLOT(on_connected()));
connect(this, SIGNAL(messageReceived(IrcMessage*)), this, SLOT(onMessageReceived(IrcMessage*)));
}
@ -50,9 +53,15 @@ void MyIrcSession::on_connected() {
}
}
void MyIrcSession::on_socketError(QAbstractSocket::SocketError error) {
on_disconnected();
}
void MyIrcSession::on_disconnected() {
if (suffix.empty())
if (suffix.empty()) {
np->handleDisconnected(user, 0, "");
np->tryNextServer();
}
m_connected = false;
}
@ -161,7 +170,8 @@ void MyIrcSession::on_messageReceived(IrcMessage *message) {
bool flags = 0;
std::string nickname = TO_UTF8(m->sender().name());
flags = correctNickname(nickname);
np->handleMessage(user, nickname, TO_UTF8(m->message()));
LOG4CXX_INFO(logger, nickname + suffix);
np->handleMessage(user, nickname + suffix, TO_UTF8(m->message()));
}
}
@ -181,6 +191,7 @@ void MyIrcSession::on_numericMessageReceived(IrcMessage *message) {
channel = m->parameters().value(2);
members = m->parameters().value(3).split(" ");
LOG4CXX_INFO(logger, user << ": Received members for " << TO_UTF8(channel) << suffix);
for (int i = 0; i < members.size(); i++) {
bool flags = 0;
std::string nickname = TO_UTF8(members.at(i));
@ -190,9 +201,7 @@ void MyIrcSession::on_numericMessageReceived(IrcMessage *message) {
}
break;
case 432:
if (m_connected) {
np->handleDisconnected(user, pbnetwork::CONNECTION_ERROR_INVALID_USERNAME, "Erroneous Nickname");
}
np->handleDisconnected(user, pbnetwork::CONNECTION_ERROR_INVALID_USERNAME, "Erroneous Nickname");
break;
default:
break;

View file

@ -18,6 +18,8 @@
using namespace Transport;
class IRCNetworkPlugin;
class MyIrcSession : public IrcSession
{
Q_OBJECT
@ -37,7 +39,7 @@ public:
typedef std::map<std::string, boost::shared_ptr<AutoJoinChannel> > AutoJoinMap;
MyIrcSession(const std::string &user, NetworkPlugin *np, const std::string &suffix = "", QObject* parent = 0);
MyIrcSession(const std::string &user, IRCNetworkPlugin *np, const std::string &suffix = "", QObject* parent = 0);
std::map<std::string, bool> m_modes;
std::string suffix;
int rooms;
@ -72,11 +74,12 @@ public:
protected Q_SLOTS:
void on_connected();
void on_disconnected();
void on_socketError(QAbstractSocket::SocketError error);
void onMessageReceived(IrcMessage* message);
protected:
NetworkPlugin *np;
IRCNetworkPlugin *np;
std::string user;
std::string m_identify;
AutoJoinMap m_autoJoin;

View file

@ -1,138 +0,0 @@
#include "singleircnetworkplugin.h"
#include "transport/logging.h"
#include <IrcCommand>
#include <IrcMessage>
#define FROM_UTF8(WHAT) QString::fromUtf8((WHAT).c_str(), (WHAT).size())
#define TO_UTF8(WHAT) std::string((WHAT).toUtf8().data(), (WHAT).toUtf8().size())
DEFINE_LOGGER(logger, "SingleIRCNetworkPlugin");
SingleIRCNetworkPlugin::SingleIRCNetworkPlugin(Config *config, Swift::QtEventLoop *loop, const std::string &host, int port) {
this->config = config;
if (CONFIG_HAS_KEY(config, "service.irc_server")) {
m_server = CONFIG_STRING(config, "service.irc_server");
}
else {
LOG4CXX_ERROR(logger, "No [service] irc_server defined, exiting...");
exit(-1);
}
m_socket = new QTcpSocket();
m_socket->connectToHost(FROM_UTF8(host), port);
connect(m_socket, SIGNAL(readyRead()), this, SLOT(readData()));
if (CONFIG_HAS_KEY(config, "service.irc_identify")) {
m_identify = CONFIG_STRING(config, "service.irc_identify");
}
else {
m_identify = "NickServ identify $name $password";
}
LOG4CXX_INFO(logger, "SingleIRCNetworkPlugin for server " << m_server << " initialized.");
}
void SingleIRCNetworkPlugin::readData() {
size_t availableBytes = m_socket->bytesAvailable();
if (availableBytes == 0)
return;
std::string d = std::string(m_socket->readAll().data(), availableBytes);
handleDataRead(d);
}
void SingleIRCNetworkPlugin::sendData(const std::string &string) {
m_socket->write(string.c_str(), string.size());
}
void SingleIRCNetworkPlugin::handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) {
// legacy name is users nickname
if (m_sessions[user] != NULL) {
LOG4CXX_WARN(logger, user << ": Already logged in.");
return;
}
LOG4CXX_INFO(logger, user << ": Connecting " << m_server << " as " << legacyName);
MyIrcSession *session = new MyIrcSession(user, this);
session->setUserName(FROM_UTF8(legacyName));
session->setNickName(FROM_UTF8(legacyName));
session->setRealName(FROM_UTF8(legacyName));
session->setHost(FROM_UTF8(m_server));
session->setPort(6667);
session->setEncoding( "utf-8" );
if (!password.empty()) {
std::string identify = m_identify;
boost::replace_all(identify, "$password", password);
boost::replace_all(identify, "$name", legacyName);
session->setIdentify(identify);
}
session->open();
m_sessions[user] = session;
}
void SingleIRCNetworkPlugin::handleLogoutRequest(const std::string &user, const std::string &legacyName) {
if (m_sessions[user] == NULL) {
LOG4CXX_WARN(logger, user << ": Already disconnected.");
return;
}
LOG4CXX_INFO(logger, user << ": Disconnecting.");
m_sessions[user]->close();
m_sessions[user]->deleteLater();
m_sessions.erase(user);
}
void SingleIRCNetworkPlugin::handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &/*xhtml*/) {
if (m_sessions[user] == NULL) {
LOG4CXX_WARN(logger, user << ": Message received for unconnected user");
return;
}
// handle PMs
std::string r = legacyName;
if (legacyName.find("/") == std::string::npos) {
r = legacyName.substr(0, r.find("@"));
}
else {
r = legacyName.substr(legacyName.find("/") + 1);
}
LOG4CXX_INFO(logger, user << ": Forwarding message to " << r);
m_sessions[user]->sendCommand(IrcCommand::createMessage(FROM_UTF8(r), FROM_UTF8(message)));
if (r.find("#") == 0) {
handleMessage(user, legacyName, message, TO_UTF8(m_sessions[user]->nickName()));
}
}
void SingleIRCNetworkPlugin::handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &password) {
if (m_sessions[user] == NULL) {
LOG4CXX_WARN(logger, user << ": Join room requested for unconnected user");
return;
}
LOG4CXX_INFO(logger, user << ": Joining " << room);
m_sessions[user]->addAutoJoinChannel(room, password);
m_sessions[user]->sendCommand(IrcCommand::createJoin(FROM_UTF8(room), FROM_UTF8(password)));
m_sessions[user]->rooms += 1;
// update nickname, because we have nickname per session, no nickname per room.
handleRoomNicknameChanged(user, room, TO_UTF8(m_sessions[user]->userName()));
}
void SingleIRCNetworkPlugin::handleLeaveRoomRequest(const std::string &user, const std::string &room) {
std::string r = room;
std::string u = user;
if (m_sessions[u] == NULL) {
LOG4CXX_WARN(logger, user << ": Leave room requested for unconnected user");
return;
}
LOG4CXX_INFO(logger, user << ": Leaving " << room);
m_sessions[u]->sendCommand(IrcCommand::createPart(FROM_UTF8(r)));
m_sessions[u]->removeAutoJoinChannel(r);
m_sessions[u]->rooms -= 1;
}

View file

@ -1,40 +0,0 @@
#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 SingleIRCNetworkPlugin : public QObject, public NetworkPlugin {
Q_OBJECT
public:
SingleIRCNetworkPlugin(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;
std::string m_server;
std::string m_identify;
};

View file

@ -17,7 +17,9 @@
#include "geventloop.h"
// #include "valgrind/memcheck.h"
#ifndef __FreeBSD__
#include "malloc.h"
#endif
#include <algorithm>
#include "errno.h"
#include <boost/make_shared.hpp>
@ -364,8 +366,10 @@ class SpectrumNetworkPlugin : public NetworkPlugin {
purple_accounts_delete_wrapped(account);
#ifndef WIN32
#ifndef __FreeBSD__
malloc_trim(0);
#endif
#endif
// VALGRIND_DO_LEAK_CHECK;
}
}
@ -1459,8 +1463,10 @@ static void signed_on(PurpleConnection *gc, gpointer unused) {
PurpleAccount *account = purple_connection_get_account_wrapped(gc);
np->handleConnected(np->m_accounts[account]);
#ifndef WIN32
#ifndef __FreeBSD__
// force returning of memory chunks allocated by libxml2 to kernel
malloc_trim(0);
#endif
#endif
// For prpl-gg
@ -1648,8 +1654,10 @@ static void transportDataReceived(gpointer data, gint source, PurpleInputConditi
int main(int argc, char **argv) {
#ifndef WIN32
#ifndef __FreeBSD__
mallopt(M_CHECK_ACTION, 2);
mallopt(M_PERTURB, 0xb);
#endif
signal(SIGPIPE, SIG_IGN);

View file

@ -1,80 +0,0 @@
#include "userdb.h"
#if 0
DEFINE_LOGGER(logger, "Twitter Backend Database");
UserDB::UserDB(std::string database): errMsg(0), rc(0), dbOpen(false)
{
rc = sqlite3_open(database.c_str(), &db);
if( rc ) {
LOG4CXX_ERROR(logger, "Failed to open database" << database);
sqlite3_close(db);
exit(0);
}
LOG4CXX_INFO(logger, "Checking if table users is present")
if(exe(std::string("select * from users limit 1;")) != SQLITE_OK) {
exe("create table users (user text primarykey, key text, secret text);");
LOG4CXX_INFO(logger, "Created table users in the database");
}
dbOpen = true;
}
int UserDB::exe(std::string s_exe)
{
data.clear();
//LOG4CXX_INFO(logger, "Executing: " << s_exe)
rc = sqlite3_get_table(db, s_exe.c_str(), &result, &nRow, &nCol, &errMsg);
if( rc == SQLITE_OK ) {
int col = nCol; //Skip past the headers
for(int i = 0; i < nRow; ++i) {
std::vector<std::string> row;
for(int j = 0 ; j < nCol ; j++) row.push_back(result[col++]);
data.push_back(row);
}
}
sqlite3_free_table(result);
return rc;
}
void UserDB::insert(UserData info)
{
std::string q = "insert into users (user,key,secret) values ('" + info.user + "','" + info.accessTokenKey + "','" + info.accessTokenSecret + "');";
if(exe(q) != SQLITE_OK) {
LOG4CXX_ERROR(logger, "Failed to insert into database!");
exit(0);
}
}
void UserDB::fetch(std::string user, std::vector<std::string> &row)
{
std::string q = "select key,secret from users where user='" + user + "'";
if(exe(q) != SQLITE_OK) {
LOG4CXX_ERROR(logger, "Failed to fetch data from database!");
exit(0);
}
row = data[0];
}
std::set<std::string> UserDB::getRegisteredUsers()
{
std::string q = "select user from users";
if(exe(q) != SQLITE_OK) {
LOG4CXX_ERROR(logger, "Failed to registered users from database!");
exit(0);
}
std::set<std::string> users;
for(int i=0 ; i<data.size() ; i++)
users.insert(data[i][0]);
return users;
}
UserDB::~UserDB()
{
sqlite3_close(db);
}
#endif

View file

@ -1,48 +0,0 @@
#if 0
#ifndef USERDB_H
#define USERDB_H
#include <iostream>
#include <sqlite3.h>
#include <vector>
#include <set>
#include "transport/logging.h"
struct UserData
{
std::string user;
std::string accessTokenKey;
std::string accessTokenSecret;
UserData(){}
UserData(std::string _user, std::string key, std::string secret) {
user = _user;
accessTokenKey = key;
accessTokenSecret = secret;
}
};
class UserDB {
private:
sqlite3 *db;
char *errMsg;
char **result;
int rc;
int nRow,nCol;
bool dbOpen;
std::vector< std::vector<std::string> > data;
public:
UserDB (std::string database);
int exe(std::string s_exe);
void insert(UserData info);
void fetch(std::string user, std::vector<std::string> &row);
std::set<std::string> getRegisteredUsers();
~UserDB();
};
#endif
#endif

View file

@ -28,6 +28,20 @@
#include <boost/bind.hpp>
#include <boost/signal.hpp>
namespace Transport {
template <class myType>
const myType &safeAs(const boost::program_options::variable_value &var, const myType &def) {
try {
return var.as<myType>();
}
catch(...) {
return def;
}
}
}
#define CONFIG_HAS_KEY(PTR, KEY) (*PTR).hasKey(KEY)
#define CONFIG_STRING(PTR, KEY) (*PTR)[KEY].as<std::string>()
#define CONFIG_INT(PTR, KEY) (*PTR)[KEY].as<int>()
@ -35,9 +49,9 @@
#define CONFIG_LIST(PTR, KEY) (*PTR)[KEY].as<std::list<std::string> >()
#define CONFIG_VECTOR(PTR, KEY) ((*PTR).hasKey(KEY) ? (*PTR)[KEY].as<std::vector<std::string> >() : std::vector<std::string>())
#define CONFIG_STRING_DEFAULTED(PTR, KEY, DEF) ((*PTR).hasKey(KEY) ? (*PTR)[KEY].as<std::string>() : DEF)
#define CONFIG_BOOL_DEFAULTED(PTR, KEY, DEF) ((*PTR).hasKey(KEY) ? (*PTR)[KEY].as<bool>() : DEF)
#define CONFIG_STRING_DEFAULTED(PTR, KEY, DEF) ((*PTR).hasKey(KEY) ? Transport::safeAs<std::string>((*PTR)[KEY], DEF) : DEF)
#define CONFIG_BOOL_DEFAULTED(PTR, KEY, DEF) ((*PTR).hasKey(KEY) ? Transport::safeAs<bool>((*PTR)[KEY], DEF) : DEF)
#define CONFIG_LIST_DEFAULTED(PTR, KEY, DEF) ((*PTR).hasKey(KEY) ? Transport::safeAs<std::list<std::string> >((*PTR)[KEY], DEF) : DEF)
namespace Transport {

View file

@ -34,6 +34,12 @@ class ConversationManager;
/// Represents one XMPP-Legacy network conversation.
class Conversation {
public:
typedef struct _Participant {
int flag;
int status;
std::string statusMessage;
} Participant;
/// Type of participants in MUC rooms.
enum ParticipantFlag {None, Moderator};
@ -82,6 +88,18 @@ class Conversation {
m_jid = jid;
}
void addJID(const Swift::JID &jid) {
m_jids.push_back(jid);
}
void removeJID(const Swift::JID &jid) {
m_jids.remove(jid);
}
const std::list<Swift::JID> &getJIDs() {
return m_jids;
}
/// Sends message to Legacy network.
/// \param message Message.
@ -116,6 +134,11 @@ class Conversation {
void destroyRoom();
void sendParticipants(const Swift::JID &to);
private:
Swift::Presence::ref generatePresence(const std::string &nick, int flag, int status, const std::string &statusMessage, const std::string &newname = "");
private:
ConversationManager *m_conversationManager;
std::string m_legacyName;
@ -123,6 +146,8 @@ class Conversation {
std::string m_room;
bool m_muc;
Swift::JID m_jid;
std::list<Swift::JID> m_jids;
std::map<std::string, Participant> m_participants;
};
}

View file

@ -70,6 +70,7 @@ class ConversationManager {
void removeConversation(Conversation *conv);
void resetResources();
void removeJID(const Swift::JID &jid);
private:
void handleMessageReceived(Swift::Message::ref message);

View file

@ -218,6 +218,7 @@ class NetworkPlugin {
/// \param photo Raw photo data.
virtual void handleVCardUpdatedRequest(const std::string &/*user*/, const std::string &/*photo*/, const std::string &nickname) {}
virtual void handleRoomSubjectChangedRequest(const std::string &/*user*/, const std::string &/*room*/, const std::string &/*message*/) {}
virtual void handleJoinRoomRequest(const std::string &/*user*/, const std::string &/*room*/, const std::string &/*nickname*/, const std::string &/*pasword*/) {}
virtual void handleLeaveRoomRequest(const std::string &/*user*/, const std::string &/*room*/) {}
@ -260,6 +261,7 @@ class NetworkPlugin {
void handleFTFinishPayload(const std::string &payload);
void handleFTPausePayload(const std::string &payload);
void handleFTContinuePayload(const std::string &payload);
void handleRoomSubjectChangedPayload(const std::string &payload);
void send(const std::string &data);
void sendPong();

View file

@ -110,6 +110,10 @@ class User : public Swift::EntityCapsProvider {
return m_connected;
}
int getResourceCount() {
return m_resources;
}
boost::signal<void ()> onReadyToConnect;
boost::signal<void (Swift::Presence::ref presence)> onPresenceChanged;
boost::signal<void (const Swift::JID &who, const std::string &room, const std::string &nickname, const std::string &password)> onRoomJoined;

View file

@ -59,4 +59,4 @@ class VCardResponder : public Swift::Responder<Swift::VCard> {
Swift::Timer::ref m_collectTimer;
};
}
}

View file

@ -374,6 +374,16 @@ void NetworkPlugin::handleConvMessagePayload(const std::string &data) {
handleMessageSendRequest(payload.username(), payload.buddyname(), payload.message(), payload.xhtml());
}
void NetworkPlugin::handleRoomSubjectChangedPayload(const std::string &data) {
pbnetwork::ConversationMessage payload;
if (payload.ParseFromString(data) == false) {
// TODO: ERROR
return;
}
handleRoomSubjectChangedRequest(payload.username(), payload.buddyname(), payload.message());
}
void NetworkPlugin::handleAttentionPayload(const std::string &data) {
pbnetwork::ConversationMessage payload;
if (payload.ParseFromString(data) == false) {
@ -550,6 +560,9 @@ void NetworkPlugin::handleDataRead(std::string &data) {
case pbnetwork::WrapperMessage_Type_TYPE_CONV_MESSAGE:
handleConvMessagePayload(wrapper.payload());
break;
case pbnetwork::WrapperMessage_Type_TYPE_ROOM_SUBJECT_CHANGED:
handleRoomSubjectChangedPayload(wrapper.payload());
break;
case pbnetwork::WrapperMessage_Type_TYPE_JOIN_ROOM:
handleJoinRoomPayload(wrapper.payload());
break;

View file

@ -195,7 +195,7 @@ int start_instances(ManagerConfig *config, const std::string &_jid) {
}
}
catch (const filesystem_error& ex) {
std::cerr << "boost filesystem error\n";
std::cerr << "Filesystem error: " << ex.what() << "\n";
return 6;
}
return rv;
@ -271,7 +271,7 @@ void stop_instances(ManagerConfig *config, const std::string &_jid) {
}
}
catch (const filesystem_error& ex) {
std::cerr << "boost filesystem error\n";
std::cerr << "Filesystem error: " << ex.what() << "\n";
exit(5);
}
}
@ -324,7 +324,7 @@ int show_status(ManagerConfig *config) {
}
}
catch (const filesystem_error& ex) {
std::cerr << "boost filesystem error\n";
std::cerr << "Filesystem error: " << ex.what() << "\n";
exit(5);
}
return ret;
@ -460,7 +460,7 @@ void ask_local_server(ManagerConfig *config, Swift::BoostNetworkFactories &netwo
}
}
catch (const filesystem_error& ex) {
std::cerr << "boost filesystem error\n";
std::cerr << "Filesystem error: " << ex.what() << "\n";
exit(5);
}
}
@ -498,7 +498,7 @@ std::vector<std::string> show_list(ManagerConfig *config, bool show) {
}
}
catch (const filesystem_error& ex) {
std::cerr << "boost filesystem error\n";
std::cerr << "Filesystem error: " << ex.what() << "\n";
}
return list;
}

View file

@ -38,11 +38,11 @@ else(PROTOBUF_FOUND)
ADD_LIBRARY(transport SHARED ${HEADERS} ${SRC} ${SWIFTEN_SRC})
endif(PROTOBUF_FOUND)
if (CMAKE_COMPILER_IS_GNUCXX)
# if (CMAKE_COMPILER_IS_GNUCXX)
if (NOT WIN32)
ADD_DEFINITIONS(-fPIC)
endif()
endif()
# endif()
if (WIN32)
TARGET_LINK_LIBRARIES(transport transport-plugin sqlite3 ${PQXX_LIBRARY} ${PQ_LIBRARY} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES} ${PROTOBUF_LIBRARY})

View file

@ -135,18 +135,6 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description
;
// Load configs passed by command line
if (m_argc != 0 && m_argv) {
basic_command_line_parser<char> parser = command_line_parser(m_argc, m_argv).options(opts).allow_unregistered();
parsed_options parsed = parser.run();
BOOST_FOREACH(option &opt, parsed.options) {
if (opt.unregistered && !opt.value.empty()) {
m_unregistered[opt.string_key] = variable_value(opt.value[0], false);
}
}
store(parsed, m_variables);
}
parsed_options parsed = parse_config_file(ifs, opts, true);
bool found_working = false;
@ -212,15 +200,43 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description
parsed.options.push_back(boost::program_options::basic_option<char>("database.database", value));
}
std::list<std::string> has_key;
BOOST_FOREACH(option &opt, parsed.options) {
if (opt.unregistered) {
m_unregistered[opt.string_key] = variable_value(opt.value[0], false);
if (std::find(has_key.begin(), has_key.end(), opt.string_key) == has_key.end()) {
has_key.push_back(opt.string_key);
m_unregistered[opt.string_key] = variable_value(opt.value[0], false);
}
else {
std::list<std::string> list;
try {
list = m_unregistered[opt.string_key].as<std::list<std::string> >();
}
catch(...) {
list.push_back(m_unregistered[opt.string_key].as<std::string>());
}
list.push_back(opt.value[0]);
m_unregistered[opt.string_key] = variable_value(list, false);
}
}
else if (opt.value[0].find("$jid") != std::string::npos) {
boost::replace_all(opt.value[0], "$jid", jid);
}
}
// Load configs passed by command line
if (m_argc != 0 && m_argv) {
basic_command_line_parser<char> parser = command_line_parser(m_argc, m_argv).options(opts).allow_unregistered();
parsed_options parsed = parser.run();
BOOST_FOREACH(option &opt, parsed.options) {
if (opt.unregistered && !opt.value.empty()) {
m_unregistered[opt.string_key] = variable_value(opt.value[0], false);
}
}
store(parsed, m_variables);
}
store(parsed, m_variables);
notify(m_variables);

View file

@ -55,6 +55,10 @@ void Conversation::destroyRoom() {
Swift::MUCUserPayload *p = new Swift::MUCUserPayload ();
p->addItem(item);
Swift::MUCUserPayload::StatusCode c;
c.code = 332;
p->addStatusCode(c);
presence->addPayload(boost::shared_ptr<Swift::Payload>(p));
m_conversationManager->getComponent()->getStanzaChannel()->sendPresence(presence);
}
@ -111,13 +115,23 @@ void Conversation::handleMessage(boost::shared_ptr<Swift::Message> &message, con
if (n.empty()) {
n = " ";
}
message->setTo(m_jid);
message->setFrom(Swift::JID(legacyName, m_conversationManager->getComponent()->getJID().toBare(), n));
m_conversationManager->getComponent()->getStanzaChannel()->sendMessage(message);
BOOST_FOREACH(const Swift::JID &jid, m_jids) {
message->setTo(jid);
message->setFrom(Swift::JID(legacyName, m_conversationManager->getComponent()->getJID().toBare(), n));
m_conversationManager->getComponent()->getStanzaChannel()->sendMessage(message);
}
}
}
void Conversation::handleParticipantChanged(const std::string &nick, int flag, int status, const std::string &statusMessage, const std::string &newname) {
void Conversation::sendParticipants(const Swift::JID &to) {
for (std::map<std::string, Participant>::iterator it = m_participants.begin(); it != m_participants.end(); it++) {
Swift::Presence::ref presence = generatePresence(it->first, it->second.flag, it->second.status, it->second.statusMessage, "");
presence->setTo(to);
m_conversationManager->getComponent()->getStanzaChannel()->sendPresence(presence);
}
}
Swift::Presence::ref Conversation::generatePresence(const std::string &nick, int flag, int status, const std::string &statusMessage, const std::string &newname) {
std::string nickname = nick;
Swift::Presence::ref presence = Swift::Presence::create();
std::string legacyName = m_legacyName;
@ -127,7 +141,6 @@ void Conversation::handleParticipantChanged(const std::string &nick, int flag, i
}
}
presence->setFrom(Swift::JID(legacyName, m_conversationManager->getComponent()->getJID().toBare(), nickname));
presence->setTo(m_jid);
presence->setType(Swift::Presence::Available);
if (!statusMessage.empty())
@ -168,9 +181,29 @@ void Conversation::handleParticipantChanged(const std::string &nick, int flag, i
}
p->addItem(item);
presence->addPayload(boost::shared_ptr<Swift::Payload>(p));
m_conversationManager->getComponent()->getStanzaChannel()->sendPresence(presence);
return presence;
}
void Conversation::handleParticipantChanged(const std::string &nick, int flag, int status, const std::string &statusMessage, const std::string &newname) {
Swift::Presence::ref presence = generatePresence(nick, flag, status, statusMessage, newname);
if (presence->getType() == Swift::Presence::Unavailable) {
m_participants.erase(nick);
}
else {
Participant p;
p.flag = flag;
p.status = status;
p.statusMessage = statusMessage;
m_participants[nick] = p;
}
BOOST_FOREACH(const Swift::JID &jid, m_jids) {
presence->setTo(jid);
m_conversationManager->getComponent()->getStanzaChannel()->sendPresence(presence);
}
if (!newname.empty()) {
handleParticipantChanged(newname, flag, status, statusMessage);
}

View file

@ -89,6 +89,12 @@ void ConversationManager::resetResources() {
}
}
void ConversationManager::removeJID(const Swift::JID &jid) {
for (std::map<std::string, Conversation *>::const_iterator it = m_convs.begin(); it != m_convs.end(); it++) {
(*it).second->removeJID(jid);
}
}
void ConversationManager::handleMessageReceived(Swift::Message::ref message) {
// std::string name = message->getTo().getUnescapedNode();
// if (name.find_last_of("%") != std::string::npos) { // OK when commented

View file

@ -56,6 +56,8 @@
#else
#include "sys/wait.h"
#include "sys/signal.h"
#include <sys/types.h>
#include <signal.h>
#include "popt.h"
#endif
@ -1192,7 +1194,7 @@ void NetworkPluginServer::handleRoomJoined(User *user, const Swift::JID &who, co
user->getConversationManager()->addConversation(conv);
conv->onMessageToSend.connect(boost::bind(&NetworkPluginServer::handleMessageReceived, this, _1, _2));
conv->setNickname(nickname);
conv->setJID(who);
conv->addJID(who);
}
void NetworkPluginServer::handleRoomLeft(User *user, const std::string &r) {
@ -1301,6 +1303,22 @@ void NetworkPluginServer::handleMessageReceived(NetworkConversation *conv, boost
send(c->connection, message);
return;
}
if (!msg->getSubject().empty()) {
pbnetwork::ConversationMessage m;
m.set_username(conv->getConversationManager()->getUser()->getJID().toBare());
m.set_buddyname(conv->getLegacyName());
m.set_message(msg->getSubject());
std::string message;
m.SerializeToString(&message);
WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_ROOM_SUBJECT_CHANGED);
Backend *c = (Backend *) conv->getConversationManager()->getUser()->getData();
send(c->connection, message);
return;
}
std::string xhtml;

View file

@ -41,7 +41,7 @@ using namespace Transport;
void BasicTest::setMeUp (void) {
streamEnded = false;
std::istringstream ifs("service.server_mode = 1\nservice.jid=localhost");
std::istringstream ifs("service.server_mode = 1\nservice.jid=localhost\nservice.more_resources=1\n");
cfg = new Config();
cfg->load(ifs);
@ -86,6 +86,7 @@ void BasicTest::setMeUp (void) {
payloadSerializers->addSerializer(new Swift::GatewayPayloadSerializer());
parser = new Swift::XMPPParser(this, payloadParserFactories, factories->getXMLParserFactory());
parser2 = 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")));
@ -95,13 +96,19 @@ void BasicTest::setMeUp (void) {
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'>");
parser2->parse("<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='localhost' version='1.0'>");
received.clear();
received2.clear();
receivedData.clear();
loop->processEvents();
}
void BasicTest::tearMeDown (void) {
dynamic_cast<Swift::ServerStanzaChannel *>(component->getStanzaChannel())->removeSession(serverFromClientSession);
if (serverFromClientSession2) {
dynamic_cast<Swift::ServerStanzaChannel *>(component->getStanzaChannel())->removeSession(serverFromClientSession2);
serverFromClientSession2.reset();
}
delete component;
delete userRegistry;
delete factories;
@ -109,29 +116,48 @@ void BasicTest::tearMeDown (void) {
delete loop;
delete cfg;
delete parser;
delete parser2;
delete storage;
delete userRegistration;
delete itemsResponder;
received.clear();
received2.clear();
receivedData.clear();
receivedData2.clear();
}
void BasicTest::handleDataReceived(const Swift::SafeByteArray &data) {
// std::cout << safeByteArrayToString(data) << "\n";
stream1_active = true;
receivedData += safeByteArrayToString(data) + "\n";
parser->parse(safeByteArrayToString(data));
}
void BasicTest::handleDataReceived2(const Swift::SafeByteArray &data) {
// std::cout << safeByteArrayToString(data) << "\n";
stream1_active = false;
receivedData2 += safeByteArrayToString(data) + "\n";
parser2->parse(safeByteArrayToString(data));
}
void BasicTest::handleStreamStart(const Swift::ProtocolHeader&) {
}
void BasicTest::dumpReceived() {
std::cout << "\nStream1:\n";
std::cout << receivedData << "\n";
std::cout << "Stream2:\n";
std::cout << receivedData2 << "\n";
}
void BasicTest::handleElement(boost::shared_ptr<Swift::Element> element) {
received.push_back(element);
if (stream1_active) {
received.push_back(element);
}
else {
received2.push_back(element);
}
}
void BasicTest::handleStreamEnd() {
@ -159,6 +185,7 @@ Swift::Stanza *BasicTest::getStanza(boost::shared_ptr<Swift::Element> element) {
void BasicTest::connectUser() {
CPPUNIT_ASSERT_EQUAL(0, userManager->getUserCount());
userRegistry->isValidUserPassword(Swift::JID("user@localhost/resource"), serverFromClientSession.get(), Swift::createSafeByteArray("password"));
userRegistry->onPasswordValid(Swift::JID("user@localhost/resource"));
loop->processEvents();
CPPUNIT_ASSERT_EQUAL(1, userManager->getUserCount());
@ -173,9 +200,39 @@ void BasicTest::connectUser() {
user->setConnected(true);
CPPUNIT_ASSERT(user->isConnected() == true);
CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
CPPUNIT_ASSERT_EQUAL(2, (int) received.size());
CPPUNIT_ASSERT(getStanza(received[0])->getPayload<Swift::DiscoInfo>());
received.clear();
receivedData.clear();
}
void BasicTest::connectSecondResource() {
serverFromClientSession2 = boost::shared_ptr<Swift::ServerFromClientSession>(new Swift::ServerFromClientSession("id", factories->getConnectionFactory()->createConnection(),
payloadParserFactories, payloadSerializers, userRegistry, factories->getXMLParserFactory(), Swift::JID("user@localhost/resource2")));
serverFromClientSession2->startSession();
serverFromClientSession2->onDataWritten.connect(boost::bind(&BasicTest::handleDataReceived2, this, _1));
dynamic_cast<Swift::ServerStanzaChannel *>(component->getStanzaChannel())->addSession(serverFromClientSession2);
userRegistry->isValidUserPassword(Swift::JID("user@localhost/resource2"), serverFromClientSession2.get(), Swift::createSafeByteArray("password"));
userRegistry->onPasswordValid(Swift::JID("user@localhost/resource2"));
loop->processEvents();
Swift::Presence::ref response = Swift::Presence::create();
response->setTo("localhost");
response->setFrom("user@localhost/resource2");
injectPresence(response);
loop->processEvents();
CPPUNIT_ASSERT_EQUAL(1, userManager->getUserCount());
User *user = userManager->getUser("user@localhost");
CPPUNIT_ASSERT(user);
CPPUNIT_ASSERT_EQUAL(2, user->getResourceCount());
CPPUNIT_ASSERT(getStanza(received2[1])->getPayload<Swift::DiscoInfo>());
}
void BasicTest::disconnectUser() {

View file

@ -205,6 +205,7 @@ class BasicTest : public Swift::XMPPParserClient {
void tearMeDown (void);
void handleDataReceived(const Swift::SafeByteArray &data);
void handleDataReceived2(const Swift::SafeByteArray &data);
void handleStreamStart(const Swift::ProtocolHeader&);
@ -228,6 +229,7 @@ class BasicTest : public Swift::XMPPParserClient {
}
void connectUser();
void connectSecondResource();
void disconnectUser();
void add2Buddies();
@ -237,9 +239,11 @@ class BasicTest : public Swift::XMPPParserClient {
bool streamEnded;
UserManager *userManager;
boost::shared_ptr<Swift::ServerFromClientSession> serverFromClientSession;
boost::shared_ptr<Swift::ServerFromClientSession> serverFromClientSession2;
Swift::FullPayloadSerializerCollection* payloadSerializers;
Swift::FullPayloadParserFactoryCollection* payloadParserFactories;
Swift::XMPPParser *parser;
Swift::XMPPParser *parser2;
UserRegistry *userRegistry;
Config *cfg;
Swift::Server *server;
@ -248,9 +252,12 @@ class BasicTest : public Swift::XMPPParserClient {
TestingFactory *factory;
Component *component;
std::vector<boost::shared_ptr<Swift::Element> > received;
std::vector<boost::shared_ptr<Swift::Element> > received2;
std::string receivedData;
std::string receivedData2;
StorageBackend *storage;
UserRegistration *userRegistration;
DiscoItemsResponder *itemsResponder;
bool stream1_active;
};

View file

@ -24,7 +24,12 @@ using namespace Transport;
class ConfigTest : public CPPUNIT_NS :: TestFixture{
CPPUNIT_TEST_SUITE(ConfigTest);
CPPUNIT_TEST(setStringTwice);
CPPUNIT_TEST(updateBackendConfig);
CPPUNIT_TEST(unregisteredList);
CPPUNIT_TEST(unregisteredString);
CPPUNIT_TEST(unregisteredListAsString);
CPPUNIT_TEST(unregisteredStringAsList);
CPPUNIT_TEST_SUITE_END();
public:
@ -35,6 +40,14 @@ class ConfigTest : public CPPUNIT_NS :: TestFixture{
}
void setStringTwice() {
char *argv[3] = {"binary", "--service.jids=localhost", NULL};
Config cfg(2, argv);
std::istringstream ifs("service.jids = irc.freenode.org\n");
cfg.load(ifs);
CPPUNIT_ASSERT_EQUAL(std::string("localhost"), CONFIG_STRING(&cfg, "service.jids"));
}
void updateBackendConfig() {
Config cfg;
CPPUNIT_ASSERT(!cfg.hasKey("registration.needPassword"));
@ -44,6 +57,35 @@ class ConfigTest : public CPPUNIT_NS :: TestFixture{
CPPUNIT_ASSERT_EQUAL(false, CONFIG_BOOL(&cfg, "registration.needPassword"));
}
void unregisteredList() {
Config cfg;
std::istringstream ifs("service.irc_server = irc.freenode.org\nservice.irc_server=localhost\n");
cfg.load(ifs);
CPPUNIT_ASSERT_EQUAL(2, (int) CONFIG_LIST(&cfg, "service.irc_server").size());
}
void unregisteredString() {
Config cfg;
std::istringstream ifs("service.irc_server = irc.freenode.org");
cfg.load(ifs);
CPPUNIT_ASSERT_EQUAL(std::string("irc.freenode.org"), CONFIG_STRING(&cfg, "service.irc_server"));
}
void unregisteredListAsString() {
Config cfg;
std::istringstream ifs("service.irc_server = irc.freenode.orgn\nservice.irc_server = irc2.freenode.org");
cfg.load(ifs);
CPPUNIT_ASSERT_EQUAL(std::string(""), CONFIG_STRING_DEFAULTED(&cfg, "service.irc_server", ""));
}
void unregisteredStringAsList() {
Config cfg;
std::istringstream ifs("service.irc_server = irc.freenode.org");
cfg.load(ifs);
std::list<std::string> list;
CPPUNIT_ASSERT_EQUAL(0, (int) CONFIG_LIST_DEFAULTED(&cfg, "service.irc_server", list).size());
}
};
CPPUNIT_TEST_SUITE_REGISTRATION (ConfigTest);

View file

@ -25,8 +25,11 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe
CPPUNIT_TEST_SUITE(ConversationManagerTest);
CPPUNIT_TEST(handleNormalMessages);
CPPUNIT_TEST(handleGroupchatMessages);
CPPUNIT_TEST(handleGroupchatMessagesTwoResources);
CPPUNIT_TEST(handleChatstateMessages);
CPPUNIT_TEST(handleSubjectMessages);
CPPUNIT_TEST(handleParticipantChanged);
CPPUNIT_TEST(handleParticipantChangedTwoResources);
CPPUNIT_TEST(handlePMFromXMPP);
CPPUNIT_TEST(handleGroupchatRemoved);
CPPUNIT_TEST_SUITE_END();
@ -89,6 +92,38 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe
received.clear();
}
void handleSubjectMessages() {
User *user = userManager->getUser("user@localhost");
TestingConversation *conv = new TestingConversation(user->getConversationManager(), "buddy1");
user->getConversationManager()->addConversation(conv);
conv->onMessageToSend.connect(boost::bind(&ConversationManagerTest::handleMessageReceived, this, _1, _2));
boost::shared_ptr<Swift::Message> msg(new Swift::Message());
msg->setSubject("subject");
// Forward it
conv->handleMessage(msg);
loop->processEvents();
CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
CPPUNIT_ASSERT(dynamic_cast<Swift::Message *>(getStanza(received[0])));
CPPUNIT_ASSERT_EQUAL(std::string("subject"), dynamic_cast<Swift::Message *>(getStanza(received[0]))->getSubject());
received.clear();
// send response
msg->setFrom("user@localhost/resource");
msg->setTo("buddy1@localhost/bot");
injectMessage(msg);
loop->processEvents();
CPPUNIT_ASSERT_EQUAL(0, (int) received.size());
CPPUNIT_ASSERT(m_msg);
CPPUNIT_ASSERT_EQUAL(std::string("subject"), m_msg->getSubject());
received.clear();
}
void handleNormalMessages() {
User *user = userManager->getUser("user@localhost");
@ -158,7 +193,7 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe
user->getConversationManager()->addConversation(conv);
conv->onMessageToSend.connect(boost::bind(&ConversationManagerTest::handleMessageReceived, this, _1, _2));
conv->setNickname("nickname");
conv->setJID("user@localhost/resource");
conv->addJID("user@localhost/resource");
// reset resources should not touch this resource
user->getConversationManager()->resetResources();
@ -191,13 +226,55 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe
CPPUNIT_ASSERT_EQUAL(std::string("response!"), m_msg->getBody());
}
void handleGroupchatMessagesTwoResources() {
connectSecondResource();
received2.clear();
User *user = userManager->getUser("user@localhost");
TestingConversation *conv = new TestingConversation(user->getConversationManager(), "#room", true);
user->getConversationManager()->addConversation(conv);
conv->onMessageToSend.connect(boost::bind(&ConversationManagerTest::handleMessageReceived, this, _1, _2));
conv->setNickname("nickname");
conv->addJID("user@localhost/resource");
conv->addJID("user@localhost/resource2");
// reset resources should not touch this resource
user->getConversationManager()->resetResources();
boost::shared_ptr<Swift::Message> msg(new Swift::Message());
msg->setBody("hi there!");
// Forward it
conv->handleMessage(msg, "anotheruser");
loop->processEvents();
CPPUNIT_ASSERT_EQUAL(1, (int) received2.size());
CPPUNIT_ASSERT(dynamic_cast<Swift::Message *>(getStanza(received2[0])));
CPPUNIT_ASSERT_EQUAL(std::string("hi there!"), dynamic_cast<Swift::Message *>(getStanza(received2[0]))->getBody());
CPPUNIT_ASSERT_EQUAL(std::string("user@localhost/resource2"), dynamic_cast<Swift::Message *>(getStanza(received2[0]))->getTo().toString());
CPPUNIT_ASSERT_EQUAL(std::string("#room@localhost/anotheruser"), dynamic_cast<Swift::Message *>(getStanza(received2[0]))->getFrom().toString());
received.clear();
// send response
msg->setFrom("user@localhost/resource2");
msg->setTo("#room@localhost");
msg->setBody("response!");
msg->setType(Swift::Message::Groupchat);
injectMessage(msg);
loop->processEvents();
CPPUNIT_ASSERT_EQUAL(0, (int) received.size());
CPPUNIT_ASSERT(m_msg);
CPPUNIT_ASSERT_EQUAL(std::string("response!"), m_msg->getBody());
}
void handleParticipantChanged() {
User *user = userManager->getUser("user@localhost");
TestingConversation *conv = new TestingConversation(user->getConversationManager(), "#room", true);
conv->onMessageToSend.connect(boost::bind(&ConversationManagerTest::handleMessageReceived, this, _1, _2));
conv->setNickname("nickname");
conv->setJID("user@localhost/resource");
conv->addJID("user@localhost/resource");
// normal presence
conv->handleParticipantChanged("anotheruser", 0, Swift::StatusShow::Away, "my status message");
@ -246,6 +323,31 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe
CPPUNIT_ASSERT_EQUAL(303, getStanza(received[0])->getPayload<Swift::MUCUserPayload>()->getStatusCodes()[0].code);
}
void handleParticipantChangedTwoResources() {
connectSecondResource();
received2.clear();
User *user = userManager->getUser("user@localhost");
TestingConversation *conv = new TestingConversation(user->getConversationManager(), "#room", true);
conv->onMessageToSend.connect(boost::bind(&ConversationManagerTest::handleMessageReceived, this, _1, _2));
conv->setNickname("nickname");
conv->addJID("user@localhost/resource");
conv->addJID("user@localhost/resource2");
// normal presence
conv->handleParticipantChanged("anotheruser", 0, Swift::StatusShow::Away, "my status message");
loop->processEvents();
CPPUNIT_ASSERT_EQUAL(1, (int) received2.size());
CPPUNIT_ASSERT(dynamic_cast<Swift::Presence *>(getStanza(received2[0])));
CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::Away, dynamic_cast<Swift::Presence *>(getStanza(received2[0]))->getShow());
CPPUNIT_ASSERT_EQUAL(std::string("user@localhost/resource2"), dynamic_cast<Swift::Presence *>(getStanza(received2[0]))->getTo().toString());
CPPUNIT_ASSERT_EQUAL(std::string("#room@localhost/anotheruser"), dynamic_cast<Swift::Presence *>(getStanza(received2[0]))->getFrom().toString());
CPPUNIT_ASSERT(getStanza(received2[0])->getPayload<Swift::MUCUserPayload>());
CPPUNIT_ASSERT_EQUAL(Swift::MUCOccupant::Member, *getStanza(received2[0])->getPayload<Swift::MUCUserPayload>()->getItems()[0].affiliation);
CPPUNIT_ASSERT_EQUAL(Swift::MUCOccupant::Participant, *getStanza(received2[0])->getPayload<Swift::MUCUserPayload>()->getItems()[0].role);
}
void handlePMFromXMPP() {
User *user = userManager->getUser("user@localhost");
TestingConversation *conv = new TestingConversation(user->getConversationManager(), "#room", true);
@ -293,6 +395,7 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe
CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::None, dynamic_cast<Swift::Presence *>(getStanza(received[0]))->getShow());
CPPUNIT_ASSERT_EQUAL(std::string("user@localhost/resource"), dynamic_cast<Swift::Presence *>(getStanza(received[0]))->getTo().toString());
CPPUNIT_ASSERT_EQUAL(std::string("#room@localhost/nickname"), dynamic_cast<Swift::Presence *>(getStanza(received[0]))->getFrom().toString());
CPPUNIT_ASSERT_EQUAL(332, getStanza(received[0])->getPayload<Swift::MUCUserPayload>()->getStatusCodes()[0].code);
}
};

View file

@ -25,7 +25,10 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
CPPUNIT_TEST(sendCurrentPresence);
CPPUNIT_TEST(handlePresence);
CPPUNIT_TEST(handlePresenceJoinRoom);
CPPUNIT_TEST(handlePresenceJoinRoomTwoResources);
CPPUNIT_TEST(handlePresenceLeaveRoom);
CPPUNIT_TEST(handlePresenceLeaveRoomTwoResources);
CPPUNIT_TEST(handlePresenceLeaveRoomTwoResourcesOneDisconnects);
CPPUNIT_TEST(leaveJoinedRoom);
CPPUNIT_TEST(handleDisconnected);
CPPUNIT_TEST(handleDisconnectedReconnect);
@ -139,6 +142,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
// simulate that backend joined the room
TestingConversation *conv = new TestingConversation(user->getConversationManager(), "#room", true);
conv->addJID("user@localhost/resource");
user->getConversationManager()->addConversation(conv);
received.clear();
@ -154,6 +158,41 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
CPPUNIT_ASSERT_EQUAL(std::string(""), roomPassword);
}
void handlePresenceJoinRoomTwoResources() {
handlePresenceJoinRoom();
User *user = userManager->getUser("user@localhost");
// Add 1 participant
Conversation *conv = user->getConversationManager()->getConversation("#room");
conv->handleParticipantChanged("anotheruser", 0, Swift::StatusShow::Away, "my status message");
// Connect 2nd resource
connectSecondResource();
received2.clear();
Swift::Presence::ref response = Swift::Presence::create();
response->setTo("#room@localhost/hanzz");
response->setFrom("user@localhost/resource2");
Swift::MUCPayload *payload = new Swift::MUCPayload();
payload->setPassword("password");
response->addPayload(boost::shared_ptr<Swift::Payload>(payload));
injectPresence(response);
loop->processEvents();
CPPUNIT_ASSERT_EQUAL(std::string(""), room);
CPPUNIT_ASSERT_EQUAL(std::string(""), roomNickname);
CPPUNIT_ASSERT_EQUAL(std::string(""), roomPassword);
CPPUNIT_ASSERT_EQUAL(2, (int) received2.size());
CPPUNIT_ASSERT(dynamic_cast<Swift::Presence *>(getStanza(received2[1])));
CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::Away, dynamic_cast<Swift::Presence *>(getStanza(received2[1]))->getShow());
CPPUNIT_ASSERT_EQUAL(std::string("user@localhost/resource2"), dynamic_cast<Swift::Presence *>(getStanza(received2[1]))->getTo().toString());
CPPUNIT_ASSERT_EQUAL(std::string("#room@localhost/anotheruser"), dynamic_cast<Swift::Presence *>(getStanza(received2[1]))->getFrom().toString());
CPPUNIT_ASSERT(getStanza(received2[1])->getPayload<Swift::MUCUserPayload>());
CPPUNIT_ASSERT_EQUAL(Swift::MUCOccupant::Member, *getStanza(received2[1])->getPayload<Swift::MUCUserPayload>()->getItems()[0].affiliation);
CPPUNIT_ASSERT_EQUAL(Swift::MUCOccupant::Participant, *getStanza(received2[1])->getPayload<Swift::MUCUserPayload>()->getItems()[0].role);
}
void handlePresenceLeaveRoom() {
Swift::Presence::ref response = Swift::Presence::create();
response->setTo("#room@localhost/hanzz");
@ -173,6 +212,71 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
CPPUNIT_ASSERT_EQUAL(std::string(""), roomPassword);
}
void handlePresenceLeaveRoomTwoResources() {
handlePresenceJoinRoomTwoResources();
received.clear();
// User is still connected from resource2, so he should not leave the room
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);
CPPUNIT_ASSERT_EQUAL(std::string(""), roomNickname);
CPPUNIT_ASSERT_EQUAL(std::string(""), roomPassword);
// disconnect also from resource
// User is still connected from resource2, so he should not leave the room
response = Swift::Presence::create();
response->setTo("#room@localhost/hanzz");
response->setFrom("user@localhost/resource2");
response->setType(Swift::Presence::Unavailable);
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 handlePresenceLeaveRoomTwoResourcesOneDisconnects() {
handlePresenceJoinRoomTwoResources();
received.clear();
User *user = userManager->getUser("user@localhost");
// User is still connected from resource2, so he should not leave the room
Swift::Presence::ref response = Swift::Presence::create();
response->setTo("localhost/hanzz");
response->setFrom("user@localhost/resource");
response->setType(Swift::Presence::Unavailable);
injectPresence(response);
loop->processEvents();
CPPUNIT_ASSERT_EQUAL(std::string(""), room);
CPPUNIT_ASSERT_EQUAL(std::string(""), roomNickname);
CPPUNIT_ASSERT_EQUAL(std::string(""), roomPassword);
Conversation *conv = user->getConversationManager()->getConversation("#room");
CPPUNIT_ASSERT_EQUAL(1, (int) conv->getJIDs().size());
CPPUNIT_ASSERT_EQUAL(Swift::JID("user@localhost/resource2"), conv->getJIDs().front());
}
void leaveJoinedRoom() {
User *user = userManager->getUser("user@localhost");
handlePresenceJoinRoom();

View file

@ -23,6 +23,7 @@ using namespace Transport;
class UserManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
CPPUNIT_TEST_SUITE(UserManagerTest);
CPPUNIT_TEST(connectUser);
CPPUNIT_TEST(connectTwoResources);
CPPUNIT_TEST(connectUserTransportDisabled);
CPPUNIT_TEST(connectUserRegistrationNeeded);
CPPUNIT_TEST(connectUserRegistrationNeededRegistered);
@ -86,6 +87,22 @@ class UserManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
CPPUNIT_ASSERT_EQUAL(Swift::Presence::Unavailable, presence->getType());
}
void connectTwoResources() {
connectUser();
add2Buddies();
connectSecondResource();
// we should get presences
CPPUNIT_ASSERT_EQUAL(4, (int) received2.size());
CPPUNIT_ASSERT(dynamic_cast<Swift::Presence *>(getStanza(received2[2])));
CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::Away, dynamic_cast<Swift::Presence *>(getStanza(received2[2]))->getShow());
CPPUNIT_ASSERT_EQUAL(std::string("status1"), dynamic_cast<Swift::Presence *>(getStanza(received2[2]))->getStatus());
CPPUNIT_ASSERT(dynamic_cast<Swift::Presence *>(getStanza(received2[3])));
CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::Away, dynamic_cast<Swift::Presence *>(getStanza(received2[3]))->getShow());
CPPUNIT_ASSERT_EQUAL(std::string("status2"), dynamic_cast<Swift::Presence *>(getStanza(received2[3]))->getStatus());
}
};
CPPUNIT_TEST_SUITE_REGISTRATION (UserManagerTest);

View file

@ -218,10 +218,17 @@ void User::handlePresence(Swift::Presence::ref presence) {
if (isMUC) {
if (presence->getType() == Swift::Presence::Unavailable) {
std::string room = Buddy::JIDToLegacyName(presence->getTo());
Conversation *conv = m_conversationManager->getConversation(room);
if (conv) {
conv->removeJID(presence->getFrom());
if (!conv->getJIDs().empty()) {
return;
}
}
LOG4CXX_INFO(logger, m_jid.toString() << ": Going to left room " << room);
onRoomLeft(room);
Conversation *conv = m_conversationManager->getConversation(room);
if (conv) {
m_conversationManager->removeConversation(conv);
delete conv;
@ -235,8 +242,15 @@ void User::handlePresence(Swift::Presence::ref presence) {
onReadyToConnect();
}
std::string room = Buddy::JIDToLegacyName(presence->getTo());
if (m_conversationManager->getConversation(room) != NULL) {
LOG4CXX_INFO(logger, m_jid.toString() << ": User has already tried to join room " << room << " as " << presence->getTo().getResource());
Conversation *conv = m_conversationManager->getConversation(room);
if (conv != NULL) {
if (std::find(conv->getJIDs().begin(), conv->getJIDs().end(), presence->getFrom()) != conv->getJIDs().end()) {
LOG4CXX_INFO(logger, m_jid.toString() << ": User has already tried to join room " << room << " as " << presence->getTo().getResource());
}
else {
conv->addJID(presence->getFrom());
conv->sendParticipants(presence->getFrom());
}
return;
}
@ -249,6 +263,10 @@ void User::handlePresence(Swift::Presence::ref presence) {
}
return;
}
if (presence->getType() == Swift::Presence::Unavailable) {
m_conversationManager->removeJID(presence->getFrom());
}
// User wants to disconnect this resource
@ -266,13 +284,14 @@ void User::handlePresence(Swift::Presence::ref presence) {
}
else {
sendCurrentPresence();
// This resource is new, so we have to send buddies presences
if (currentResourcesCount != m_resources) {
m_rosterManager->sendCurrentPresences(presence->getFrom());
}
}
}
// This resource is new, so we have to send buddies presences
if (presence->getType() != Swift::Presence::Unavailable && currentResourcesCount != m_resources) {
m_rosterManager->sendCurrentPresences(presence->getFrom());
}
m_resources = currentResourcesCount;

View file

@ -31,7 +31,9 @@
#include "Swiften/Swiften.h"
#include "Swiften/Server/ServerStanzaChannel.h"
#include "Swiften/Elements/StreamError.h"
#ifndef __FreeBSD__
#include "malloc.h"
#endif
// #include "valgrind/memcheck.h"
namespace Transport {
@ -124,8 +126,10 @@ void UserManager::removeUser(User *user, bool onUserBehalf) {
onUserDestroyed(user);
delete user;
#ifndef WIN32
#ifndef __FreeBSD__
malloc_trim(0);
#endif
#endif
// VALGRIND_DO_LEAK_CHECK;
}
@ -340,7 +344,7 @@ void UserManager::handleMessageReceived(Swift::Message::ref message) {
messageToBackendSent();
}
if (message->getBody().empty() && !statePayload) {
if (message->getBody().empty() && !statePayload && message->getSubject().empty()) {
return;
}