Merge remote-tracking branch 'hanzz/origin/master'

This commit is contained in:
Vitaly Takmazov 2011-11-25 12:05:45 +04:00
commit eaa28f6599
76 changed files with 1658 additions and 943 deletions

View file

@ -44,8 +44,8 @@ message( STATUS "Found Boost: ${Boost_LIBRARIES}, ${Boost_INCLUDE_DIR}")
set(Protobuf_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
find_package(Protobuf REQUIRED)
set(IRCClientQt_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
find_package(IRCClientQt)
set(Communi_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
find_package(Communi)
set(log4cxx_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
find_package(log4cxx)
@ -64,6 +64,25 @@ ADD_DEFINITIONS(-DBOOST_FILESYSTEM_VERSION=2)
message(" Supported features")
message("-----------------------")
if (SPECTRUM_VERSION)
ADD_DEFINITIONS(-DSPECTRUM_VERSION="${SPECTRUM_VERSION}")
else (SPECTRUM_VERSION)
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git)
execute_process(COMMAND git "--git-dir=${CMAKE_CURRENT_SOURCE_DIR}/.git" rev-parse --short HEAD
OUTPUT_VARIABLE GIT_REVISION
OUTPUT_STRIP_TRAILING_WHITESPACE
)
set(SPECTRUM_VERSION 2.0.0-beta-git-${GIT_REVISION})
ADD_DEFINITIONS(-DSPECTRUM_VERSION="${SPECTRUM_VERSION}")
else (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git)
set(SPECTRUM_VERSION 2.0.0-alpha)
ADD_DEFINITIONS(-DSPECTRUM_VERSION="${SPECTRUM_VERSION}")
endif (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git)
endif (SPECTRUM_VERSION)
message("Version : " ${SPECTRUM_VERSION})
if (SQLITE3_FOUND)
ADD_DEFINITIONS(-DWITH_SQLITE)
include_directories(${SQLITE3_INCLUDE_DIR})
@ -104,13 +123,13 @@ if (PROTOBUF_FOUND)
endif()
if(IRC_FOUND)
ADD_DEFINITIONS(-DIRC_SHARED)
ADD_DEFINITIONS(-DCOMMUNI_SHARED)
message("IRC plugin : yes")
include_directories(${QT_QTNETWORK_INCLUDE_DIR})
include_directories(${IRC_INCLUDE_DIR})
include(${QT_USE_FILE})
else()
message("IRC plugin : no (install libircclient-qt and libprotobuf-dev)")
message("IRC plugin : no (install libCommuni and libprotobuf-dev)")
endif()
message("Frotz plugin : yes")
@ -170,10 +189,8 @@ include_directories(${OPENSSL_INCLUDE_DIR})
ADD_SUBDIRECTORY(src)
ADD_SUBDIRECTORY(plugin)
ADD_SUBDIRECTORY(include)
#ADD_SUBDIRECTORY(examples)
ADD_SUBDIRECTORY(spectrum)
ADD_SUBDIRECTORY(backends)
#ADD_SUBDIRECTORY(tests)
if (NOT WIN32)
ADD_SUBDIRECTORY(spectrum_manager)
endif()

6
README
View file

@ -0,0 +1,6 @@
Spectrum is an XMPP transport/gateway. It allows XMPP users to communicate with
their friends who are using one of the supported networks. It supports a wide
range of different networks such as ICQ, XMPP (Jabber, GTalk), AIM, MSN,
Facebook, Twitter, Gadu-Gadu, IRC and SIMPLE. Spectrum is written in C++
and uses the Swiften XMPP library and libpurple for “legacy networks”.
Spectrum is open source and released under the GNU GPL.

View file

@ -4,7 +4,7 @@ if (PROTOBUF_FOUND)
endif()
if (IRC_FOUND)
ADD_SUBDIRECTORY(libircclient-qt)
ADD_SUBDIRECTORY(libcommuni)
endif()
if (NOT WIN32)

View file

@ -0,0 +1,10 @@
cmake_minimum_required(VERSION 2.6)
FILE(GLOB SRC *.cpp)
FILE(GLOB HEADERS *.h)
QT4_WRAP_CPP(SRC ${HEADERS})
ADD_EXECUTABLE(spectrum2_libcommuni_backend ${SRC})
target_link_libraries(spectrum2_libcommuni_backend ${IRC_LIBRARY} ${QT_LIBRARIES} transport-plugin transport pthread)
INSTALL(TARGETS spectrum2_libcommuni_backend RUNTIME DESTINATION bin)

View file

@ -1,4 +1,6 @@
#include "ircnetworkplugin.h"
#include <IrcCommand>
#include <IrcMessage>
IRCNetworkPlugin::IRCNetworkPlugin(Config *config, Swift::QtEventLoop *loop, const std::string &host, int port) {
this->config = config;
@ -26,8 +28,10 @@ void IRCNetworkPlugin::handleLoginRequest(const std::string &user, const std::st
if (CONFIG_BOOL(config, "service.server_mode")) {
MyIrcSession *session = new MyIrcSession(user, this);
std::string h = user.substr(0, user.find("@"));
session->setNick(QString::fromStdString(h.substr(0, h.find("%"))));
session->connectToServer(QString::fromStdString(h.substr(h.find("%") + 1)), 6667);
session->setNickName(QString::fromStdString(h.substr(0, h.find("%"))));
session->setHost(QString::fromStdString(h.substr(h.find("%") + 1)));
session->setPort(6667);
session->open();
std::cout << "CONNECTING IRC NETWORK " << h.substr(h.find("%") + 1) << "\n";
m_sessions[user] = session;
}
@ -39,7 +43,7 @@ void IRCNetworkPlugin::handleLoginRequest(const std::string &user, const std::st
void IRCNetworkPlugin::handleLogoutRequest(const std::string &user, const std::string &legacyName) {
if (m_sessions[user] == NULL)
return;
m_sessions[user]->disconnectFromServer();
m_sessions[user]->close();
m_sessions[user]->deleteLater();
m_sessions.erase(user);
}
@ -68,7 +72,7 @@ void IRCNetworkPlugin::handleMessageSendRequest(const std::string &user, const s
}
}
std::cout << "MESSAGE " << u << " " << r << "\n";
m_sessions[u]->message(QString::fromStdString(r), QString::fromStdString(message));
m_sessions[u]->sendCommand(IrcCommand::createMessage(QString::fromStdString(r), QString::fromStdString(message)));
std::cout << "SENT\n";
}
@ -85,8 +89,10 @@ void IRCNetworkPlugin::handleJoinRoomRequest(const std::string &user, const std:
if (room.find("@") != std::string::npos) {
// suffix is %irc.freenode.net to let MyIrcSession return #room%irc.freenode.net
MyIrcSession *session = new MyIrcSession(user, this, room.substr(room.find("@")));
session->setNick(QString::fromStdString(nickname));
session->connectToServer(QString::fromStdString(room.substr(room.find("@") + 1)), 6667);
session->setNickName(QString::fromStdString(nickname));
session->setHost(QString::fromStdString(room.substr(room.find("@") + 1)));
session->setPort(6667);
session->open();
std::cout << "CONNECTING IRC NETWORK " << room.substr(room.find("@") + 1) << "\n";
std::cout << "SUFFIX " << room.substr(room.find("@")) << "\n";
m_sessions[u] = session;
@ -96,11 +102,11 @@ void IRCNetworkPlugin::handleJoinRoomRequest(const std::string &user, const std:
}
}
std::cout << "JOINING " << r << "\n";
m_sessions[u]->addAutoJoinChannel(QString::fromStdString(r));
m_sessions[u]->join(QString::fromStdString(r), QString::fromStdString(password));
m_sessions[u]->addAutoJoinChannel(r);
m_sessions[u]->sendCommand(IrcCommand::createJoin(QString::fromStdString(r), QString::fromStdString(password)));
m_sessions[u]->rooms += 1;
// update nickname, because we have nickname per session, no nickname per room.
handleRoomNicknameChanged(user, r, m_sessions[u]->nick().toStdString());
handleRoomNicknameChanged(user, r, m_sessions[u]->nickName().toStdString());
}
void IRCNetworkPlugin::handleLeaveRoomRequest(const std::string &user, const std::string &room) {
@ -114,12 +120,12 @@ void IRCNetworkPlugin::handleLeaveRoomRequest(const std::string &user, const std
if (m_sessions[u] == NULL)
return;
m_sessions[u]->part(QString::fromStdString(r));
m_sessions[u]->removeAutoJoinChannel(QString::fromStdString(r));
m_sessions[u]->sendCommand(IrcCommand::createPart(QString::fromStdString(r)));
m_sessions[u]->removeAutoJoinChannel(r);
m_sessions[u]->rooms -= 1;
if (m_sessions[u]->rooms <= 0) {
m_sessions[u]->disconnectFromServer();
m_sessions[u]->close();
m_sessions[u]->deleteLater();
m_sessions.erase(u);
}

View file

@ -15,11 +15,22 @@
#include <QtNetwork>
#include "Swiften/EventLoop/Qt/QtEventLoop.h"
#include "ircnetworkplugin.h"
#include "singleircnetworkplugin.h"
#include "log4cxx/logger.h"
#include "log4cxx/consoleappender.h"
#include "log4cxx/patternlayout.h"
#include "log4cxx/propertyconfigurator.h"
#include "log4cxx/helpers/properties.h"
#include "log4cxx/helpers/fileinputstream.h"
#include "log4cxx/helpers/transcoder.h"
using namespace boost::program_options;
using namespace Transport;
IRCNetworkPlugin * np = NULL;
using namespace log4cxx;
NetworkPlugin * np = NULL;
int main (int argc, char* argv[]) {
std::string host;
@ -72,8 +83,39 @@ int main (int argc, char* argv[]) {
}
QCoreApplication app(argc, argv);
if (CONFIG_STRING(&config, "logging.backend_config").empty()) {
LoggerPtr root = log4cxx::Logger::getRootLogger();
#ifndef _MSC_VER
root->addAppender(new ConsoleAppender(new PatternLayout("%d %-5p %c: %m%n")));
#else
root->addAppender(new ConsoleAppender(new PatternLayout(L"%d %-5p %c: %m%n")));
#endif
}
else {
log4cxx::helpers::Properties p;
log4cxx::helpers::FileInputStream *istream = new log4cxx::helpers::FileInputStream(CONFIG_STRING(&config, "logging.backend_config"));
p.load(istream);
LogString pid, jid;
log4cxx::helpers::Transcoder::decode(boost::lexical_cast<std::string>(getpid()), pid);
log4cxx::helpers::Transcoder::decode(CONFIG_STRING(&config, "service.jid"), jid);
#ifdef _MSC_VER
p.setProperty(L"pid", pid);
p.setProperty(L"jid", jid);
#else
p.setProperty("pid", pid);
p.setProperty("jid", jid);
#endif
log4cxx::PropertyConfigurator::configure(p);
}
Swift::QtEventLoop eventLoop;
np = new IRCNetworkPlugin(&config, &eventLoop, host, port);
if (config.getUnregistered().find("service.irc_server") == config.getUnregistered().end()) {
np = new IRCNetworkPlugin(&config, &eventLoop, host, port);
}
else {
np = new SingleIRCNetworkPlugin(&config, &eventLoop, host, port);
}
return app.exec();
}

View file

@ -0,0 +1,212 @@
/*
* Copyright (C) 2008-2009 J-P Nurmi jpnurmi@gmail.com
*
* This example is free, and not covered by LGPL license. There is no
* restriction applied to their modification, redistribution, using and so on.
* You can study them, modify them, use them in your own program - either
* completely or partially. By using it you may give me some credits in your
* program, but you don't have to.
*/
#include "session.h"
#include <QtCore>
#include <iostream>
#include "Swiften/Elements/StatusShow.h"
#include <IrcCommand>
#include <IrcMessage>
#include "log4cxx/logger.h"
using namespace log4cxx;
static LoggerPtr logger = log4cxx::Logger::getLogger("IRCSession");
MyIrcSession::MyIrcSession(const std::string &user, NetworkPlugin *np, const std::string &suffix, QObject* parent) : IrcSession(parent)
{
this->np = np;
this->user = user;
this->suffix = suffix;
rooms = 0;
connect(this, SIGNAL(disconnected()), SLOT(on_disconnected()));
connect(this, SIGNAL(connected()), SLOT(on_connected()));
connect(this, SIGNAL(messageReceived(IrcMessage*)), this, SLOT(onMessageReceived(IrcMessage*)));
}
void MyIrcSession::on_connected() {
if (suffix.empty()) {
np->handleConnected(user);
}
for(std::list<std::string>::const_iterator it = m_autoJoin.begin(); it != m_autoJoin.end(); it++) {
sendCommand(IrcCommand::createJoin(QString::fromStdString(*it)));
}
if (getIdentify().find(" ") != std::string::npos) {
std::string to = getIdentify().substr(0, getIdentify().find(" "));
std::string what = getIdentify().substr(getIdentify().find(" ") + 1);
sendCommand(IrcCommand::createMessage(QString::fromStdString(to), QString::fromStdString(what)));
}
}
void MyIrcSession::on_disconnected() {
if (suffix.empty())
np->handleDisconnected(user, 0, "");
}
bool MyIrcSession::correctNickname(std::string &nickname) {
bool flags = 0;
switch(nickname.at(0)) {
case '@': nickname = nickname.substr(1); flags = 1; break;
case '+': nickname = nickname.substr(1); break;
default: break;
}
return flags;
}
void MyIrcSession::on_joined(IrcMessage *message) {
IrcJoinMessage *m = (IrcJoinMessage *) message;
bool flags = 0;
std::string nickname = m->sender().name().toStdString();
flags = correctNickname(nickname);
np->handleParticipantChanged(user, nickname, m->channel().toStdString() + suffix, (int) flags, pbnetwork::STATUS_ONLINE);
LOG4CXX_INFO(logger, user << ": Joined " << m->parameters()[0].toStdString());
}
void MyIrcSession::on_parted(IrcMessage *message) {
IrcPartMessage *m = (IrcPartMessage *) message;
bool flags = 0;
std::string nickname = m->sender().name().toStdString();
flags = correctNickname(nickname);
LOG4CXX_INFO(logger, user << ": " << nickname << " parted " << m->channel().toStdString() + suffix);
np->handleParticipantChanged(user, nickname, m->channel().toStdString() + suffix,(int) flags, pbnetwork::STATUS_NONE, m->reason().toStdString());
}
void MyIrcSession::on_quit(IrcMessage *message) {
IrcQuitMessage *m = (IrcQuitMessage *) message;
for(std::list<std::string>::const_iterator it = m_autoJoin.begin(); it != m_autoJoin.end(); it++) {
bool flags = 0;
std::string nickname = m->sender().name().toStdString();
flags = correctNickname(nickname);
LOG4CXX_INFO(logger, user << ": " << nickname << " quit " << (*it) + suffix);
np->handleParticipantChanged(user, nickname, (*it) + suffix,(int) flags, pbnetwork::STATUS_NONE, m->reason().toStdString());
}
}
void MyIrcSession::on_nickChanged(IrcMessage *message) {
IrcNickMessage *m = (IrcNickMessage *) message;
for(std::list<std::string>::const_iterator it = m_autoJoin.begin(); it != m_autoJoin.end(); it++) {
std::string nickname = m->sender().name().toStdString();
bool flags = m_modes[(*it) + nickname];
LOG4CXX_INFO(logger, user << ": " << nickname << " changed nickname to " << m->nick().toStdString());
np->handleParticipantChanged(user, nickname, (*it) + suffix,(int) flags, pbnetwork::STATUS_ONLINE, "", m->nick().toStdString());
}
}
void MyIrcSession::on_modeChanged(IrcMessage *message) {
IrcModeMessage *m = (IrcModeMessage *) message;
// mode changed: "#testik" "HanzZ" "+o" "hanzz_k"
std::string nickname = m->argument().toStdString();
std::string mode = m->mode().toStdString();
if (nickname.empty())
return;
LOG4CXX_INFO(logger, user << ": " << nickname << " changed mode to " << mode);
for(std::list<std::string>::const_iterator it = m_autoJoin.begin(); it != m_autoJoin.end(); it++) {
if (mode == "+o") {
m_modes[(*it) + nickname] = 1;
}
else {
m_modes[(*it) + nickname] = 0;
}
bool flags = m_modes[(*it) + nickname];
np->handleParticipantChanged(user, nickname, (*it) + suffix,(int) flags, pbnetwork::STATUS_ONLINE, "");
}
}
void MyIrcSession::on_topicChanged(IrcMessage *message) {
IrcTopicMessage *m = (IrcTopicMessage *) message;
bool flags = 0;
std::string nickname = m->sender().name().toStdString();
flags = correctNickname(nickname);
LOG4CXX_INFO(logger, user << ": " << nickname << " topic changed to " << m->topic().toStdString());
np->handleSubject(user, m->channel().toStdString() + suffix, m->topic().toStdString(), nickname);
}
void MyIrcSession::on_messageReceived(IrcMessage *message) {
IrcPrivateMessage *m = (IrcPrivateMessage *) message;
std::string target = m->target().toStdString();
LOG4CXX_INFO(logger, user << ": Message from " << target);
if (target.find("#") == 0) {
bool flags = 0;
std::string nickname = m->sender().name().toStdString();
flags = correctNickname(nickname);
np->handleMessage(user, target + suffix, m->message().toStdString(), nickname);
}
else {
bool flags = 0;
std::string nickname = m->sender().name().toStdString();
flags = correctNickname(nickname);
np->handleMessage(user, nickname, m->message().toStdString());
}
}
void MyIrcSession::on_numericMessageReceived(IrcMessage *message) {
IrcNumericMessage *m = (IrcNumericMessage *) message;
switch (m->code()) {
case 332:
m_topicData = m->parameters().value(2).toStdString();
break;
case 333:
np->handleSubject(user, m->parameters().value(1).toStdString() + suffix, m_topicData, m->parameters().value(2).toStdString());
break;
case 353:
QString channel = m->parameters().value(2);
QStringList members = m->parameters().value(3).split(" ");
for (int i = 0; i < members.size(); i++) {
bool flags = 0;
std::string nickname = members.at(i).toStdString();
flags = correctNickname(nickname);
m_modes[channel.toStdString() + nickname] = flags;
np->handleParticipantChanged(user, nickname, channel.toStdString() + suffix,(int) flags, pbnetwork::STATUS_ONLINE);
}
break;
}
//qDebug() << "numeric message received:" << receiver() << origin << code << params;
}
void MyIrcSession::onMessageReceived(IrcMessage *message) {
LOG4CXX_INFO(logger, user << ": " << message->toString().toStdString());
switch (message->type()) {
case IrcMessage::Join:
on_joined(message);
break;
case IrcMessage::Part:
on_parted(message);
break;
case IrcMessage::Quit:
on_quit(message);
break;
case IrcMessage::Nick:
on_nickChanged(message);
break;
case IrcMessage::Mode:
on_modeChanged(message);
break;
case IrcMessage::Topic:
on_topicChanged(message);
break;
case IrcMessage::Private:
on_messageReceived(message);
break;
case IrcMessage::Numeric:
on_numericMessageReceived(message);
break;
}
}

View file

@ -0,0 +1,103 @@
/*
* Copyright (C) 2008-2009 J-P Nurmi jpnurmi@gmail.com
*
* This example is free, and not covered by LGPL license. There is no
* restriction applied to their modification, redistribution, using and so on.
* You can study them, modify them, use them in your own program - either
* completely or partially. By using it you may give me some credits in your
* program, but you don't have to.
*/
#ifndef SESSION_H
#define SESSION_H
#include <IrcSession>
#include <transport/networkplugin.h>
using namespace Transport;
class MyIrcSession : public IrcSession
{
Q_OBJECT
public:
MyIrcSession(const std::string &user, NetworkPlugin *np, const std::string &suffix = "", QObject* parent = 0);
std::map<std::string, bool> m_modes;
std::string suffix;
int rooms;
void addAutoJoinChannel(const std::string &channel) {
m_autoJoin.push_back(channel);
}
void removeAutoJoinChannel(const std::string &channel) {
m_autoJoin.remove(channel);
}
void setIdentify(const std::string &identify) {
m_identify = identify;
}
const std::string &getIdentify() {
return m_identify;
}
bool correctNickname(std::string &nickname);
void on_joined(IrcMessage *message);
void on_parted(IrcMessage *message);
void on_quit(IrcMessage *message);
void on_nickChanged(IrcMessage *message);
void on_modeChanged(IrcMessage *message);
void on_topicChanged(IrcMessage *message);
void on_messageReceived(IrcMessage *message);
void on_numericMessageReceived(IrcMessage *message);
protected Q_SLOTS:
void on_connected();
void on_disconnected();
void onMessageReceived(IrcMessage* message);
protected:
NetworkPlugin *np;
std::string user;
std::string m_identify;
std::list<std::string> m_autoJoin;
std::string m_topicData;
};
//class MyIrcBuffer : public Irc::Buffer
//{
// Q_OBJECT
//public:
// MyIrcBuffer(const QString& receiver, const std::string &user, NetworkPlugin *np, const std::string &suffix, Irc::Session* parent);
// NetworkPlugin *np;
// std::string user;
// MyIrcSession *p;
// std::string m_topicData;
// std::string suffix;
//protected Q_SLOTS:
// void on_receiverChanged(const QString& receiver);
// void on_joined(const QString& origin);
// void on_parted(const QString& origin, const QString& message);
// void on_quit(const QString& origin, const QString& message);
// void on_nickChanged(const QString& origin, const QString& nick);
// void on_modeChanged(const QString& origin, const QString& mode, const QString& args);
// void on_topicChanged(const QString& origin, const QString& topic);
// void on_invited(const QString& origin, const QString& receiver, const QString& channel);
// void on_kicked(const QString& origin, const QString& nick, const QString& message);
// void on_messageReceived(const QString& origin, const QString& message, Irc::Buffer::MessageFlags flags);
// void on_noticeReceived(const QString& origin, const QString& notice, Irc::Buffer::MessageFlags flags);
// void on_ctcpRequestReceived(const QString& origin, const QString& request, Irc::Buffer::MessageFlags flags);
// void on_ctcpReplyReceived(const QString& origin, const QString& reply, Irc::Buffer::MessageFlags flags);
// void on_ctcpActionReceived(const QString& origin, const QString& action, Irc::Buffer::MessageFlags flags);
// void on_numericMessageReceived(const QString& origin, uint code, const QStringList& params);
// void on_unknownMessageReceived(const QString& origin, const QStringList& params);
// bool correctNickname(std::string &nickname);
//};
#endif // SESSION_H

View file

@ -0,0 +1,128 @@
#include "singleircnetworkplugin.h"
#include "log4cxx/logger.h"
#include <IrcCommand>
#include <IrcMessage>
using namespace log4cxx;
static LoggerPtr logger = log4cxx::Logger::getLogger("SingleIRCNetworkPlugin");
SingleIRCNetworkPlugin::SingleIRCNetworkPlugin(Config *config, Swift::QtEventLoop *loop, const std::string &host, int port) {
this->config = config;
m_server = config->getUnregistered().find("service.irc_server")->second;
m_socket = new QTcpSocket();
m_socket->connectToHost(QString::fromStdString(host), port);
connect(m_socket, SIGNAL(readyRead()), this, SLOT(readData()));
if (config->getUnregistered().find("service.irc_identify") != config->getUnregistered().end()) {
m_identify = config->getUnregistered().find("service.irc_identify")->second;
}
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(QString::fromStdString(legacyName));
session->setNickName(QString::fromStdString(legacyName));
session->setRealName(QString::fromStdString(legacyName));
session->setHost(QString::fromStdString(m_server));
session->setPort(6667);
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(QString::fromStdString(r), QString::fromStdString(message)));
if (r.find("#") == 0) {
handleMessage(user, legacyName, message, m_sessions[user]->nickName().toStdString());
}
}
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);
m_sessions[user]->sendCommand(IrcCommand::createJoin(QString::fromStdString(room), QString::fromStdString(password)));
m_sessions[user]->rooms += 1;
// update nickname, because we have nickname per session, no nickname per room.
handleRoomNicknameChanged(user, room, m_sessions[user]->userName().toStdString());
}
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(QString::fromStdString(r)));
m_sessions[u]->removeAutoJoinChannel(r);
m_sessions[u]->rooms -= 1;
}

View file

@ -0,0 +1,40 @@
#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

@ -1,10 +0,0 @@
cmake_minimum_required(VERSION 2.6)
FILE(GLOB SRC *.cpp)
FILE(GLOB HEADERS *.h)
QT4_WRAP_CPP(SRC ${HEADERS})
ADD_EXECUTABLE(spectrum2_libircclient-qt_backend ${SRC})
target_link_libraries(spectrum2_libircclient-qt_backend ${IRC_LIBRARY} ${QT_LIBRARIES} transport-plugin transport pthread)
INSTALL(TARGETS spectrum2_libircclient-qt_backend RUNTIME DESTINATION bin)

View file

@ -1,232 +0,0 @@
/*
* Copyright (C) 2008-2009 J-P Nurmi jpnurmi@gmail.com
*
* This example is free, and not covered by LGPL license. There is no
* restriction applied to their modification, redistribution, using and so on.
* You can study them, modify them, use them in your own program - either
* completely or partially. By using it you may give me some credits in your
* program, but you don't have to.
*/
#include "session.h"
#include <QtCore>
#include <iostream>
#include "Swiften/Elements/StatusShow.h"
MyIrcSession::MyIrcSession(const std::string &user, NetworkPlugin *np, const std::string &suffix, QObject* parent) : Irc::Session(parent)
{
this->np = np;
this->user = user;
this->suffix = suffix;
rooms = 0;
connect(this, SIGNAL(disconnected()), SLOT(on_disconnected()));
}
void MyIrcSession::on_connected(){
std::cout << "connected:\n";
}
void MyIrcSession::on_disconnected()
{
std::cout << "disconnected:\n";
if (suffix.empty())
np->handleDisconnected(user, 0, "");
}
void MyIrcSession::on_bufferAdded(Irc::Buffer* buffer)
{
qDebug() << "buffer added:" << buffer->receiver();
}
void MyIrcSession::on_bufferRemoved(Irc::Buffer* buffer)
{
qDebug() << "buffer removed:" << buffer->receiver();
}
Irc::Buffer* MyIrcSession::createBuffer(const QString& receiver)
{
return new MyIrcBuffer(receiver, user, np, suffix, this);
}
MyIrcBuffer::MyIrcBuffer(const QString& receiver, const std::string &user, NetworkPlugin *np, const std::string &suffix, Irc::Session* parent)
: Irc::Buffer(receiver, parent)
{
this->np = np;
this->user = user;
this->suffix = suffix;
p = (MyIrcSession *) parent;
connect(this, SIGNAL(receiverChanged(QString)), SLOT(on_receiverChanged(QString)));
connect(this, SIGNAL(joined(QString)), SLOT(on_joined(QString)));
connect(this, SIGNAL(parted(QString, QString)), SLOT(on_parted(QString, QString)));
connect(this, SIGNAL(quit(QString, QString)), SLOT(on_quit(QString, QString)));
connect(this, SIGNAL(nickChanged(QString, QString)), SLOT(on_nickChanged(QString, QString)));
connect(this, SIGNAL(modeChanged(QString, QString, QString)), SLOT(on_modeChanged(QString, QString, QString)));
connect(this, SIGNAL(topicChanged(QString, QString)), SLOT(on_topicChanged(QString, QString)));
connect(this, SIGNAL(invited(QString, QString, QString)), SLOT(on_invited(QString, QString, QString)));
connect(this, SIGNAL(kicked(QString, QString, QString)), SLOT(on_kicked(QString, QString, QString)));
connect(this, SIGNAL(messageReceived(QString, QString, Irc::Buffer::MessageFlags)),
SLOT(on_messageReceived(QString, QString, Irc::Buffer::MessageFlags)));
connect(this, SIGNAL(noticeReceived(QString, QString, Irc::Buffer::MessageFlags)),
SLOT(on_noticeReceived(QString, QString, Irc::Buffer::MessageFlags)));
connect(this, SIGNAL(ctcpRequestReceived(QString, QString, Irc::Buffer::MessageFlags)),
SLOT(on_ctcpRequestReceived(QString, QString, Irc::Buffer::MessageFlags)));
connect(this, SIGNAL(ctcpReplyReceived(QString, QString, Irc::Buffer::MessageFlags)),
SLOT(on_ctcpReplyReceived(QString, QString, Irc::Buffer::MessageFlags)));
connect(this, SIGNAL(ctcpActionReceived(QString, QString, Irc::Buffer::MessageFlags)),
SLOT(on_ctcpActionReceived(QString, QString, Irc::Buffer::MessageFlags)));
connect(this, SIGNAL(numericMessageReceived(QString, uint, QStringList)), SLOT(on_numericMessageReceived(QString, uint, QStringList)));
connect(this, SIGNAL(unknownMessageReceived(QString, QStringList)), SLOT(on_unknownMessageReceived(QString, QStringList)));
}
void MyIrcBuffer::on_receiverChanged(const QString& receiver)
{
qDebug() << "receiver changed:" << receiver;
}
bool MyIrcBuffer::correctNickname(std::string &nickname) {
bool flags = 0;
switch(nickname.at(0)) {
case '@': nickname = nickname.substr(1); flags = 1; break;
case '+': nickname = nickname.substr(1); break;
default: break;
}
return flags;
}
void MyIrcBuffer::on_joined(const QString& origin) {
qDebug() << "joined:" << receiver() << origin;
bool flags = 0;
std::string nickname = origin.toStdString();
flags = correctNickname(nickname);
np->handleParticipantChanged(user, origin.toStdString(), receiver().toStdString() + suffix, (int) flags, pbnetwork::STATUS_ONLINE);
}
void MyIrcBuffer::on_parted(const QString& origin, const QString& message) {
qDebug() << "parted:" << receiver() << origin << message;
bool flags = 0;
std::string nickname = origin.toStdString();
flags = correctNickname(nickname);
np->handleParticipantChanged(user, nickname, receiver().toStdString() + suffix,(int) flags, pbnetwork::STATUS_NONE, message.toStdString());
}
void MyIrcBuffer::on_quit(const QString& origin, const QString& message)
{
qDebug() << "quit:" << receiver() << origin << message;
on_parted(origin, message);
}
void MyIrcBuffer::on_nickChanged(const QString& origin, const QString& nick) {
qDebug() << "nick changed:" << receiver() << origin << nick;
std::string nickname = origin.toStdString();
bool flags = p->m_modes[receiver().toStdString() + nickname];
// std::cout << receiver().toStdString() + nickname << " " << flags << "\n";
np->handleParticipantChanged(user, nickname, receiver().toStdString() + suffix,(int) flags, pbnetwork::STATUS_ONLINE, "", nick.toStdString());
}
void MyIrcBuffer::on_modeChanged(const QString& origin, const QString& mode, const QString& args) {
// mode changed: "#testik" "HanzZ" "+o" "hanzz_k"
qDebug() << "mode changed:" << receiver() << origin << mode << args;
std::string nickname = args.toStdString();
if (nickname.empty())
return;
if (mode == "+o") {
p->m_modes[receiver().toStdString() + nickname] = 1;
}
else {
p->m_modes[receiver().toStdString() + nickname] = 0;
}
bool flags = p->m_modes[receiver().toStdString() + nickname];
np->handleParticipantChanged(user, nickname, receiver().toStdString() + suffix,(int) flags, pbnetwork::STATUS_ONLINE, "");
}
void MyIrcBuffer::on_topicChanged(const QString& origin, const QString& topic) {
//topic changed: "#testik" "HanzZ" "test"
qDebug() << "topic changed:" << receiver() << origin << topic;
np->handleSubject(user, receiver().toStdString() + suffix, topic.toStdString(), origin.toStdString());
}
void MyIrcBuffer::on_invited(const QString& origin, const QString& receiver, const QString& channel)
{
qDebug() << "invited:" << Irc::Buffer::receiver() << origin << receiver << channel;
}
void MyIrcBuffer::on_kicked(const QString& origin, const QString& nick, const QString& message)
{
qDebug() << "kicked:" << receiver() << origin << nick << message;
}
void MyIrcBuffer::on_messageReceived(const QString& origin, const QString& message, Irc::Buffer::MessageFlags flags) {
qDebug() << "message received:" << receiver() << origin << message << (flags & Irc::Buffer::IdentifiedFlag ? "(identified!)" : "(not identified)");
if (!receiver().startsWith("#") && (flags & Irc::Buffer::EchoFlag))
return;
std::string r = receiver().toStdString();
// if (!suffix.empty()) {
// r = receiver().replace('@', '%').toStdString();
// }
if (r.find("#") == 0) {
np->handleMessage(user, r + suffix, message.toStdString(), origin.toStdString());
}
else {
np->handleMessage(user, r + suffix, message.toStdString());
}
}
void MyIrcBuffer::on_noticeReceived(const QString& origin, const QString& notice, Irc::Buffer::MessageFlags flags)
{
qDebug() << "notice received:" << receiver() << origin << notice
<< (flags & Irc::Buffer::IdentifiedFlag ? "(identified!)" : "(not identified)");
}
void MyIrcBuffer::on_ctcpRequestReceived(const QString& origin, const QString& request, Irc::Buffer::MessageFlags flags)
{
qDebug() << "ctcp request received:" << receiver() << origin << request
<< (flags & Irc::Buffer::IdentifiedFlag ? "(identified!)" : "(not identified)");
}
void MyIrcBuffer::on_ctcpReplyReceived(const QString& origin, const QString& reply, Irc::Buffer::MessageFlags flags)
{
qDebug() << "ctcp reply received:" << receiver() << origin << reply
<< (flags & Irc::Buffer::IdentifiedFlag ? "(identified!)" : "(not identified)");
}
void MyIrcBuffer::on_ctcpActionReceived(const QString& origin, const QString& action, Irc::Buffer::MessageFlags flags)
{
qDebug() << "ctcp action received:" << receiver() << origin << action
<< (flags & Irc::Buffer::IdentifiedFlag ? "(identified!)" : "(not identified)");
}
void MyIrcBuffer::on_numericMessageReceived(const QString& origin, uint code, const QStringList& params)
{
switch (code) {
case 251:
if (suffix.empty())
np->handleConnected(user);
break;
case 332:
m_topicData = params.value(2).toStdString();
break;
case 333:
np->handleSubject(user, params.value(1).toStdString() + suffix, m_topicData, params.value(2).toStdString());
break;
case 353:
QString channel = params.value(2);
QStringList members = params.value(3).split(" ");
for (int i = 0; i < members.size(); i++) {
bool flags = 0;
std::string nickname = members.at(i).toStdString();
flags = correctNickname(nickname);
p->m_modes[channel.toStdString() + nickname] = flags;
std::cout << channel.toStdString() + suffix << " " << flags << "\n";
np->handleParticipantChanged(user, nickname, channel.toStdString() + suffix,(int) flags, pbnetwork::STATUS_ONLINE);
}
break;
}
qDebug() << "numeric message received:" << receiver() << origin << code << params;
}
void MyIrcBuffer::on_unknownMessageReceived(const QString& origin, const QStringList& params)
{
qDebug() << "unknown message received:" << receiver() << origin << params;
}

View file

@ -1,77 +0,0 @@
/*
* Copyright (C) 2008-2009 J-P Nurmi jpnurmi@gmail.com
*
* This example is free, and not covered by LGPL license. There is no
* restriction applied to their modification, redistribution, using and so on.
* You can study them, modify them, use them in your own program - either
* completely or partially. By using it you may give me some credits in your
* program, but you don't have to.
*/
#ifndef SESSION_H
#define SESSION_H
#include <IrcSession>
#include <IrcBuffer>
#include <transport/networkplugin.h>
using namespace Transport;
class MyIrcSession : public Irc::Session
{
Q_OBJECT
public:
MyIrcSession(const std::string &user, NetworkPlugin *np, const std::string &suffix = "", QObject* parent = 0);
std::map<std::string, bool> m_modes;
std::string suffix;
int rooms;
protected Q_SLOTS:
void on_connected();
void on_disconnected();
void on_bufferAdded(Irc::Buffer* buffer);
void on_bufferRemoved(Irc::Buffer* buffer);
protected:
NetworkPlugin *np;
std::string user;
virtual Irc::Buffer* createBuffer(const QString& receiver);
};
class MyIrcBuffer : public Irc::Buffer
{
Q_OBJECT
public:
MyIrcBuffer(const QString& receiver, const std::string &user, NetworkPlugin *np, const std::string &suffix, Irc::Session* parent);
NetworkPlugin *np;
std::string user;
MyIrcSession *p;
std::string m_topicData;
std::string suffix;
protected Q_SLOTS:
void on_receiverChanged(const QString& receiver);
void on_joined(const QString& origin);
void on_parted(const QString& origin, const QString& message);
void on_quit(const QString& origin, const QString& message);
void on_nickChanged(const QString& origin, const QString& nick);
void on_modeChanged(const QString& origin, const QString& mode, const QString& args);
void on_topicChanged(const QString& origin, const QString& topic);
void on_invited(const QString& origin, const QString& receiver, const QString& channel);
void on_kicked(const QString& origin, const QString& nick, const QString& message);
void on_messageReceived(const QString& origin, const QString& message, Irc::Buffer::MessageFlags flags);
void on_noticeReceived(const QString& origin, const QString& notice, Irc::Buffer::MessageFlags flags);
void on_ctcpRequestReceived(const QString& origin, const QString& request, Irc::Buffer::MessageFlags flags);
void on_ctcpReplyReceived(const QString& origin, const QString& reply, Irc::Buffer::MessageFlags flags);
void on_ctcpActionReceived(const QString& origin, const QString& action, Irc::Buffer::MessageFlags flags);
void on_numericMessageReceived(const QString& origin, uint code, const QStringList& params);
void on_unknownMessageReceived(const QString& origin, const QStringList& params);
bool correctNickname(std::string &nickname);
};
#endif // SESSION_H

View file

@ -69,6 +69,20 @@ class SpectrumNetworkPlugin;
GKeyFile *keyfile;
SpectrumNetworkPlugin *np;
std::string replaceAll(
std::string result,
const std::string& replaceWhat,
const std::string& replaceWithWhat)
{
while(1)
{
const int pos = result.find(replaceWhat);
if (pos==-1) break;
result.replace(pos,replaceWhat.size(),replaceWithWhat);
}
return result;
}
static std::string KEYFILE_STRING(const std::string &cat, const std::string &key, const std::string &def = "") {
gchar *str = g_key_file_get_string(keyfile, cat.c_str(), key.c_str(), 0);
if (!str) {
@ -83,6 +97,11 @@ static std::string KEYFILE_STRING(const std::string &cat, const std::string &key
ret.erase(ret.end() - 1);
}
}
if (ret.find("$jid") != std::string::npos) {
std::string jid = KEYFILE_STRING("service", "jid");
ret = replaceAll(ret, "$jid", jid);
}
return ret;
}
@ -523,6 +542,10 @@ class SpectrumNetworkPlugin : public NetworkPlugin {
while (keys && keys[i] != NULL) {
std::string key = keys[i];
if (key == "fb_api_key" || key == "fb_api_secret") {
purple_account_set_bool(account, "auth_fb", TRUE);
}
PurplePlugin *plugin = purple_find_prpl(purple_account_get_protocol_id(account));
PurplePluginProtocolInfo *prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(plugin);
bool found = false;
@ -570,11 +593,13 @@ class SpectrumNetworkPlugin : public NetworkPlugin {
getProtocolAndName(legacyName, name, protocol);
if (password.empty()) {
LOG4CXX_INFO(logger, name.c_str() << ": Empty password");
np->handleDisconnected(user, 0, "Empty password.");
return;
}
if (!purple_find_prpl(protocol.c_str())) {
LOG4CXX_INFO(logger, name.c_str() << ": Invalid protocol '" << protocol << "'");
np->handleDisconnected(user, 0, "Invalid protocol " + protocol);
return;
}
@ -1205,6 +1230,11 @@ static gboolean disconnectMe(void *data) {
return FALSE;
}
static gboolean pingTimeout(void *data) {
np->checkPing();
return TRUE;
}
static void connection_report_disconnect(PurpleConnection *gc, PurpleConnectionError reason, const char *text){
PurpleAccount *account = purple_connection_get_account(gc);
np->handleDisconnected(np->m_accounts[account], (int) reason, text ? text : "");
@ -1550,11 +1580,78 @@ static void transport_core_ui_init(void)
// #endif
}
/***** Core Ui Ops *****/
static void
spectrum_glib_log_handler(const gchar *domain,
GLogLevelFlags flags,
const gchar *message,
gpointer user_data)
{
const char *level;
char *new_msg = NULL;
char *new_domain = NULL;
if ((flags & G_LOG_LEVEL_ERROR) == G_LOG_LEVEL_ERROR)
level = "ERROR";
else if ((flags & G_LOG_LEVEL_CRITICAL) == G_LOG_LEVEL_CRITICAL)
level = "CRITICAL";
else if ((flags & G_LOG_LEVEL_WARNING) == G_LOG_LEVEL_WARNING)
level = "WARNING";
else if ((flags & G_LOG_LEVEL_MESSAGE) == G_LOG_LEVEL_MESSAGE)
level = "MESSAGE";
else if ((flags & G_LOG_LEVEL_INFO) == G_LOG_LEVEL_INFO)
level = "INFO";
else if ((flags & G_LOG_LEVEL_DEBUG) == G_LOG_LEVEL_DEBUG)
level = "DEBUG";
else {
LOG4CXX_ERROR(logger, "Unknown glib logging level in " << (guint)flags);
level = "UNKNOWN"; /* This will never happen. */
}
if (message != NULL)
new_msg = purple_utf8_try_convert(message);
if (domain != NULL)
new_domain = purple_utf8_try_convert(domain);
if (new_msg != NULL) {
std::string area("glib");
area.push_back('/');
area.append(level);
std::string message(new_domain ? new_domain : "g_log");
message.push_back(' ');
message.append(new_msg);
LOG4CXX_ERROR(logger, message);
g_free(new_msg);
}
g_free(new_domain);
}
static void
debug_init(void)
{
#define REGISTER_G_LOG_HANDLER(name) \
g_log_set_handler((name), \
(GLogLevelFlags)(G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL \
| G_LOG_FLAG_RECURSION), \
spectrum_glib_log_handler, NULL)
REGISTER_G_LOG_HANDLER(NULL);
REGISTER_G_LOG_HANDLER("GLib");
REGISTER_G_LOG_HANDLER("GModule");
REGISTER_G_LOG_HANDLER("GLib-GObject");
REGISTER_G_LOG_HANDLER("GThread");
#undef REGISTER_G_LOD_HANDLER
}
static PurpleCoreUiOps coreUiOps =
{
NULL,
// debug_init,
NULL,
debug_init,
transport_core_ui_init,
NULL,
spectrum_ui_get_info,
@ -1852,7 +1949,7 @@ int main(int argc, char **argv) {
p.load(istream);
LogString pid, jid;
log4cxx::helpers::Transcoder::decode(stringOf(getpid()), pid);
log4cxx::helpers::Transcoder::decode(KEYFILE_STRING("service", "service.jid"), jid);
log4cxx::helpers::Transcoder::decode(KEYFILE_STRING("service", "jid"), jid);
#ifdef _MSC_VER
p.setProperty(L"pid", pid);
p.setProperty(L"jid", jid);
@ -1868,6 +1965,7 @@ int main(int argc, char **argv) {
m_sock = create_socket(host, port);
purple_input_add(m_sock, PURPLE_INPUT_READ, &transportDataReceived, NULL);
purple_timeout_add_seconds(30, pingTimeout, NULL);
np = new SpectrumNetworkPlugin(host, port);
bool libev = KEYFILE_STRING("service", "eventloop") == "libev";

View file

@ -0,0 +1,10 @@
FIND_LIBRARY(IRC_LIBRARY NAMES Communi)
FIND_PATH(IRC_INCLUDE_DIR NAMES "ircglobal.h" PATH_SUFFIXES Communi qt4/Communi )
# message( STATUS ${IRC_LIBRARY})
if( IRC_LIBRARY AND IRC_INCLUDE_DIR )
message( STATUS "Found libCommuni ${IRC_LIBRARY}, ${IRC_INCLUDE_DIR}")
set( IRC_FOUND 1 )
else()
message( STATUS "Could NOT find libCommuni" )
endif()

View file

@ -1,10 +0,0 @@
FIND_LIBRARY(IRC_LIBRARY NAMES ircclient-qt)
FIND_PATH(IRC_INCLUDE_DIR NAMES "ircglobal.h" PATH_SUFFIXES ircclient-qt qt4/ircclient-qt )
# message( STATUS ${IRC_LIBRARY})
if( IRC_LIBRARY AND IRC_INCLUDE_DIR )
message( STATUS "Found libircclient-qt: ${IRC_LIBRARY}, ${IRC_INCLUDE_DIR}")
set( IRC_FOUND 1 )
else()
message( STATUS "Could NOT find libircclient-qt" )
endif()

View file

@ -1,6 +0,0 @@
ADD_SUBDIRECTORY(server_connect)
ADD_SUBDIRECTORY(usermanager)
if (PROTOBUF_FOUND)
ADD_SUBDIRECTORY(external_network_plugin)
endif()

View file

@ -1,13 +0,0 @@
FILE(GLOB SRC *.cpp)
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/pbnetwork_pb2.py"
COMMAND ${PROTOBUF_PROTOC_EXECUTABLE}
ARGS --python_out ${CMAKE_CURRENT_BINARY_DIR} pbnetwork.proto
COMMENT "Running Py protocol buffer compiler on pbnetwork.proto"
VERBATIM )
ADD_EXECUTABLE(external_network_plugin ${SRC} ${CMAKE_CURRENT_BINARY_DIR}/pbnetwork_pb2.py)
TARGET_LINK_LIBRARIES(external_network_plugin transport ${SWIFTEN_LIBRARIES})

View file

@ -1,39 +0,0 @@
#include "transport/config.h"
#include "transport/transport.h"
#include "transport/usermanager.h"
#include "transport/logger.h"
#include "transport/sqlite3backend.h"
#include "transport/userregistration.h"
#include "transport/networkpluginserver.h"
#include "Swiften/EventLoop/SimpleEventLoop.h"
using namespace Transport;
int main(void)
{
Config config;
if (!config.load("sample.cfg")) {
std::cout << "Can't open sample.cfg configuration file.\n";
return 1;
}
Swift::SimpleEventLoop eventLoop;
Component transport(&eventLoop, &config, NULL);
Logger logger(&transport);
SQLite3Backend sql(&config);
logger.setStorageBackend(&sql);
if (!sql.connect()) {
std::cout << "Can't connect to database.\n";
}
UserManager userManager(&transport, &sql);
UserRegistration userRegistration(&transport, &userManager, &sql);
logger.setUserRegistration(&userRegistration);
logger.setUserManager(&userManager);
NetworkPluginServer plugin(&transport, &config, &userManager);
transport.connect();
eventLoop.run();
}

View file

@ -1,29 +0,0 @@
package pbnetwork;
message Connected {
required string name = 1;
}
message Disconnected {
required string name = 1;
required int32 error = 2;
optional string message = 3;
}
message Login {
required string protocol = 1;
required string legacyName = 2;
required string password = 3;
}
message WrapperMessage {
enum Type {
TYPE_CONNECTED = 1;
TYPE_DISCONNECTED = 2;
TYPE_LOGIN = 3;
TYPE_LOGOUT = 4;
}
required Type type = 1;
required bytes payload = 2;
}
;

View file

@ -1,29 +0,0 @@
#! /usr/bin/python
from pbnetwork_pb2 import *
import time
import sys
import socket
import struct
connected = Connected()
connected.name = "hanzz.k@gmail.com"
wrapper = WrapperMessage()
wrapper.type = WrapperMessage.TYPE_CONNECTED
wrapper.payload = connected.SerializeToString()
sck = socket.socket()
sck.connect(("localhost", 10000))
message = wrapper.SerializeToString();
header = struct.pack(">L", len(message))
print [header]
sck.send(header + message+header + message);
sck.send(header + message);
sck.send(header + message);
sck.send(header + message);
sck.send(header + message);
print sck.recv(255)

View file

@ -1,6 +0,0 @@
FILE(GLOB SRC *.cpp)
ADD_EXECUTABLE(transport_server_connect ${SRC})
TARGET_LINK_LIBRARIES(transport_server_connect transport ${SWIFTEN_LIBRARIES})

View file

@ -1,36 +0,0 @@
#include "transport/config.h"
#include "transport/transport.h"
#include "transport/logger.h"
#include "Swiften/EventLoop/SimpleEventLoop.h"
#include "Swiften/Network/BoostTimerFactory.h"
#include "Swiften/Network/BoostIOServiceThread.h"
#include "Swiften/Network/BoostNetworkFactories.h"
#include "Swiften/Server/UserRegistry.h"
#include "Swiften/Server/Server.h"
#include "Swiften/Swiften.h"
using namespace Transport;
class DummyUserRegistry : public Swift::UserRegistry {
public:
DummyUserRegistry() {}
virtual bool isValidUserPassword(const Swift::JID&user, const Swift::SafeByteArray&) const {
onPasswordValid(user.toString());
return true;
}
};
int main(void)
{
Swift::logging = true;
Swift::SimpleEventLoop loop;
Swift::BoostNetworkFactories *m_factories = new Swift::BoostNetworkFactories(&loop);
DummyUserRegistry dummyregistry;
Swift::Server server(&loop, m_factories, &dummyregistry, "localhost", 5222);
server.start();
loop.run();
}

View file

@ -1,6 +0,0 @@
[service]
jid = icq.localhost
password = secret
server = 127.0.0.1
port = 5222
server_mode = 1

View file

@ -1,6 +0,0 @@
FILE(GLOB SRC *.cpp)
ADD_EXECUTABLE(transport_usermanager ${SRC})
TARGET_LINK_LIBRARIES(transport_usermanager transport ${SWIFTEN_LIBRARIES})

View file

@ -1,36 +0,0 @@
#include "transport/config.h"
#include "transport/transport.h"
#include "transport/usermanager.h"
#include "transport/logger.h"
#include "transport/sqlite3backend.h"
#include "transport/userregistration.h"
#include "Swiften/EventLoop/SimpleEventLoop.h"
using namespace Transport;
int main(void)
{
Config config;
if (!config.load("sample.cfg")) {
std::cout << "Can't open sample.cfg configuration file.\n";
return 1;
}
Swift::SimpleEventLoop eventLoop;
Component transport(&eventLoop, &config, NULL);
Logger logger(&transport);
SQLite3Backend sql(&config);
logger.setStorageBackend(&sql);
if (!sql.connect()) {
std::cout << "Can't connect to database.\n";
}
UserManager userManager(&transport, &sql);
UserRegistration userRegistration(&transport, &userManager, &sql);
logger.setUserRegistration(&userRegistration);
logger.setUserManager(&userManager);
transport.connect();
eventLoop.run();
}

View file

@ -1,9 +0,0 @@
[service]
jid = icq.localhost
password = secret
server = 127.0.0.1
port = 8888
[database]
database = test.sql
prefix=icq

View file

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

View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 2011 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#pragma once
#include <vector>
#include <string>
#include <Swiften/Elements/Payload.h>
namespace Swift {
class StatsPayload : public Payload {
public:
class Item {
public:
Item(const std::string &name = "", const std::string &units = "", const std::string &value = "") :
name(name), units(units), value(value) { }
void setName(const std::string &name) {
this->name = name;
}
const std::string &getName() const {
return name;
}
void setUnits(const std::string &units) {
this->units = units;
}
const std::string &getUnits() const {
return units;
}
void setValue(const std::string &value) {
this->value = value;
}
const std::string &getValue() const {
return value;
}
private:
std::string name;
std::string units;
std::string value;
};
typedef std::vector<StatsPayload::Item> StatsPayloadItems;
StatsPayload();
void addItem(const StatsPayload::Item &item) {
items.push_back(item);
}
const StatsPayloadItems &getItems() const {
return items;
}
private:
StatsPayloadItems items;
};
}

View file

@ -0,0 +1,43 @@
/*
* Copyright (c) 2011 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#include <Swiften/Parser/PayloadParsers/StatsParser.h>
#include <Swiften/Parser/SerializingParser.h>
namespace Swift {
StatsParser::StatsParser() : level_(TopLevel), inItem_(false) {
}
void StatsParser::handleStartElement(const std::string& element, const std::string& /*ns*/, const AttributeMap& attributes) {
if (level_ == PayloadLevel) {
if (element == "stat") {
inItem_ = true;
currentItem_ = StatsPayload::Item();
currentItem_.setName(attributes.getAttribute("name"));
currentItem_.setValue(attributes.getAttribute("value"));
currentItem_.setUnits(attributes.getAttribute("units"));
}
}
++level_;
}
void StatsParser::handleEndElement(const std::string& element, const std::string& /*ns*/) {
--level_;
if (level_ == PayloadLevel) {
if (inItem_) {
getPayloadInternal()->addItem(currentItem_);
inItem_ = false;
}
}
}
void StatsParser::handleCharacterData(const std::string& data) {
}
}

View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2011 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#pragma once
#include <Swiften/Elements/StatsPayload.h>
#include <Swiften/Parser/GenericPayloadParser.h>
namespace Swift {
class SerializingParser;
class StatsParser : public GenericPayloadParser<StatsPayload> {
public:
StatsParser();
virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes);
virtual void handleEndElement(const std::string& element, const std::string&);
virtual void handleCharacterData(const std::string& data);
private:
enum Level {
TopLevel = 0,
PayloadLevel = 1,
ItemLevel = 2
};
int level_;
bool inItem_;
StatsPayload::Item currentItem_;
};
}

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2011 Jan Kaluza
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#include <Swiften/Serializer/PayloadSerializers/StatsSerializer.h>
#include <boost/shared_ptr.hpp>
#include <Swiften/Base/foreach.h>
#include <Swiften/Serializer/XML/XMLTextNode.h>
#include <Swiften/Serializer/XML/XMLRawTextNode.h>
#include <Swiften/Serializer/XML/XMLElement.h>
namespace Swift {
StatsSerializer::StatsSerializer() : GenericPayloadSerializer<StatsPayload>() {
}
std::string StatsSerializer::serializePayload(boost::shared_ptr<StatsPayload> stats) const {
XMLElement queryElement("query", "http://jabber.org/protocol/stats");
foreach(const StatsPayload::Item& item, stats->getItems()) {
boost::shared_ptr<XMLElement> statElement(new XMLElement("stat"));
statElement->setAttribute("name", item.getName());
if (!item.getUnits().empty()) {
statElement->setAttribute("units", item.getUnits());
}
if (!item.getValue().empty()) {
statElement->setAttribute("value", item.getValue());
}
queryElement.addNode(statElement);
}
return queryElement.serialize();
}
}

View file

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

View file

@ -34,6 +34,7 @@
#define CONFIG_BOOL(PTR, KEY) (*PTR)[KEY].as<bool>()
#define CONFIG_LIST(PTR, KEY) (*PTR)[KEY].as<std::list<std::string> >()
#define CONFIG_VECTOR(PTR, KEY) (*PTR)[KEY].as<std::vector<std::string> >()
#define CONFIG_HAS_KEY(PTR, KEY) (*PTR).hasKey(KEY)
namespace Transport {
@ -60,9 +61,9 @@ class Config {
/// the parser using opts parameter.
/// \param configfile path to config file
/// \param opts extra options which will be recognized by a parser
bool load(const std::string &configfile, boost::program_options::options_description &opts);
bool load(const std::string &configfile, boost::program_options::options_description &opts, const std::string &jid = "");
bool load(std::istream &ifs, boost::program_options::options_description &opts);
bool load(std::istream &ifs, boost::program_options::options_description &opts, const std::string &jid = "");
bool load(std::istream &ifs);
@ -71,10 +72,14 @@ class Config {
/// This function loads only config variables needed by libtransport.
/// \see load(const std::string &, boost::program_options::options_description &)
/// \param configfile path to config file
bool load(const std::string &configfile);
bool load(const std::string &configfile, const std::string &jid = "");
bool reload();
bool hasKey(const std::string &key) {
return m_variables.find(key) != m_variables.end();
}
/// Returns value of variable defined by key.
/// For variables in sections you can use "section.variable" key format.

View file

@ -74,6 +74,14 @@ class Conversation {
m_nickname = nickname;
}
const std::string &getNickname() {
return m_nickname;
}
void setJID(const Swift::JID &jid) {
m_jid = jid;
}
/// Sends message to Legacy network.
/// \param message Message.
@ -112,6 +120,7 @@ class Conversation {
std::string m_nickname;
std::string m_room;
bool m_muc;
Swift::JID m_jid;
};
}

View file

@ -73,6 +73,8 @@ class ConversationManager {
/// \param conv Conversation.
void removeConversation(Conversation *conv);
void resetResources();
private:
void handleMessageReceived(Swift::Message::ref message);

View file

@ -214,7 +214,8 @@ class NetworkPlugin {
virtual void handleExitRequest() { exit(1); }
void handleDataRead(std::string &data);
virtual void sendData(const std::string &string) {}
void checkPing();
private:
void handleLoginPayload(const std::string &payload);

View file

@ -96,7 +96,7 @@ class NetworkPluginServer {
void handleFTDataPayload(Backend *b ,const std::string &payload);
void handleUserCreated(User *user);
void handleRoomJoined(User *user, const std::string &room, const std::string &nickname, const std::string &password);
void handleRoomJoined(User *user, const Swift::JID &who, const std::string &room, const std::string &nickname, const std::string &password);
void handleRoomLeft(User *user, const std::string &room);
void handleUserReadyToConnect(User *user);
void handleUserPresenceChanged(User *user, Swift::Presence::ref presence);

View file

@ -1,5 +1,25 @@
package pbnetwork;
enum ConnectionError {
CONNECTION_ERROR_NETWORK_ERROR = 0;
CONNECTION_ERROR_INVALID_USERNAME = 1;
CONNECTION_ERROR_AUTHENTICATION_FAILED = 2;
CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE = 3;
CONNECTION_ERROR_NO_SSL_SUPPORT = 4;
CONNECTION_ERROR_ENCRYPTION_ERROR = 5;
CONNECTION_ERROR_NAME_IN_USE = 6;
CONNECTION_ERROR_INVALID_SETTINGS = 7;
CONNECTION_ERROR_CERT_NOT_PROVIDED = 8;
CONNECTION_ERROR_CERT_UNTRUSTED = 9;
CONNECTION_ERROR_CERT_EXPIRED = 10;
CONNECTION_ERROR_CERT_NOT_ACTIVATED = 11;
CONNECTION_ERROR_CERT_HOSTNAME_MISMATCH = 12;
CONNECTION_ERROR_CERT_FINGERPRINT_MISMATCH = 13;
CONNECTION_ERROR_CERT_SELF_SIGNED = 14;
CONNECTION_ERROR_CERT_OTHER_ERROR = 15;
CONNECTION_ERROR_OTHER_ERROR = 16;
}
enum StatusType {
STATUS_ONLINE = 0;
STATUS_AWAY = 1;
@ -135,4 +155,4 @@ message WrapperMessage {
required Type type = 1;
optional bytes payload = 2;
}
;
;

View file

@ -49,6 +49,7 @@ class AddressedRosterRequest : public Swift::GenericRequest<Swift::RosterPayload
/// Manages roster of one XMPP user.
class RosterManager {
public:
typedef std::map<std::string, Buddy *, std::less<std::string>, boost::pool_allocator< std::pair<std::string, Buddy *> > > BuddiesMap;
/// Creates new RosterManager.
/// \param user User associated with this RosterManager.
/// \param component Transport instance associated with this roster.
@ -80,6 +81,10 @@ class RosterManager {
/// \return User
User *getUser() { return m_user; }
const BuddiesMap &getBuddies() {
return m_buddies;
}
bool isRemoteRosterSupported() {
return m_supportRemoteRoster;
}
@ -125,6 +130,7 @@ class RosterManager {
Swift::Timer::ref m_RIETimer;
std::list <Swift::SetRosterRequest::ref> m_requests;
bool m_supportRemoteRoster;
AddressedRosterRequest::ref m_remoteRosterRequest;
};
}

View file

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

View file

@ -111,7 +111,7 @@ class User : public Swift::EntityCapsProvider {
boost::signal<void ()> onReadyToConnect;
boost::signal<void (Swift::Presence::ref presence)> onPresenceChanged;
boost::signal<void (const std::string &room, const std::string &nickname, const std::string &password)> onRoomJoined;
boost::signal<void (const Swift::JID &who, const std::string &room, const std::string &nickname, const std::string &password)> onRoomJoined;
boost::signal<void (const std::string &room)> onRoomLeft;
boost::signal<void ()> onDisconnected;
@ -135,6 +135,7 @@ class User : public Swift::EntityCapsProvider {
time_t m_lastActivity;
std::map<Swift::JID, Swift::DiscoInfo::ref> m_legacyCaps;
std::vector<boost::shared_ptr<Swift::OutgoingFileTransfer> > m_filetransfers;
int m_resources;
};
}

View file

@ -24,6 +24,7 @@
#include <stdlib.h>
#include <vector>
#include <string>
#include "Swiften/StringCodecs/Base64.h"
namespace Transport {
@ -31,6 +32,10 @@ namespace Util {
void removeEverythingOlderThan(const std::vector<std::string> &dirs, time_t t);
std::string encryptPassword(const std::string &password, const std::string &key);
std::string decryptPassword(std::string &encrypted, const std::string &key);
}
}

View file

@ -553,6 +553,13 @@ void NetworkPlugin::send(const std::string &data) {
sendData(std::string(header, 4) + data);
}
void NetworkPlugin::checkPing() {
if (m_pingReceived == false) {
handleExitRequest();
}
m_pingReceived = false;
}
void NetworkPlugin::sendPong() {
m_pingReceived = true;
std::string message;

View file

@ -13,7 +13,7 @@ INSTALL(TARGETS spectrum2 RUNTIME DESTINATION bin)
INSTALL(FILES
sample2.cfg
RENAME spectrum.cfg.example
DESTINATION /etc/spectrum2
DESTINATION /etc/spectrum2/transports
)
INSTALL(FILES

View file

@ -8,9 +8,11 @@
#include "transport/userregistration.h"
#include "transport/networkpluginserver.h"
#include "transport/admininterface.h"
#include "transport/statsresponder.h"
#include "transport/util.h"
#include "Swiften/EventLoop/SimpleEventLoop.h"
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
#ifndef WIN32
#include "sys/signal.h"
#include <pwd.h>
@ -122,6 +124,7 @@ int main(int argc, char **argv)
boost::program_options::variables_map vm;
bool no_daemon = false;
std::string config_file;
std::string jid;
#ifndef WIN32
@ -135,11 +138,14 @@ int main(int argc, char **argv)
return -1;
}
#endif
boost::program_options::options_description desc("Usage: spectrum [OPTIONS] <config_file.cfg>\nAllowed options");
boost::program_options::options_description desc(std::string("Spectrum version: ") + SPECTRUM_VERSION + "\nUsage: spectrum [OPTIONS] <config_file.cfg>\nAllowed options");
desc.add_options()
("help,h", "help")
("no-daemonize,n", "Do not run spectrum as daemon")
("no-debug,d", "Create coredumps on crash")
("jid,j", boost::program_options::value<std::string>(&jid)->default_value(""), "Specify JID of transport manually")
("config", boost::program_options::value<std::string>(&config_file)->default_value(""), "Config file")
("version,v", "Shows Spectrum version")
;
try
{
@ -149,7 +155,10 @@ int main(int argc, char **argv)
options(desc).positional(p).run(), vm);
boost::program_options::notify(vm);
if (vm.count("version")) {
std::cout << SPECTRUM_VERSION << "\n";
return 0;
}
if(vm.count("help"))
{
@ -177,31 +186,46 @@ int main(int argc, char **argv)
return 1;
}
if (!config.load(vm["config"].as<std::string>())) {
if (!config.load(vm["config"].as<std::string>(), jid)) {
std::cerr << "Can't load configuration file.\n";
return 1;
}
// create directories
try {
boost::filesystem::create_directories(
boost::filesystem::path(CONFIG_STRING(&config, "service.pidfile")).parent_path().string()
);
}
catch (...) {
std::cerr << "Can't create service.pidfile directory " << boost::filesystem::path(CONFIG_STRING(&config, "service.pidfile")).parent_path().string() << ".\n";
return 1;
}
// create directories
try {
boost::filesystem::create_directories(CONFIG_STRING(&config, "service.working_dir"));
}
catch (...) {
std::cerr << "Can't create service.working_dir directory " << CONFIG_STRING(&config, "service.working_dir") << ".\n";
return 1;
}
if (!CONFIG_STRING(&config, "service.group").empty() ||!CONFIG_STRING(&config, "service.user").empty() ) {
struct group *gr;
if ((gr = getgrnam(CONFIG_STRING(&config, "service.group").c_str())) == NULL) {
std::cerr << "Invalid service.group name " << CONFIG_STRING(&config, "service.group") << "\n";
return 1;
}
struct passwd *pw;
if ((pw = getpwnam(CONFIG_STRING(&config, "service.user").c_str())) == NULL) {
std::cerr << "Invalid service.user name " << CONFIG_STRING(&config, "service.user") << "\n";
return 1;
}
chown(CONFIG_STRING(&config, "service.working_dir").c_str(), pw->pw_uid, gr->gr_gid);
}
#ifndef WIN32
if (!no_daemon) {
// create directories
try {
boost::filesystem::create_directories(CONFIG_STRING(&config, "service.working_dir"));
}
catch (...) {
std::cerr << "Can't create service.working_dir directory " << CONFIG_STRING(&config, "service.working_dir") << ".\n";
return 1;
}
try {
boost::filesystem::create_directories(
boost::filesystem::path(CONFIG_STRING(&config, "service.pidfile")).parent_path().string()
);
}
catch (...) {
std::cerr << "Can't create service.pidfile directory " << boost::filesystem::path(CONFIG_STRING(&config, "service.pidfile")).parent_path().string() << ".\n";
return 1;
}
// daemonize
daemonize(CONFIG_STRING(&config, "service.working_dir").c_str(), CONFIG_STRING(&config, "service.pidfile").c_str());
// removeOldIcons(CONFIG_STRING(&config, "service.working_dir") + "/icons");
@ -231,6 +255,46 @@ int main(int argc, char **argv)
p.setProperty("pid", pid);
p.setProperty("jid", jid);
#endif
std::string dir;
BOOST_FOREACH(const log4cxx::LogString &prop, p.propertyNames()) {
if (boost::ends_with(prop, ".File")) {
dir = p.get(prop);
boost::replace_all(dir, "${jid}", jid);
break;
}
}
if (!dir.empty()) {
// create directories
try {
boost::filesystem::create_directories(
boost::filesystem::path(dir).parent_path().string()
);
}
catch (...) {
std::cerr << "Can't create logging directory directory " << boost::filesystem::path(dir).parent_path().string() << ".\n";
return 1;
}
#ifndef WIN32
if (!CONFIG_STRING(&config, "service.group").empty() && !CONFIG_STRING(&config, "service.user").empty()) {
struct group *gr;
if ((gr = getgrnam(CONFIG_STRING(&config, "service.group").c_str())) == NULL) {
std::cerr << "Invalid service.group name " << CONFIG_STRING(&config, "service.group") << "\n";
return 1;
}
struct passwd *pw;
if ((pw = getpwnam(CONFIG_STRING(&config, "service.user").c_str())) == NULL) {
std::cerr << "Invalid service.user name " << CONFIG_STRING(&config, "service.user") << "\n";
return 1;
}
chown(dir.c_str(), pw->pw_uid, gr->gr_gid);
}
#endif
}
log4cxx::PropertyConfigurator::configure(p);
}
@ -242,12 +306,12 @@ int main(int argc, char **argv)
if (!CONFIG_STRING(&config, "service.group").empty()) {
struct group *gr;
if ((gr = getgrnam(CONFIG_STRING(&config, "service.group").c_str())) == NULL) {
LOG4CXX_ERROR(logger, "Invalid service.group name " << CONFIG_STRING(&config, "service.group"));
std::cerr << "Invalid service.group name " << CONFIG_STRING(&config, "service.group") << "\n";
return 1;
}
if (((setgid(gr->gr_gid)) != 0) || (initgroups(CONFIG_STRING(&config, "service.user").c_str(), gr->gr_gid) != 0)) {
LOG4CXX_ERROR(logger, "Failed to set service.group name " << CONFIG_STRING(&config, "service.group") << " - " << gr->gr_gid << ":" << strerror(errno));
std::cerr << "Failed to set service.group name " << CONFIG_STRING(&config, "service.group") << " - " << gr->gr_gid << ":" << strerror(errno) << "\n";
return 1;
}
}
@ -255,17 +319,22 @@ int main(int argc, char **argv)
if (!CONFIG_STRING(&config, "service.user").empty()) {
struct passwd *pw;
if ((pw = getpwnam(CONFIG_STRING(&config, "service.user").c_str())) == NULL) {
LOG4CXX_ERROR(logger, "Invalid service.user name " << CONFIG_STRING(&config, "service.user"));
std::cerr << "Invalid service.user name " << CONFIG_STRING(&config, "service.user") << "\n";
return 1;
}
if ((setuid(pw->pw_uid)) != 0) {
LOG4CXX_ERROR(logger, "Failed to set service.user name " << CONFIG_STRING(&config, "service.user") << " - " << pw->pw_uid << ":" << strerror(errno));
std::cerr << "Failed to set service.user name " << CONFIG_STRING(&config, "service.user") << " - " << pw->pw_uid << ":" << strerror(errno) << "\n";
return 1;
}
}
setrlimit(RLIMIT_CORE, &limit);
}
struct rlimit limit;
limit.rlim_max = RLIM_INFINITY;
limit.rlim_cur = RLIM_INFINITY;
setrlimit(RLIMIT_CORE, &limit);
#endif
Swift::SimpleEventLoop eventLoop;
@ -313,6 +382,8 @@ int main(int argc, char **argv)
NetworkPluginServer plugin(&transport, &config, &userManager, &ftManager);
AdminInterface adminInterface(&transport, &userManager, &plugin, storageBackend);
StatsResponder statsResponder(&transport, &userManager, &plugin, storageBackend);
statsResponder.start();
eventLoop_ = &eventLoop;

View file

@ -5,6 +5,7 @@ server = 127.0.0.1
port = 5222
server_mode = 1
backend_host=localhost
pidfile=./test.pid
# < this option doesn't work yet
backend_port=10001
admin_username=admin
@ -12,13 +13,14 @@ admin_password=test
#cert=server.pfx #patch to PKCS#12 certificate
#cert_password=test #password to that certificate if any
users_per_backend=10
backend=/home/hanzz/code/libtransport/backends/libpurple/spectrum2_libpurple_backend
#backend=/home/hanzz/code/libtransport/backends/libpurple/spectrum2_libpurple_backend
#backend=/usr/bin/mono /home/hanzz/code/networkplugin-csharp/msnp-sharp-backend/bin/Debug/msnp-sharp-backend.exe
#backend=/home/hanzz/code/libtransport/backends/frotz/spectrum2_frotz_backend
#backend=/home/hanzz/code/libtransport/backends/libircclient-qt/spectrum2_libircclient-qt_backend
backend=/home/hanzz/code/libtransport/backends/libircclient-qt/spectrum2_libircclient-qt_backend
#protocol=prpl-msn
protocol=any
#protocol=prpl-icq
irc_server=irc.freenode.org
[backend]
#default_avatar=catmelonhead.jpg

View file

@ -36,8 +36,8 @@ backend_port=10001
users_per_backend=10
# Full path to backend binary.
backend=/usr/bin/spectrum_libpurple_backend
#backend=/usr/bin/spectrum_libircclient-qt_backend
backend=/usr/bin/spectrum2_libpurple_backend
#backend=/usr/bin/spectrum2_libircclient-qt_backend
# Libpurple protocol-id for spectrum_libpurple_backend
protocol=prpl-jabber
@ -62,18 +62,19 @@ type=xmpp
[logging]
# log4cxx/log4j logging configuration file in ini format used for main spectrum2 instance.
config = /etc/spectrum2/logging.cfg
config = /etc/spectrum2/logging.cfg
# log4cxx/log4j logging configuration file in ini format used for backends.
backend_config = /etc/spectrum2/backend-logging.cfg # log4cxx/log4j logging configuration file for backends
backend_config = /etc/spectrum2/backend-logging.cfg
[database]
# Database backend type
# "sqlite3", "mysql" or "none" without database backend
type = none
type = none
# For SQLite3: Full path to database
# For MySQL: name of database
# database = /var/lib/spectrum2/$jid/database.sql
database = jabber_transport
# Server.

View file

@ -1,9 +1,9 @@
cmake_minimum_required(VERSION 2.6)
FILE(GLOB SRC *.cpp)
ADD_EXECUTABLE(spectrum2_manager ${SRC})
ADD_EXECUTABLE(spectrum2_manager ${SRC} ../../src/config.cpp)
target_link_libraries(spectrum2_manager transport)
target_link_libraries(spectrum2_manager ${SWIFTEN_LIBRARY})
INSTALL(TARGETS spectrum2_manager RUNTIME DESTINATION bin)

View file

@ -1,10 +1,6 @@
#include "managerconfig.h"
#include "transport/transport.h"
#include "transport/usermanager.h"
#include "transport/logger.h"
#include "transport/sqlite3backend.h"
#include "transport/userregistration.h"
#include "transport/networkpluginserver.h"
#include "transport/config.h"
#include "Swiften/Swiften.h"
#include "Swiften/EventLoop/SimpleEventLoop.h"
#include <boost/foreach.hpp>
@ -86,12 +82,17 @@ static std::string searchForBinary(const std::string &binary) {
}
// Executes new backend
static unsigned long exec_(std::string path, std::string config) {
static unsigned long exec_(std::string path, std::string config, std::string jid = "") {
// fork and exec
pid_t pid = fork();
if ( pid == 0 ) {
// child process
exit(execl(path.c_str(), path.c_str(), config.c_str(), NULL));
if (jid.empty()) {
exit(execl(path.c_str(), path.c_str(), config.c_str(), NULL));
}
else {
exit(execl(path.c_str(), path.c_str(), "-j", jid.c_str(), config.c_str(), NULL));
}
} else if ( pid < 0 ) {
// fork failed
}
@ -147,15 +148,30 @@ static void start_all_instances(ManagerConfig *config) {
Config cfg;
if (cfg.load(itr->path().string()) == false) {
std::cerr << "Can't load config file " << itr->path().string() << ". Skipping...\n";
continue;
}
int pid = isRunning(CONFIG_STRING(&cfg, "service.pidfile"));
if (pid == 0) {
std::cout << "Starting " << itr->path() << ": OK\n";
exec_(spectrum2_binary, itr->path().string());
}
else {
std::cout << "Starting " << itr->path() << ": Already started (PID=" << pid << ")\n";
std::vector<std::string> vhosts;
if (CONFIG_HAS_KEY(&cfg, "vhosts.vhost"))
vhosts = CONFIG_VECTOR(&cfg, "vhosts.vhost");
vhosts.push_back(CONFIG_STRING(&cfg, "service.jid"));
BOOST_FOREACH(std::string &vhost, vhosts) {
Config vhostCfg;
if (vhostCfg.load(itr->path().string(), vhost) == false) {
std::cerr << "Can't load config file " << itr->path().string() << ". Skipping...\n";
continue;
}
int pid = isRunning(CONFIG_STRING(&vhostCfg, "service.pidfile"));
if (pid == 0) {
std::cout << "Starting " << itr->path() << ": OK\n";
exec_(spectrum2_binary, itr->path().string(), vhost);
}
else {
std::cout << "Starting " << itr->path() << ": Already started (PID=" << pid << ")\n";
}
}
}
}
@ -188,13 +204,26 @@ static void stop_all_instances(ManagerConfig *config) {
std::cerr << "Can't load config file " << itr->path().string() << ". Skipping...\n";
}
int pid = isRunning(CONFIG_STRING(&cfg, "service.pidfile"));
if (pid) {
std::cout << "Stopping " << itr->path() << ": OK\n";
kill(pid, SIGTERM);
}
else {
std::cout << "Stopping " << itr->path() << ": Not running\n";
std::vector<std::string> vhosts;
if (CONFIG_HAS_KEY(&cfg, "vhosts.vhost"))
vhosts = CONFIG_VECTOR(&cfg, "vhosts.vhost");
vhosts.push_back(CONFIG_STRING(&cfg, "service.jid"));
BOOST_FOREACH(std::string &vhost, vhosts) {
Config vhostCfg;
if (vhostCfg.load(itr->path().string(), vhost) == false) {
std::cerr << "Can't load config file " << itr->path().string() << ". Skipping...\n";
continue;
}
int pid = isRunning(CONFIG_STRING(&vhostCfg, "service.pidfile"));
if (pid) {
std::cout << "Stopping " << itr->path() << ": OK\n";
kill(pid, SIGTERM);
}
else {
std::cout << "Stopping " << itr->path() << ": Not running\n";
}
}
}
}

View file

@ -35,9 +35,9 @@ if (CMAKE_COMPILER_IS_GNUCXX)
endif()
if (WIN32)
TARGET_LINK_LIBRARIES(transport ${Boost_LIBRARIES} ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES} ${LOG4CXX_LIBRARIES})
TARGET_LINK_LIBRARIES(transport ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES} ${LOG4CXX_LIBRARIES})
else (WIN32)
TARGET_LINK_LIBRARIES(transport ${Boost_LIBRARIES} ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES} ${LOG4CXX_LIBRARIES} ${POPT_LIBRARY})
TARGET_LINK_LIBRARIES(transport ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES} ${LOG4CXX_LIBRARIES} ${POPT_LIBRARY})
endif(WIN32)
SET_TARGET_PROPERTIES(transport PROPERTIES

View file

@ -66,6 +66,11 @@ void AdminInterface::handleMessageReceived(Swift::Message::ref message) {
return;
}
// Ignore empty messages
if (message->getBody().empty()) {
return;
}
LOG4CXX_INFO(logger, "Message from admin received");
message->setTo(message->getFrom());
message->setFrom(m_component->getJID());

View file

@ -31,13 +31,13 @@ using namespace boost::program_options;
namespace Transport {
bool Config::load(const std::string &configfile, boost::program_options::options_description &opts) {
bool Config::load(const std::string &configfile, boost::program_options::options_description &opts, const std::string &jid) {
std::ifstream ifs(configfile.c_str());
if (!ifs.is_open())
return false;
m_file = configfile;
bool ret = load(ifs, opts);
bool ret = load(ifs, opts, jid);
ifs.close();
char path[PATH_MAX] = "";
@ -49,7 +49,7 @@ bool Config::load(const std::string &configfile, boost::program_options::options
return ret;
}
bool Config::load(std::istream &ifs, boost::program_options::options_description &opts) {
bool Config::load(std::istream &ifs, boost::program_options::options_description &opts, const std::string &_jid) {
m_unregistered.clear();
opts.add_options()
("service.jid", value<std::string>()->default_value(""), "Transport Jabber ID")
@ -60,13 +60,13 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description
("service.group", value<std::string>()->default_value(""), "The name of group Spectrum runs as.")
("service.backend", value<std::string>()->default_value("libpurple_backend"), "Backend")
("service.protocol", value<std::string>()->default_value(""), "Protocol")
("service.pidfile", value<std::string>()->default_value("/var/run/spectrum2/spectrum2.pid"), "Full path to pid file")
("service.working_dir", value<std::string>()->default_value("/var/lib/spectrum2"), "Working dir")
("service.pidfile", value<std::string>()->default_value("/var/run/spectrum2/$jid.pid"), "Full path to pid file")
("service.working_dir", value<std::string>()->default_value("/var/lib/spectrum2/$jid"), "Working dir")
("service.allowed_servers", value<std::string>()->default_value(""), "Only users from these servers can connect")
("service.server_mode", value<bool>()->default_value(false), "True if Spectrum should behave as server")
("service.users_per_backend", value<int>()->default_value(100), "Number of users per one legacy network backend")
("service.backend_host", value<std::string>()->default_value("localhost"), "Host to bind backend server to")
("service.backend_port", value<std::string>()->default_value("10000"), "Port to bind backend server to")
("service.backend_port", value<std::string>()->default_value("0"), "Port to bind backend server to")
("service.cert", value<std::string>()->default_value(""), "PKCS#12 Certificate.")
("service.cert_password", value<std::string>()->default_value(""), "PKCS#12 Certificate password.")
("service.admin_jid", value<std::string>()->default_value(""), "Administrator jid.")
@ -76,15 +76,16 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description
("service.memory_collector_time", value<int>()->default_value(0), "Time in seconds after which backend with most memory is set to die.")
("service.more_resources", value<bool>()->default_value(false), "Allow more resources to be connected in server mode at the same time.")
("service.enable_privacy_lists", value<bool>()->default_value(true), "")
("vhosts.vhost", value<std::vector<std::string> >()->multitoken(), "")
("identity.name", value<std::string>()->default_value("Spectrum 2 Transport"), "Name showed in service discovery.")
("identity.category", value<std::string>()->default_value("gateway"), "Disco#info identity category. 'gateway' by default.")
("identity.type", value<std::string>()->default_value(""), "Type of transport ('icq','msn','gg','irc', ...)")
("registration.enable_public_registration", value<bool>()->default_value(true), "True if users should be able to register.")
("registration.language", value<std::string>()->default_value("en"), "Default language for registration form")
("registration.instructions", value<std::string>()->default_value(""), "Instructions showed to user in registration form")
("registration.username_field", value<std::string>()->default_value(""), "Label for username field")
("registration.instructions", value<std::string>()->default_value("Enter your legacy network username and password."), "Instructions showed to user in registration form")
("registration.username_label", value<std::string>()->default_value("Legacy network username:"), "Label for username field")
("registration.username_mask", value<std::string>()->default_value(""), "Username mask")
("registration.encoding", value<std::string>()->default_value("en"), "Default encoding in registration form")
("registration.encoding", value<std::string>()->default_value("utf8"), "Default encoding in registration form")
("database.type", value<std::string>()->default_value("none"), "Database type.")
("database.database", value<std::string>()->default_value(""), "Database used to store data")
("database.server", value<std::string>()->default_value("localhost"), "Database server.")
@ -92,6 +93,7 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description
("database.password", value<std::string>()->default_value(""), "Database Password.")
("database.port", value<int>()->default_value(0), "Database port.")
("database.prefix", value<std::string>()->default_value(""), "Prefix of tables in database")
("database.encryption_key", value<std::string>()->default_value(""), "Encryption key.")
("logging.config", value<std::string>()->default_value(""), "Path to log4cxx config file which is used for Spectrum 2 instance")
("logging.backend_config", value<std::string>()->default_value(""), "Path to log4cxx config file which is used for backends")
("backend.default_avatar", value<std::string>()->default_value(""), "Full path to default avatar")
@ -101,10 +103,69 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description
parsed_options parsed = parse_config_file(ifs, opts, true);
BOOST_FOREACH(option opt, parsed.options) {
bool found_working = false;
bool found_pidfile = false;
bool found_backend_port = false;
std::string jid = "";
BOOST_FOREACH(option &opt, parsed.options) {
if (opt.string_key == "service.jid") {
if (_jid.empty()) {
jid = opt.value[0];
}
else {
opt.value[0] = _jid;
jid = _jid;
}
}
else if (opt.string_key == "service.backend_port") {
found_backend_port = true;
if (opt.value[0] == "0") {
unsigned long r = 0;
BOOST_FOREACH(char c, _jid) {
r += (int) c;
}
srand(time(NULL) + r);
int randomPort = 30000 + rand() % 10000;
opt.value[0] = boost::lexical_cast<std::string>(randomPort);
}
}
else if (opt.string_key == "service.working_dir") {
found_working = true;
}
else if (opt.string_key == "service.pidfile") {
found_pidfile = true;
}
}
if (!found_working) {
std::vector<std::string> value;
value.push_back("/var/lib/spectrum2/$jid");
parsed.options.push_back(boost::program_options::basic_option<char>("service.working_dir", value));
}
if (!found_pidfile) {
std::vector<std::string> value;
value.push_back("/var/run/spectrum2/$jid.pid");
parsed.options.push_back(boost::program_options::basic_option<char>("service.pidfile", value));
}
if (!found_backend_port) {
unsigned long r = 0;
BOOST_FOREACH(char c, _jid) {
r += (int) c;
}
srand(time(NULL) + r);
int randomPort = 30000 + rand() % 10000;
std::vector<std::string> value;
value.push_back(boost::lexical_cast<std::string>(randomPort));
parsed.options.push_back(boost::program_options::basic_option<char>("service.backend_port", value));
}
BOOST_FOREACH(option &opt, parsed.options) {
if (opt.unregistered) {
m_unregistered[opt.string_key] = opt.value[0];
}
else if (opt.value[0].find("$jid") != std::string::npos) {
boost::replace_all(opt.value[0], "$jid", jid);
}
}
store(parsed, m_variables);
@ -120,9 +181,9 @@ bool Config::load(std::istream &ifs) {
return load(ifs, opts);
}
bool Config::load(const std::string &configfile) {
bool Config::load(const std::string &configfile, const std::string &jid) {
options_description opts("Transport options");
return load(configfile, opts);
return load(configfile, opts, jid);
}
bool Config::reload() {

View file

@ -37,6 +37,7 @@ Conversation::Conversation(ConversationManager *conversationManager, const std::
m_legacyName = legacyName;
m_conversationManager->addConversation(this);
m_muc = isMUC;
m_jid = m_conversationManager->getUser()->getJID().toBare();
}
Conversation::~Conversation() {
@ -54,11 +55,16 @@ void Conversation::handleMessage(boost::shared_ptr<Swift::Message> &message, con
else {
message->setType(Swift::Message::Chat);
}
std::string n = nickname;
if (n.empty() && !m_room.empty() && !m_muc) {
n = m_nickname;
}
if (message->getType() != Swift::Message::Groupchat) {
message->setTo(m_conversationManager->getUser()->getJID().toBare());
message->setTo(m_jid);
// normal message
if (nickname.empty()) {
if (n.empty()) {
Buddy *buddy = m_conversationManager->getUser()->getRosterManager()->getBuddy(m_legacyName);
if (buddy) {
message->setFrom(buddy->getJID());
@ -70,10 +76,10 @@ void Conversation::handleMessage(boost::shared_ptr<Swift::Message> &message, con
// PM message
else {
if (m_room.empty()) {
message->setFrom(Swift::JID(nickname, m_conversationManager->getComponent()->getJID().toBare(), "user"));
message->setFrom(Swift::JID(n, m_conversationManager->getComponent()->getJID().toBare(), "user"));
}
else {
message->setFrom(Swift::JID(m_room, m_conversationManager->getComponent()->getJID().toBare(), nickname));
message->setFrom(Swift::JID(m_room, m_conversationManager->getComponent()->getJID().toBare(), n));
}
}
m_conversationManager->getComponent()->getStanzaChannel()->sendMessage(message);
@ -83,7 +89,7 @@ void Conversation::handleMessage(boost::shared_ptr<Swift::Message> &message, con
if (legacyName.find_last_of("@") != std::string::npos) {
legacyName.replace(legacyName.find_last_of("@"), 1, "%"); // OK
}
message->setTo(m_conversationManager->getUser()->getJID().toString());
message->setTo(m_jid);
message->setFrom(Swift::JID(legacyName, m_conversationManager->getComponent()->getJID().toBare(), nickname));
m_conversationManager->getComponent()->getStanzaChannel()->sendMessage(message);
}
@ -99,7 +105,7 @@ void Conversation::handleParticipantChanged(const std::string &nick, int flag, i
}
}
presence->setFrom(Swift::JID(legacyName, m_conversationManager->getComponent()->getJID().toBare(), nickname));
presence->setTo(m_conversationManager->getUser()->getJID().toString());
presence->setTo(m_jid);
presence->setType(Swift::Presence::Available);
if (!statusMessage.empty())

View file

@ -62,6 +62,15 @@ void ConversationManager::removeConversation(Conversation *conv) {
m_convs.erase(conv->getLegacyName());
}
void ConversationManager::resetResources() {
for (std::map<std::string, Conversation *>::const_iterator it = m_convs.begin(); it != m_convs.end(); it++) {
if ((*it).second->isMUC()) {
continue;
}
(*it).second->setJID(m_user->getJID().toBare());
}
}
void ConversationManager::handleMessageReceived(Swift::Message::ref message) {
// std::string name = message->getTo().getUnescapedNode();
// if (name.find_last_of("%") != std::string::npos) { // OK when commented
@ -84,10 +93,13 @@ void ConversationManager::handleMessageReceived(Swift::Message::ref message) {
if (!m_convs[name]) {
m_convs[name] = m_component->getFactory()->createConversation(this, name);
m_convs[name]->setRoom(room_name);
m_convs[name]->setNickname(name);
}
}
// update resource and send the message
m_convs[name]->setJID(message->getFrom());
m_convs[name]->sendMessage(message);
}
}
}

View file

@ -21,6 +21,7 @@
#ifdef WITH_MYSQL
#include "transport/mysqlbackend.h"
#include "transport/util.h"
#include <boost/bind.hpp>
#include "log4cxx/logger.h"
@ -409,7 +410,11 @@ bool MySQLBackend::exec(const std::string &query) {
}
void MySQLBackend::setUser(const UserInfo &user) {
*m_setUser << user.jid << user.uin << user.password << user.language << user.encoding << user.vip << user.password;
std::string encrypted = user.password;
if (!CONFIG_STRING(m_config, "database.encryption_key").empty()) {
encrypted = Util::encryptPassword(encrypted, CONFIG_STRING(m_config, "database.encryption_key"));
}
*m_setUser << user.jid << user.uin << encrypted << user.language << user.encoding << user.vip << user.password;
EXEC(m_setUser, setUser(user));
}
@ -423,6 +428,10 @@ bool MySQLBackend::getUser(const std::string &barejid, UserInfo &user) {
while (m_getUser->fetch() == 0) {
ret = true;
*m_getUser >> user.id >> user.jid >> user.uin >> user.password >> user.encoding >> user.language >> user.vip;
if (!CONFIG_STRING(m_config, "database.encryption_key").empty()) {
user.password = Util::decryptPassword(user.password, CONFIG_STRING(m_config, "database.encryption_key"));
}
}
return ret;

View file

@ -257,6 +257,17 @@ NetworkPluginServer::NetworkPluginServer(Component *component, Config *config, U
}
NetworkPluginServer::~NetworkPluginServer() {
for (std::list<Backend *>::const_iterator it = m_clients.begin(); it != m_clients.end(); it++) {
LOG4CXX_INFO(logger, "Stopping backend " << *it);
std::string message;
pbnetwork::WrapperMessage wrap;
wrap.set_type(pbnetwork::WrapperMessage_Type_TYPE_EXIT);
wrap.SerializeToString(&message);
Backend *c = (Backend *) *it;
send(c->connection, message);
}
m_pingTimer->stop();
m_server->stop();
m_server.reset();
@ -924,7 +935,7 @@ void NetworkPluginServer::handleUserCreated(User *user) {
// UserInfo userInfo = user->getUserInfo();
user->onReadyToConnect.connect(boost::bind(&NetworkPluginServer::handleUserReadyToConnect, this, user));
user->onPresenceChanged.connect(boost::bind(&NetworkPluginServer::handleUserPresenceChanged, this, user, _1));
user->onRoomJoined.connect(boost::bind(&NetworkPluginServer::handleRoomJoined, this, user, _1, _2, _3));
user->onRoomJoined.connect(boost::bind(&NetworkPluginServer::handleRoomJoined, this, user, _1, _2, _3, _4));
user->onRoomLeft.connect(boost::bind(&NetworkPluginServer::handleRoomLeft, this, user, _1));
}
@ -980,7 +991,7 @@ void NetworkPluginServer::handleUserPresenceChanged(User *user, Swift::Presence:
send(c->connection, message);
}
void NetworkPluginServer::handleRoomJoined(User *user, const std::string &r, const std::string &nickname, const std::string &password) {
void NetworkPluginServer::handleRoomJoined(User *user, const Swift::JID &who, const std::string &r, const std::string &nickname, const std::string &password) {
UserInfo userInfo = user->getUserInfo();
pbnetwork::Room room;
@ -1003,6 +1014,7 @@ void NetworkPluginServer::handleRoomJoined(User *user, const std::string &r, con
NetworkConversation *conv = new NetworkConversation(user->getConversationManager(), r, true);
conv->onMessageToSend.connect(boost::bind(&NetworkPluginServer::handleMessageReceived, this, _1, _2));
conv->setNickname(nickname);
conv->setJID(who);
}
void NetworkPluginServer::handleRoomLeft(User *user, const std::string &r) {
@ -1036,7 +1048,6 @@ void NetworkPluginServer::handleRoomLeft(User *user, const std::string &r) {
}
void NetworkPluginServer::handleUserDestroyed(User *user) {
std::cout << "HANDLE_DESTROYED\n";
m_waitingUsers.remove(user);
UserInfo userInfo = user->getUserInfo();

View file

@ -52,9 +52,9 @@ RosterManager::RosterManager(User *user, Component *component){
m_supportRemoteRoster = false;
if (!m_component->inServerMode()) {
AddressedRosterRequest::ref request = AddressedRosterRequest::ref(new AddressedRosterRequest(m_component->getIQRouter(), m_user->getJID().toBare()));
request->onResponse.connect(boost::bind(&RosterManager::handleRemoteRosterResponse, this, _1, _2));
request->send();
m_remoteRosterRequest = AddressedRosterRequest::ref(new AddressedRosterRequest(m_component->getIQRouter(), m_user->getJID().toBare()));
m_remoteRosterRequest->onResponse.connect(boost::bind(&RosterManager::handleRemoteRosterResponse, this, _1, _2));
m_remoteRosterRequest->send();
}
}
@ -67,6 +67,11 @@ RosterManager::~RosterManager() {
sendUnavailablePresences(m_user->getJID().toBare());
if (m_remoteRosterRequest) {
m_remoteRosterRequest->onResponse.disconnect_all_slots();
m_component->getIQRouter()->removeHandler(m_remoteRosterRequest);
}
for (std::map<std::string, Buddy *, std::less<std::string>, boost::pool_allocator< std::pair<std::string, Buddy *> > >::iterator it = m_buddies.begin(); it != m_buddies.end(); it++) {
Buddy *buddy = (*it).second;
if (!buddy) {
@ -136,8 +141,6 @@ void RosterManager::handleBuddyChanged(Buddy *buddy) {
}
void RosterManager::setBuddyCallback(Buddy *buddy) {
m_setBuddyTimer->onTick.disconnect(boost::bind(&RosterManager::setBuddyCallback, this, buddy));
LOG4CXX_INFO(logger, "Associating buddy " << buddy->getName() << " with " << m_user->getJID().toString());
m_buddies[buddy->getName()] = buddy;
onBuddySet(buddy);
@ -148,21 +151,17 @@ void RosterManager::setBuddyCallback(Buddy *buddy) {
sendBuddyRosterPush(buddy);
}
else {
if (m_setBuddyTimer->onTick.empty()) {
m_setBuddyTimer->stop();
if (m_supportRemoteRoster) {
sendBuddyRosterPush(buddy);
if (m_supportRemoteRoster) {
sendBuddyRosterPush(buddy);
}
else {
// Send RIE only if there's resource which supports it.
Swift::JID jidWithRIE = m_user->getJIDWithFeature("http://jabber.org/protocol/rosterx");
if (jidWithRIE.isValid()) {
m_RIETimer->start();
}
else {
// Send RIE only if there's resource which supports it.
Swift::JID jidWithRIE = m_user->getJIDWithFeature("http://jabber.org/protocol/rosterx");
if (jidWithRIE.isValid()) {
m_RIETimer->start();
}
else {
sendBuddySubscribePresence(buddy);
}
sendBuddySubscribePresence(buddy);
}
}
}
@ -198,6 +197,7 @@ void RosterManager::handleBuddyRosterPushResponse(Swift::ErrorPayload::ref error
}
void RosterManager::handleRemoteRosterResponse(boost::shared_ptr<Swift::RosterPayload> payload, Swift::ErrorPayload::ref error) {
m_remoteRosterRequest.reset();
if (error) {
m_supportRemoteRoster = false;
LOG4CXX_INFO(logger, m_user->getJID().toString() << ": This server does not support remote roster protoXEP");

142
src/statsresponder.cpp Normal file
View file

@ -0,0 +1,142 @@
/**
* XMPP - libpurple transport
*
* Copyright (C) 2009, Jan Kaluza <hanzz@soc.pidgin.im>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
*/
#include "transport/statsresponder.h"
#include <iostream>
#include <boost/bind.hpp>
#include "Swiften/Queries/IQRouter.h"
#include "transport/BlockPayload.h"
#include "Swiften/Swiften.h"
#include "transport/usermanager.h"
#include "transport/user.h"
#include "transport/buddy.h"
#include "transport/rostermanager.h"
#include "transport/memoryusage.h"
#include "transport/conversationmanager.h"
#include "transport/rostermanager.h"
#include "transport/usermanager.h"
#include "transport/networkpluginserver.h"
#include "log4cxx/logger.h"
using namespace log4cxx;
using namespace Swift;
using namespace boost;
namespace Transport {
static LoggerPtr logger = Logger::getLogger("StatsResponder");
StatsResponder::StatsResponder(Component *component, UserManager *userManager, NetworkPluginServer *server, StorageBackend *storageBackend) : Swift::Responder<StatsPayload>(component->getIQRouter()) {
m_component = component;
m_userManager = userManager;
m_server = server;
m_storageBackend = storageBackend;
m_start = time(0);
}
StatsResponder::~StatsResponder() {
}
unsigned long StatsResponder::usedMemory() {
double shared = 0;
double rss = 0;
#ifndef WIN32
process_mem_usage(shared, rss);
#endif
rss -= shared;
const std::list <NetworkPluginServer::Backend *> &backends = m_server->getBackends();
BOOST_FOREACH(NetworkPluginServer::Backend * backend, backends) {
rss += backend->res - backend->shared;
}
return (unsigned long) rss;
}
bool StatsResponder::handleGetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<StatsPayload> stats) {
boost::shared_ptr<StatsPayload> response(new StatsPayload());
if (stats->getItems().empty()) {
response->addItem(StatsPayload::Item("uptime"));
response->addItem(StatsPayload::Item("users/online"));
response->addItem(StatsPayload::Item("contacts/online"));
response->addItem(StatsPayload::Item("contacts/total"));
response->addItem(StatsPayload::Item("backends"));
response->addItem(StatsPayload::Item("memory-usage"));
}
else {
unsigned long contactsOnline = 0;
unsigned long contactsTotal = 0;
Swift::StatusShow s;
std::string statusMessage;
for (std::map<std::string, User *>::const_iterator it = m_userManager->getUsers().begin(); it != m_userManager->getUsers().end(); it++) {
if (!(*it).second) {
continue;
}
const RosterManager::BuddiesMap &buddies = (*it).second->getRosterManager()->getBuddies();
contactsTotal += buddies.size();
for(RosterManager::BuddiesMap::const_iterator bt = buddies.begin(); bt != buddies.end(); bt++) {
if (!(*bt).second) {
continue;
}
if (!(*bt).second->getStatus(s, statusMessage))
continue;
if (s.getType() != Swift::StatusShow::None) {
contactsOnline++;
}
}
}
BOOST_FOREACH(const StatsPayload::Item &item, stats->getItems()) {
if (item.getName() == "uptime") {
response->addItem(StatsPayload::Item("uptime", "seconds", boost::lexical_cast<std::string>(time(0) - m_start)));
}
else if (item.getName() == "users/online") {
response->addItem(StatsPayload::Item("users/online", "users", boost::lexical_cast<std::string>(m_userManager->getUserCount())));
}
else if (item.getName() == "backends") {
response->addItem(StatsPayload::Item("backends", "backends", boost::lexical_cast<std::string>(m_server->getBackendCount())));
}
else if (item.getName() == "memory-usage") {
response->addItem(StatsPayload::Item("memory-usage", "KB", boost::lexical_cast<std::string>(usedMemory())));
}
else if (item.getName() == "contacts/online") {
response->addItem(StatsPayload::Item("contacts/online", "contacts", boost::lexical_cast<std::string>(contactsOnline)));
}
else if (item.getName() == "contacts/total") {
response->addItem(StatsPayload::Item("contacts/total", "contacts", boost::lexical_cast<std::string>(contactsTotal)));
}
}
}
sendResponse(from, id, response);
return true;
}
bool StatsResponder::handleSetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<StatsPayload> stats) {
return false;
}
}

View file

@ -24,6 +24,7 @@ class RosterManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
CPPUNIT_TEST_SUITE(RosterManagerTest);
CPPUNIT_TEST(setBuddy);
CPPUNIT_TEST(sendCurrentPresences);
CPPUNIT_TEST(sendCurrentPresence);
CPPUNIT_TEST_SUITE_END();
public:
@ -132,13 +133,32 @@ class RosterManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
user->getRosterManager()->sendCurrentPresences("user@localhost/resource");
CPPUNIT_ASSERT_EQUAL(2, (int) received.size());
// CPPUNIT_ASSERT(dynamic_cast<Swift::Presence *>(getStanza(received[2])));
// CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::Away, dynamic_cast<Swift::Presence *>(getStanza(received[2]))->getShow());
// CPPUNIT_ASSERT_EQUAL(std::string("status1"), dynamic_cast<Swift::Presence *>(getStanza(received[2]))->getStatus());
//
// CPPUNIT_ASSERT(dynamic_cast<Swift::Presence *>(getStanza(received[3])));
// CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::Away, dynamic_cast<Swift::Presence *>(getStanza(received[3]))->getShow());
// CPPUNIT_ASSERT_EQUAL(std::string("status2"), dynamic_cast<Swift::Presence *>(getStanza(received[3]))->getStatus());
for (int i = 0; i < 2; i++) {
CPPUNIT_ASSERT(dynamic_cast<Swift::Presence *>(getStanza(received[i])));
CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::Away, dynamic_cast<Swift::Presence *>(getStanza(received[i]))->getShow());
CPPUNIT_ASSERT_EQUAL(std::string("user@localhost/resource"), dynamic_cast<Swift::Presence *>(getStanza(received[i]))->getTo().toString());
}
}
void sendCurrentPresence() {
setBuddy();
received.clear();
User *user = userManager->getUser("user@localhost");
user->getRosterManager()->sendCurrentPresence("buddy1@localhost", "user@localhost/resource");
CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
CPPUNIT_ASSERT(dynamic_cast<Swift::Presence *>(getStanza(received[0])));
CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::Away, 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());
received.clear();
user->getRosterManager()->sendCurrentPresence("buddy_unknown@localhost", "user@localhost/resource");
CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
CPPUNIT_ASSERT(dynamic_cast<Swift::Presence *>(getStanza(received[0])));
CPPUNIT_ASSERT_EQUAL(Swift::Presence::Unavailable, dynamic_cast<Swift::Presence *>(getStanza(received[0]))->getType());
CPPUNIT_ASSERT_EQUAL(std::string("user@localhost/resource"), dynamic_cast<Swift::Presence *>(getStanza(received[0]))->getTo().toString());
}
void disconnectUser() {

45
src/tests/util.cpp Normal file
View file

@ -0,0 +1,45 @@
#include "transport/userregistry.h"
#include "transport/config.h"
#include "transport/storagebackend.h"
#include "transport/user.h"
#include "transport/transport.h"
#include "transport/conversation.h"
#include "transport/usermanager.h"
#include "transport/localbuddy.h"
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
#include <Swiften/Swiften.h>
#include <Swiften/EventLoop/DummyEventLoop.h>
#include <Swiften/Server/Server.h>
#include <Swiften/Network/DummyNetworkFactories.h>
#include <Swiften/Network/DummyConnectionServer.h>
#include "Swiften/Server/ServerStanzaChannel.h"
#include "Swiften/Server/ServerFromClientSession.h"
#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h"
#include "basictest.h"
#include "transport/util.h"
using namespace Transport;
class UtilTest : public CPPUNIT_NS :: TestFixture{
CPPUNIT_TEST_SUITE(UtilTest);
CPPUNIT_TEST(encryptDecryptPassword);
CPPUNIT_TEST_SUITE_END();
public:
void setUp (void) {
}
void tearDown (void) {
}
void encryptDecryptPassword() {
std::string encrypted = Util::encryptPassword("password", "key");
CPPUNIT_ASSERT_EQUAL(std::string("password"), Util::decryptPassword(encrypted, "key"));
}
};
CPPUNIT_TEST_SUITE_REGISTRATION (UtilTest);

View file

@ -34,6 +34,8 @@
#include "Swiften/Serializer/PayloadSerializers/AttentionSerializer.h"
#include "Swiften/Parser/PayloadParsers/XHTMLIMParser.h"
#include "Swiften/Serializer/PayloadSerializers/XHTMLIMSerializer.h"
#include "Swiften/Parser/PayloadParsers/StatsParser.h"
#include "Swiften/Serializer/PayloadSerializers/StatsSerializer.h"
#include "transport/BlockParser.h"
#include "transport/BlockSerializer.h"
#include "Swiften/Parser/PayloadParsers/InvisibleParser.h"
@ -90,11 +92,13 @@ Component::Component(Swift::EventLoop *loop, Swift::NetworkFactories *factories,
m_server->addPayloadParserFactory(new GenericPayloadParserFactory<Swift::XHTMLIMParser>("html", "http://jabber.org/protocol/xhtml-im"));
m_server->addPayloadParserFactory(new GenericPayloadParserFactory<Transport::BlockParser>("block", "urn:xmpp:block:0"));
m_server->addPayloadParserFactory(new GenericPayloadParserFactory<Swift::InvisibleParser>("invisible", "urn:xmpp:invisible:0"));
m_server->addPayloadParserFactory(new GenericPayloadParserFactory<Swift::StatsParser>("query", "http://jabber.org/protocol/stats"));
m_server->addPayloadSerializer(new Swift::AttentionSerializer());
m_server->addPayloadSerializer(new Swift::XHTMLIMSerializer());
m_server->addPayloadSerializer(new Transport::BlockSerializer());
m_server->addPayloadSerializer(new Swift::InvisibleSerializer());
m_server->addPayloadSerializer(new Swift::StatsSerializer());
m_server->onDataRead.connect(boost::bind(&Component::handleDataRead, this, _1));
m_server->onDataWritten.connect(boost::bind(&Component::handleDataWritten, this, _1));
@ -113,11 +117,13 @@ Component::Component(Swift::EventLoop *loop, Swift::NetworkFactories *factories,
m_component->addPayloadParserFactory(new GenericPayloadParserFactory<Swift::XHTMLIMParser>("html", "http://jabber.org/protocol/xhtml-im"));
m_component->addPayloadParserFactory(new GenericPayloadParserFactory<Transport::BlockParser>("block", "urn:xmpp:block:0"));
m_component->addPayloadParserFactory(new GenericPayloadParserFactory<Swift::InvisibleParser>("invisible", "urn:xmpp:invisible:0"));
m_component->addPayloadParserFactory(new GenericPayloadParserFactory<Swift::StatsParser>("query", "http://jabber.org/protocol/stats"));
m_component->addPayloadSerializer(new Swift::AttentionSerializer());
m_component->addPayloadSerializer(new Swift::XHTMLIMSerializer());
m_component->addPayloadSerializer(new Transport::BlockSerializer());
m_component->addPayloadSerializer(new Swift::InvisibleSerializer());
m_component->addPayloadSerializer(new Swift::StatsSerializer());
m_stanzaChannel = m_component->getStanzaChannel();
m_iqRouter = m_component->getIQRouter();

View file

@ -43,7 +43,7 @@ namespace Transport {
static LoggerPtr logger = Logger::getLogger("User");
User::User(const Swift::JID &jid, UserInfo &userInfo, Component *component, UserManager *userManager) {
m_jid = jid;
m_jid = jid.toBare();
m_data = NULL;
m_component = component;
@ -54,6 +54,7 @@ User::User(const Swift::JID &jid, UserInfo &userInfo, Component *component, User
m_connected = false;
m_readyForConnect = false;
m_ignoreDisconnect = false;
m_resources = 0;
m_reconnectTimer = m_component->getNetworkFactories()->getTimerFactory()->createTimer(10000);
m_reconnectTimer->onTick.connect(boost::bind(&User::onConnectingTimeout, this));
@ -96,6 +97,10 @@ Swift::JID User::getJIDWithFeature(const std::string &feature) {
else {
continue;
}
if (!discoInfo) {
continue;
}
#else
continue;
#endif
@ -129,30 +134,37 @@ void User::sendCurrentPresence() {
return;
}
if (m_connected) {
Swift::Presence::ref highest = m_presenceOracle->getHighestPriorityPresence(m_jid.toBare());
if (highest) {
Swift::Presence::ref response = Swift::Presence::create(highest);
response->setTo(m_jid);
response->setFrom(m_component->getJID());
m_component->getStanzaChannel()->sendPresence(response);
std::vector<Swift::Presence::ref> presences = m_presenceOracle->getAllPresence(m_jid);
foreach(Swift::Presence::ref presence, presences) {
if (presence->getType() == Swift::Presence::Unavailable) {
continue;
}
if (m_connected) {
Swift::Presence::ref highest = m_presenceOracle->getHighestPriorityPresence(m_jid.toBare());
if (highest) {
Swift::Presence::ref response = Swift::Presence::create(highest);
response->setTo(presence->getFrom());
response->setFrom(m_component->getJID());
m_component->getStanzaChannel()->sendPresence(response);
}
else {
Swift::Presence::ref response = Swift::Presence::create();
response->setTo(presence->getFrom());
response->setFrom(m_component->getJID());
response->setType(Swift::Presence::Unavailable);
m_component->getStanzaChannel()->sendPresence(response);
}
}
else {
Swift::Presence::ref response = Swift::Presence::create();
response->setTo(m_jid.toBare());
response->setTo(presence->getFrom());
response->setFrom(m_component->getJID());
response->setType(Swift::Presence::Unavailable);
response->setStatus("Connecting");
m_component->getStanzaChannel()->sendPresence(response);
}
}
else {
Swift::Presence::ref response = Swift::Presence::create();
response->setTo(m_jid.toBare());
response->setFrom(m_component->getJID());
response->setType(Swift::Presence::Unavailable);
response->setStatus("Connecting");
m_component->getStanzaChannel()->sendPresence(response);
}
}
void User::setConnected(bool connected) {
@ -164,6 +176,10 @@ void User::setConnected(bool connected) {
}
void User::handlePresence(Swift::Presence::ref presence) {
int currentResourcesCount = m_presenceOracle->getAllPresence(m_jid).size();
m_conversationManager->resetResources();
if (!m_connected) {
// we are not connected to legacy network, so we should do it when disco#info arrive :)
if (m_readyForConnect == false) {
@ -210,12 +226,35 @@ void User::handlePresence(Swift::Presence::ref presence) {
if (presence->getPayload<Swift::MUCPayload>() != NULL) {
password = presence->getPayload<Swift::MUCPayload>()->getPassword() ? *presence->getPayload<Swift::MUCPayload>()->getPassword() : "";
}
onRoomJoined(room, presence->getTo().getResource(), password);
onRoomJoined(presence->getFrom(), room, presence->getTo().getResource(), password);
}
return;
}
sendCurrentPresence();
// User wants to disconnect this resource
if (!m_component->inServerMode()) {
if (presence->getType() == Swift::Presence::Unavailable) {
// Send unavailable presences for online contacts
m_rosterManager->sendUnavailablePresences(presence->getFrom());
// Send unavailable presence for transport contact itself
Swift::Presence::ref response = Swift::Presence::create();
response->setTo(presence->getFrom());
response->setFrom(m_component->getJID());
response->setType(Swift::Presence::Unavailable);
m_component->getStanzaChannel()->sendPresence(response);
}
else {
sendCurrentPresence();
// This resource is new, so we have to send buddies presences
if (currentResourcesCount != m_resources) {
m_rosterManager->sendCurrentPresences(presence->getFrom());
}
}
}
m_resources = currentResourcesCount;
// Change legacy network presence

View file

@ -149,7 +149,7 @@ void UserManager::handlePresence(Swift::Presence::ref presence) {
// Create user class if it's not there
if (!user) {
// Admin user is not legacy network user, so do not create User class instance for him
if (CONFIG_STRING(m_component->getConfig(), "service.admin_username") == presence->getFrom().getNode()) {
if (m_component->inServerMode() && CONFIG_STRING(m_component->getConfig(), "service.admin_jid") == presence->getFrom().toBare().toString()) {
return;
}
@ -319,6 +319,11 @@ void UserManager::handleSubscription(Swift::Presence::ref presence) {
return;
}
// Don't let RosterManager to handle presences for us
if (presence->getTo().getNode().empty()) {
return;
}
User *user = getUser(presence->getFrom().toBare().toString());
if (user) {

View file

@ -181,7 +181,7 @@ bool UserRegistration::handleGetRequest(const Swift::JID& from, const Swift::JID
bool registered = m_storageBackend->getUser(barejid, res);
std::string instructions = CONFIG_STRING(m_config, "registration.instructions");
std::string usernameField = CONFIG_STRING(m_config, "registration.username_field");
std::string usernameField = CONFIG_STRING(m_config, "registration.username_label");
// normal jabber:iq:register
reg->setInstructions(instructions);
@ -219,20 +219,21 @@ bool UserRegistration::handleGetRequest(const Swift::JID& from, const Swift::JID
ListSingleFormField::ref language = ListSingleFormField::create();
language->setName("language");
language->setLabel((("Language")));
language->addOption(Swift::FormField::Option(CONFIG_STRING(m_config, "registration.language"), CONFIG_STRING(m_config, "registration.language")));
if (registered)
language->setValue(res.language);
else
language->setValue(CONFIG_STRING(m_config, "registration.language"));
form->addField(language);
TextSingleFormField::ref encoding = TextSingleFormField::create();
encoding->setName("encoding");
encoding->setLabel((("Encoding")));
if (registered)
encoding->setValue(res.encoding);
else
encoding->setValue(CONFIG_STRING(m_config, "registration.encoding"));
form->addField(encoding);
// TextSingleFormField::ref encoding = TextSingleFormField::create();
// encoding->setName("encoding");
// encoding->setLabel((("Encoding")));
// if (registered)
// encoding->setValue(res.encoding);
// else
// encoding->setValue(CONFIG_STRING(m_config, "registration.encoding"));
// form->addField(encoding);
if (registered) {
BooleanFormField::ref boolean = BooleanFormField::create();
@ -328,10 +329,7 @@ bool UserRegistration::handleSetRequest(const Swift::JID& from, const Swift::JID
}
// Register or change password
if (payload->getUsername()->empty() ||
(payload->getPassword()->empty() && CONFIG_STRING(m_config, "service.protocol") != "twitter" && CONFIG_STRING(m_config, "service.protocol") != "bonjour")
)
{
if (payload->getUsername()->empty()) {
sendError(from, id, ErrorPayload::NotAcceptable, ErrorPayload::Modify);
return true;
}

View file

@ -75,6 +75,34 @@ void removeEverythingOlderThan(const std::vector<std::string> &dirs, time_t t) {
}
}
std::string encryptPassword(const std::string &password, const std::string &key) {
std::string encrypted;
encrypted.resize(password.size());
for (int i = 0; i < password.size(); i++) {
char c = password[i];
char keychar = key[i % key.size()];
c += keychar;
encrypted[i] = c;
}
encrypted = Swift::Base64::encode(Swift::createByteArray(encrypted));
return encrypted;
}
std::string decryptPassword(std::string &encrypted, const std::string &key) {
encrypted = Swift::byteArrayToString(Swift::Base64::decode(encrypted));
std::string password;
password.resize(encrypted.size());
for (int i = 0; i < encrypted.size(); i++) {
char c = encrypted[i];
char keychar = key[i % key.size()];
c -= keychar;
password[i] = c;
}
return password;
}
}
}

View file

@ -1,5 +0,0 @@
ADD_SUBDIRECTORY(login)
ADD_SUBDIRECTORY(login_bad_name)
ADD_SUBDIRECTORY(login_bad_name2)
add_custom_target(tests python runtests.py WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})

View file

@ -1,6 +0,0 @@
FILE(GLOB SRC *.cpp)
ADD_EXECUTABLE(login_test ${SRC})
TARGET_LINK_LIBRARIES(login_test transport ${SWIFTEN_LIBRARIES})

View file

@ -1,44 +0,0 @@
#include <iostream>
#include <boost/bind.hpp>
#include <Swiften/Swiften.h>
#include <Swiften/Client/ClientOptions.h>
using namespace Swift;
using namespace boost;
Client* client;
static void handleDisconnected(const boost::optional<ClientError> &) {
exit(1);
}
static void handleConnected() {
exit(0);
}
static void handleMessageReceived(Message::ref message) {
// Echo back the incoming message
message->setTo(message->getFrom());
message->setFrom(JID());
client->sendMessage(message);
}
int main(int, char **argv) {
SimpleEventLoop eventLoop;
BoostNetworkFactories networkFactories(&eventLoop);
client = new Client(argv[1], argv[2], &networkFactories);
client->setAlwaysTrustCertificates();
client->onConnected.connect(&handleConnected);
client->onDisconnected.connect(bind(&handleDisconnected, _1));
client->onMessageReceived.connect(bind(&handleMessageReceived, _1));
Swift::ClientOptions opt;
opt.allowPLAINWithoutTLS = true;
client->connect(opt);
eventLoop.run();
delete client;
return 0;
}

View file

@ -1,6 +0,0 @@
FILE(GLOB SRC *.cpp)
ADD_EXECUTABLE(login_bad_name_test ${SRC})
TARGET_LINK_LIBRARIES(login_bad_name_test transport ${SWIFTEN_LIBRARIES})

View file

@ -1,45 +0,0 @@
#include <iostream>
#include <boost/bind.hpp>
#include <Swiften/Swiften.h>
#include <Swiften/Client/ClientOptions.h>
using namespace Swift;
using namespace boost;
Client* client;
static void handleDisconnected(const boost::optional<ClientError> &error) {
exit(error->getType() != ClientError::AuthenticationFailedError);
}
static void handleConnected() {
exit(1);
}
static void handleMessageReceived(Message::ref message) {
// Echo back the incoming message
message->setTo(message->getFrom());
message->setFrom(JID());
client->sendMessage(message);
}
int main(int, char **argv) {
SimpleEventLoop eventLoop;
BoostNetworkFactories networkFactories(&eventLoop);
JID jid(JID(argv[1]).getNode() + "something", JID(argv[1]).getDomain());
client = new Client(jid, argv[2], &networkFactories);
client->setAlwaysTrustCertificates();
client->onConnected.connect(&handleConnected);
client->onDisconnected.connect(bind(&handleDisconnected, _1));
client->onMessageReceived.connect(bind(&handleMessageReceived, _1));
Swift::ClientOptions opt;
opt.allowPLAINWithoutTLS = true;
client->connect(opt);
eventLoop.run();
delete client;
return 0;
}

View file

@ -1,6 +0,0 @@
FILE(GLOB SRC *.cpp)
ADD_EXECUTABLE(login_bad_name2_test ${SRC})
TARGET_LINK_LIBRARIES(login_bad_name2_test transport ${SWIFTEN_LIBRARIES})

View file

@ -1,45 +0,0 @@
#include <iostream>
#include <boost/bind.hpp>
#include <Swiften/Swiften.h>
#include <Swiften/Client/ClientOptions.h>
using namespace Swift;
using namespace boost;
Client* client;
static void handleDisconnected(const boost::optional<ClientError> &error) {
exit(error->getType() != ClientError::AuthenticationFailedError);
}
static void handleConnected() {
exit(1);
}
static void handleMessageReceived(Message::ref message) {
// Echo back the incoming message
message->setTo(message->getFrom());
message->setFrom(JID());
client->sendMessage(message);
}
int main(int, char **argv) {
SimpleEventLoop eventLoop;
BoostNetworkFactories networkFactories(&eventLoop);
JID jid(std::string("something") + JID(argv[1]).getNode(), JID(argv[1]).getDomain());
client = new Client(jid, argv[2], &networkFactories);
client->setAlwaysTrustCertificates();
client->onConnected.connect(&handleConnected);
client->onDisconnected.connect(bind(&handleDisconnected, _1));
client->onMessageReceived.connect(bind(&handleMessageReceived, _1));
Swift::ClientOptions opt;
opt.allowPLAINWithoutTLS = true;
client->connect(opt);
eventLoop.run();
delete client;
return 0;
}

View file

@ -1,70 +0,0 @@
import os
import sys
from subprocess import *
import time
def run_spectrum(backend, test):
os.system("rm test.sql")
f = open("sample.cfg", "w")
f.write("\
[service]\n\
jid = localhost\n\
password = secret\n\
server = 127.0.0.1\n\
port = 5222\n\
server_mode = 1\n\
backend=../backends/%s/%s_backend\n\
protocol=prpl-jabber\n\
\
[database]\n\
database = test.sql\n\
prefix=icq\n\
" % (backend, backend)
)
f.close()
p = Popen("../spectrum/src/spectrum sample.cfg > " + backend + "_" + test + ".log 2>&1", shell=True)
time.sleep(4)
return p
def one_test_run():
os.system("killall spectrum 2> /dev/null")
os.system("rm *.log")
for backend in os.listdir("../backends"):
if not os.path.isdir("../backends/" + backend) or backend == "CMakeFiles":
continue
for d in os.listdir("."):
binary = d + "/" + d + "_test"
if not os.path.exists(binary):
continue
if os.path.exists(d + "/.no" + backend):
continue
p = run_spectrum(backend, d)
if backend.find("purple") >= 0:
p = Popen(binary + " pyjim%jabber.cz@localhost test", shell=True)
else:
p = Popen(binary + " testnickname%irc.freenode.net@localhost test", shell=True)
seconds = 0
while p.poll() is None and seconds < 20:
time.sleep(1)
seconds += 1
if p.returncode == 0 and seconds < 20:
print "[ PASS ]", backend, binary
else:
if seconds == 20:
print "[ TIME ]", backend, binary
else:
print "[ FAIL ]", backend, binary
os.system("killall spectrum 2> /dev/null")
one_test_run()