Merge remote branch 'upstream/master'
This commit is contained in:
commit
8152282868
32 changed files with 708 additions and 428 deletions
|
@ -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}")
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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 {
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -59,4 +59,4 @@ class VCardResponder : public Swift::Responder<Swift::VCard> {
|
|||
Swift::Timer::ref m_collectTimer;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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})
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
33
src/user.cpp
33
src/user.cpp
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue