diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a3398e5..75aca2ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,7 +54,7 @@ find_package(event) find_package(Doxygen) INCLUDE(FindQt4) -FIND_PACKAGE(Qt4 COMPONENTS QtCore) +FIND_PACKAGE(Qt4 COMPONENTS QtCore QtNetwork REQUIRED) # ADD_DEFINITIONS(${SWIFTEN_CFLAGS}) ADD_DEFINITIONS(-DSUPPORT_LEGACY_CAPS) @@ -104,6 +104,7 @@ if (PROTOBUF_FOUND) if(IRC_FOUND) ADD_DEFINITIONS(-DIRC_SHARED) message("IRC plugin : yes") + include_directories(${QT_QTNETWORK_INCLUDE_DIR}) include_directories(${IRC_INCLUDE_DIR}) include(${QT_USE_FILE}) else() diff --git a/backends/libircclient-qt/ircnetworkplugin.cpp b/backends/libircclient-qt/ircnetworkplugin.cpp new file mode 100644 index 00000000..2ebe91d9 --- /dev/null +++ b/backends/libircclient-qt/ircnetworkplugin.cpp @@ -0,0 +1,126 @@ +#include "ircnetworkplugin.h" + +IRCNetworkPlugin::IRCNetworkPlugin(Config *config, Swift::QtEventLoop *loop, const std::string &host, int port) { + this->config = config; + m_socket = new QTcpSocket(); + m_socket->connectToHost(QString::fromStdString(host), port); + connect(m_socket, SIGNAL(readyRead()), this, SLOT(readData())); +} + +void IRCNetworkPlugin::readData() { + size_t availableBytes = m_socket->bytesAvailable(); + if (availableBytes == 0) + return; + + std::cout << "READ\n"; + std::string d = std::string(m_socket->readAll().data(), availableBytes); + handleDataRead(d); +} + +void IRCNetworkPlugin::sendData(const std::string &string) { + m_socket->write(string.c_str(), string.size()); +} + +void IRCNetworkPlugin::handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) { + // Server is in server-mode, so user is JID of server when we want to connect + if (CONFIG_BOOL(config, "service.server_mode")) { + MyIrcSession *session = new MyIrcSession(user, this); + std::string h = user.substr(0, user.find("@")); + session->setNick(QString::fromStdString(h.substr(0, h.find("%")))); + session->connectToServer(QString::fromStdString(h.substr(h.find("%") + 1)), 6667); + std::cout << "CONNECTING IRC NETWORK " << h.substr(h.find("%") + 1) << "\n"; + m_sessions[user] = session; + } + else { + handleConnected(user); + } +} + +void IRCNetworkPlugin::handleLogoutRequest(const std::string &user, const std::string &legacyName) { + if (m_sessions[user] == NULL) + return; + m_sessions[user]->disconnectFromServer(); + m_sessions[user]->deleteLater(); + m_sessions.erase(user); +} + +void IRCNetworkPlugin::handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &/*xhtml*/) { + std::string u = user; + std::cout << "AAAAA " << legacyName << "\n"; + if (!CONFIG_BOOL(config, "service.server_mode")) { + u = user + legacyName.substr(legacyName.find("@") + 1); + if (u.find("/") != std::string::npos) { + u = u.substr(0, u.find("/")); + } + } + if (m_sessions[u] == NULL) { + std::cout << "No session for " << u << "\n"; + return; + } + + std::string r = legacyName; + if (!CONFIG_BOOL(config, "service.server_mode")) { + if (legacyName.find("/") == std::string::npos) { + r = legacyName.substr(0, r.find("@")); + } + else { + r = legacyName.substr(legacyName.find("/") + 1); + } + } + std::cout << "MESSAGE " << u << " " << r << "\n"; + m_sessions[u]->message(QString::fromStdString(r), QString::fromStdString(message)); + std::cout << "SENT\n"; +} + +void IRCNetworkPlugin::handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &password) { + std::cout << "JOIN\n"; + std::string r = room; + std::string u = user; + if (!CONFIG_BOOL(config, "service.server_mode")) { + u = user + room.substr(room.find("@") + 1); + r = room.substr(0, room.find("@")); + } + if (m_sessions[u] == NULL) { + // in gateway mode we want to login this user to network according to legacyName + if (room.find("@") != std::string::npos) { + // suffix is %irc.freenode.net to let MyIrcSession return #room%irc.freenode.net + MyIrcSession *session = new MyIrcSession(user, this, room.substr(room.find("@"))); + session->setNick(QString::fromStdString(nickname)); + session->connectToServer(QString::fromStdString(room.substr(room.find("@") + 1)), 6667); + std::cout << "CONNECTING IRC NETWORK " << room.substr(room.find("@") + 1) << "\n"; + std::cout << "SUFFIX " << room.substr(room.find("@")) << "\n"; + m_sessions[u] = session; + } + else { + return; + } + } + std::cout << "JOINING " << r << "\n"; + m_sessions[u]->addAutoJoinChannel(QString::fromStdString(r)); + m_sessions[u]->join(QString::fromStdString(r), QString::fromStdString(password)); + m_sessions[u]->rooms += 1; + // update nickname, because we have nickname per session, no nickname per room. + handleRoomNicknameChanged(user, r, m_sessions[u]->nick().toStdString()); +} + +void IRCNetworkPlugin::handleLeaveRoomRequest(const std::string &user, const std::string &room) { + std::string r = room; + std::string u = user; + if (!CONFIG_BOOL(config, "service.server_mode")) { + r = room.substr(0, room.find("@")); + u = user + room.substr(room.find("@") + 1); + } + + if (m_sessions[u] == NULL) + return; + + m_sessions[u]->part(QString::fromStdString(r)); + m_sessions[u]->removeAutoJoinChannel(QString::fromStdString(r)); + m_sessions[u]->rooms -= 1; + + if (m_sessions[u]->rooms <= 0) { + m_sessions[u]->disconnectFromServer(); + m_sessions[u]->deleteLater(); + m_sessions.erase(u); + } +} diff --git a/backends/libircclient-qt/ircnetworkplugin.h b/backends/libircclient-qt/ircnetworkplugin.h new file mode 100644 index 00000000..c15dc9a1 --- /dev/null +++ b/backends/libircclient-qt/ircnetworkplugin.h @@ -0,0 +1,38 @@ + +#pragma once + +#include "transport/config.h" +#include "transport/networkplugin.h" +#include "session.h" +#include +#include +#include "Swiften/EventLoop/Qt/QtEventLoop.h" +#include "ircnetworkplugin.h" + + +class IRCNetworkPlugin : public QObject, public NetworkPlugin { + Q_OBJECT + + public: + IRCNetworkPlugin(Config *config, Swift::QtEventLoop *loop, const std::string &host, int port); + + void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password); + + void handleLogoutRequest(const std::string &user, const std::string &legacyName); + + void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &/*xhtml*/); + + void handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &password); + + void handleLeaveRoomRequest(const std::string &user, const std::string &room); + + std::map m_sessions; + + public slots: + void readData(); + void sendData(const std::string &string); + + private: + Config *config; + QTcpSocket *m_socket; +}; \ No newline at end of file diff --git a/backends/libircclient-qt/main.cpp b/backends/libircclient-qt/main.cpp index 7def0fbc..83723532 100644 --- a/backends/libircclient-qt/main.cpp +++ b/backends/libircclient-qt/main.cpp @@ -12,67 +12,15 @@ #include "transport/networkplugin.h" #include "session.h" #include +#include #include "Swiften/EventLoop/Qt/QtEventLoop.h" +#include "ircnetworkplugin.h" using namespace boost::program_options; using namespace Transport; -class IRCNetworkPlugin; IRCNetworkPlugin * np = NULL; -class IRCNetworkPlugin : public NetworkPlugin { - public: - IRCNetworkPlugin(Config *config, Swift::QtEventLoop *loop, const std::string &host, int port) : NetworkPlugin() { - this->config = config; - } - - void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) { - MyIrcSession *session = new MyIrcSession(user, this); - session->setNick(QString::fromStdString(user.substr(0, user.find("@")))); - session->connectToServer(QString::fromStdString(user.substr(user.find("@") + 1)), 6667); -// std::cout << "CONNECTING IRC NETWORK " << jid.getNode() << " " << jid.getDomain() << "\n"; - m_sessions[user] = session; - } - - void handleLogoutRequest(const std::string &user, const std::string &legacyName) { - if (m_sessions[user] == NULL) - return; - m_sessions[user]->disconnectFromServer(); - m_sessions[user]->deleteLater(); - } - - void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &/*xhtml*/) { - std::cout << "MESSAGE " << user << " " << legacyName << "\n"; - if (m_sessions[user] == NULL) - return; - m_sessions[user]->message(QString::fromStdString(legacyName), QString::fromStdString(message)); - std::cout << "SENT\n"; - } - - void handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &password) { - std::cout << "JOIN\n"; - if (m_sessions[user] == NULL) - return; - m_sessions[user]->addAutoJoinChannel(QString::fromStdString(room)); - m_sessions[user]->join(QString::fromStdString(room), QString::fromStdString(password)); - // update nickname, because we have nickname per session, no nickname per room. - handleRoomNicknameChanged(user, room, m_sessions[user]->nick().toStdString()); - } - - void handleLeaveRoomRequest(const std::string &user, const std::string &room) { - std::cout << "PART\n"; - if (m_sessions[user] == NULL) - return; - m_sessions[user]->part(QString::fromStdString(room)); - m_sessions[user]->removeAutoJoinChannel(QString::fromStdString(room)); - } - - std::map m_sessions; - - private: - Config *config; -}; - int main (int argc, char* argv[]) { std::string host; int port; diff --git a/backends/libircclient-qt/session.cpp b/backends/libircclient-qt/session.cpp index ed2b1674..792bceed 100644 --- a/backends/libircclient-qt/session.cpp +++ b/backends/libircclient-qt/session.cpp @@ -13,10 +13,12 @@ #include #include "Swiften/Elements/StatusShow.h" -MyIrcSession::MyIrcSession(const std::string &user, NetworkPlugin *np, QObject* parent) : Irc::Session(parent) +MyIrcSession::MyIrcSession(const std::string &user, NetworkPlugin *np, const std::string &suffix, QObject* parent) : Irc::Session(parent) { this->np = np; this->user = user; + this->suffix = suffix; + rooms = 0; connect(this, SIGNAL(disconnected()), SLOT(on_disconnected())); } @@ -26,8 +28,9 @@ void MyIrcSession::on_connected(){ void MyIrcSession::on_disconnected() { - std::cout << "disconnected:\n"; - np->handleDisconnected(user, 0, ""); + std::cout << "disconnected:\n"; + if (suffix.empty()) + np->handleDisconnected(user, 0, ""); } void MyIrcSession::on_bufferAdded(Irc::Buffer* buffer) @@ -42,14 +45,15 @@ void MyIrcSession::on_bufferRemoved(Irc::Buffer* buffer) Irc::Buffer* MyIrcSession::createBuffer(const QString& receiver) { - return new MyIrcBuffer(receiver, user, np, this); + return new MyIrcBuffer(receiver, user, np, suffix, this); } -MyIrcBuffer::MyIrcBuffer(const QString& receiver, const std::string &user, NetworkPlugin *np, Irc::Session* parent) +MyIrcBuffer::MyIrcBuffer(const QString& receiver, const std::string &user, NetworkPlugin *np, const std::string &suffix, Irc::Session* parent) : Irc::Buffer(receiver, parent) { this->np = np; this->user = user; + this->suffix = suffix; p = (MyIrcSession *) parent; connect(this, SIGNAL(receiverChanged(QString)), SLOT(on_receiverChanged(QString))); connect(this, SIGNAL(joined(QString)), SLOT(on_joined(QString))); @@ -94,7 +98,7 @@ void MyIrcBuffer::on_joined(const QString& origin) { bool flags = 0; std::string nickname = origin.toStdString(); flags = correctNickname(nickname); - np->handleParticipantChanged(user, origin.toStdString(), receiver().toStdString(), (int) flags, pbnetwork::STATUS_ONLINE); + np->handleParticipantChanged(user, origin.toStdString(), receiver().toStdString() + suffix, (int) flags, pbnetwork::STATUS_ONLINE); } void MyIrcBuffer::on_parted(const QString& origin, const QString& message) { @@ -102,7 +106,7 @@ void MyIrcBuffer::on_parted(const QString& origin, const QString& message) { bool flags = 0; std::string nickname = origin.toStdString(); flags = correctNickname(nickname); - np->handleParticipantChanged(user, nickname, receiver().toStdString(),(int) flags, pbnetwork::STATUS_NONE, message.toStdString()); + np->handleParticipantChanged(user, nickname, receiver().toStdString() + suffix,(int) flags, pbnetwork::STATUS_NONE, message.toStdString()); } void MyIrcBuffer::on_quit(const QString& origin, const QString& message) @@ -116,7 +120,7 @@ void MyIrcBuffer::on_nickChanged(const QString& origin, const QString& nick) { std::string nickname = origin.toStdString(); bool flags = p->m_modes[receiver().toStdString() + nickname]; // std::cout << receiver().toStdString() + nickname << " " << flags << "\n"; - np->handleParticipantChanged(user, nickname, receiver().toStdString(),(int) flags, pbnetwork::STATUS_ONLINE, "", nick.toStdString()); + np->handleParticipantChanged(user, nickname, receiver().toStdString() + suffix,(int) flags, pbnetwork::STATUS_ONLINE, "", nick.toStdString()); } void MyIrcBuffer::on_modeChanged(const QString& origin, const QString& mode, const QString& args) { @@ -132,13 +136,13 @@ void MyIrcBuffer::on_modeChanged(const QString& origin, const QString& mode, con p->m_modes[receiver().toStdString() + nickname] = 0; } bool flags = p->m_modes[receiver().toStdString() + nickname]; - np->handleParticipantChanged(user, nickname, receiver().toStdString(),(int) flags, pbnetwork::STATUS_ONLINE, ""); + np->handleParticipantChanged(user, nickname, receiver().toStdString() + suffix,(int) flags, pbnetwork::STATUS_ONLINE, ""); } void MyIrcBuffer::on_topicChanged(const QString& origin, const QString& topic) { //topic changed: "#testik" "HanzZ" "test" qDebug() << "topic changed:" << receiver() << origin << topic; - np->handleSubject(user, receiver().toStdString(), topic.toStdString(), origin.toStdString()); + np->handleSubject(user, receiver().toStdString() + suffix, topic.toStdString(), origin.toStdString()); } void MyIrcBuffer::on_invited(const QString& origin, const QString& receiver, const QString& channel) @@ -155,7 +159,17 @@ void MyIrcBuffer::on_messageReceived(const QString& origin, const QString& messa qDebug() << "message received:" << receiver() << origin << message << (flags & Irc::Buffer::IdentifiedFlag ? "(identified!)" : "(not identified)"); if (!receiver().startsWith("#") && (flags & Irc::Buffer::EchoFlag)) return; - np->handleMessage(user, receiver().toStdString(), message.toStdString(), origin.toStdString()); + std::string r = receiver().toStdString(); +// if (!suffix.empty()) { +// r = receiver().replace('@', '%').toStdString(); +// } + + if (r.find("#") == 0) { + np->handleMessage(user, r + suffix, message.toStdString(), origin.toStdString()); + } + else { + np->handleMessage(user, r + suffix, message.toStdString()); + } } void MyIrcBuffer::on_noticeReceived(const QString& origin, const QString& notice, Irc::Buffer::MessageFlags flags) @@ -186,13 +200,14 @@ void MyIrcBuffer::on_numericMessageReceived(const QString& origin, uint code, co { switch (code) { case 251: - np->handleConnected(user); + if (suffix.empty()) + np->handleConnected(user); break; case 332: m_topicData = params.value(2).toStdString(); break; case 333: - np->handleSubject(user, params.value(1).toStdString(), m_topicData, params.value(2).toStdString()); + np->handleSubject(user, params.value(1).toStdString() + suffix, m_topicData, params.value(2).toStdString()); break; case 353: QString channel = params.value(2); @@ -203,12 +218,12 @@ void MyIrcBuffer::on_numericMessageReceived(const QString& origin, uint code, co std::string nickname = members.at(i).toStdString(); flags = correctNickname(nickname); p->m_modes[channel.toStdString() + nickname] = flags; -// std::cout << channel.toStdString() + nickname << " " << flags << "\n"; - np->handleParticipantChanged(user, nickname, channel.toStdString(),(int) flags, pbnetwork::STATUS_ONLINE); + std::cout << channel.toStdString() + suffix << " " << flags << "\n"; + np->handleParticipantChanged(user, nickname, channel.toStdString() + suffix,(int) flags, pbnetwork::STATUS_ONLINE); } break; } - qDebug() << "numeric message received:" << receiver() << origin << code << params; + qDebug() << "numeric message received:" << receiver() << origin << code << params; } void MyIrcBuffer::on_unknownMessageReceived(const QString& origin, const QStringList& params) diff --git a/backends/libircclient-qt/session.h b/backends/libircclient-qt/session.h index 1f9e021d..326ba4b4 100644 --- a/backends/libircclient-qt/session.h +++ b/backends/libircclient-qt/session.h @@ -22,8 +22,10 @@ class MyIrcSession : public Irc::Session Q_OBJECT public: - MyIrcSession(const std::string &user, NetworkPlugin *np, QObject* parent = 0); + MyIrcSession(const std::string &user, NetworkPlugin *np, const std::string &suffix = "", QObject* parent = 0); std::map m_modes; + std::string suffix; + int rooms; protected Q_SLOTS: void on_connected(); @@ -35,6 +37,7 @@ protected Q_SLOTS: protected: NetworkPlugin *np; std::string user; + virtual Irc::Buffer* createBuffer(const QString& receiver); }; @@ -43,11 +46,12 @@ class MyIrcBuffer : public Irc::Buffer Q_OBJECT public: - MyIrcBuffer(const QString& receiver, const std::string &user, NetworkPlugin *np, Irc::Session* parent); + MyIrcBuffer(const QString& receiver, const std::string &user, NetworkPlugin *np, const std::string &suffix, Irc::Session* parent); NetworkPlugin *np; std::string user; MyIrcSession *p; std::string m_topicData; + std::string suffix; protected Q_SLOTS: void on_receiverChanged(const QString& receiver); diff --git a/backends/libpurple/main.cpp b/backends/libpurple/main.cpp index 9e03792a..51943171 100644 --- a/backends/libpurple/main.cpp +++ b/backends/libpurple/main.cpp @@ -45,6 +45,7 @@ using namespace log4cxx; static LoggerPtr logger_libpurple = log4cxx::Logger::getLogger("libpurple"); static LoggerPtr logger = log4cxx::Logger::getLogger("backend"); int m_sock; +static int writeInput; using namespace Transport; @@ -61,6 +62,8 @@ template std::string stringOf(T object) { return (os.str()); } +static void transportDataReceived(gpointer data, gint source, PurpleInputCondition cond); + class SpectrumNetworkPlugin; GKeyFile *keyfile; @@ -73,6 +76,13 @@ static std::string KEYFILE_STRING(const std::string &cat, const std::string &key } std::string ret(str); free(str); + + if (ret.find("#") != std::string::npos) { + ret = ret.substr(0, ret.find("#")); + while(*(ret.end() - 1) == ' ') { + ret.erase(ret.end() - 1); + } + } return ret; } @@ -907,6 +917,8 @@ class SpectrumNetworkPlugin : public NetworkPlugin { void sendData(const std::string &string) { write(m_sock, string.c_str(), string.size()); + if (writeInput == 0) + writeInput = purple_input_add(m_sock, PURPLE_INPUT_WRITE, &transportDataReceived, NULL); } void readyForData() { @@ -1750,6 +1762,10 @@ static void transportDataReceived(gpointer data, gint source, PurpleInputConditi np->handleDataRead(d); } else { + if (writeInput != 0) { + purple_input_remove(writeInput); + writeInput = 0; + } np->readyForData(); } } @@ -1852,7 +1868,6 @@ int main(int argc, char **argv) { m_sock = create_socket(host, port); purple_input_add(m_sock, PURPLE_INPUT_READ, &transportDataReceived, NULL); -// purple_input_add(m_sock, PURPLE_INPUT_WRITE, &transportDataReceived, NULL); np = new SpectrumNetworkPlugin(host, port); bool libev = KEYFILE_STRING("service", "eventloop") == "libev"; diff --git a/cmake_modules/FindPackageHandleStandardArgs.cmake b/cmake_modules/FindPackageHandleStandardArgs.cmake deleted file mode 100644 index 1acb021e..00000000 --- a/cmake_modules/FindPackageHandleStandardArgs.cmake +++ /dev/null @@ -1,260 +0,0 @@ -# FIND_PACKAGE_HANDLE_STANDARD_ARGS( ... ) -# -# This function is intended to be used in FindXXX.cmake modules files. -# It handles the REQUIRED, QUIET and version-related arguments to FIND_PACKAGE(). -# It also sets the _FOUND variable. -# The package is considered found if all variables ... listed contain -# valid results, e.g. valid filepaths. -# -# There are two modes of this function. The first argument in both modes is -# the name of the Find-module where it is called (in original casing). -# -# The first simple mode looks like this: -# FIND_PACKAGE_HANDLE_STANDARD_ARGS( (DEFAULT_MSG|"Custom failure message") ... ) -# If the variables to are all valid, then _FOUND -# will be set to TRUE. -# If DEFAULT_MSG is given as second argument, then the function will generate -# itself useful success and error messages. You can also supply a custom error message -# for the failure case. This is not recommended. -# -# The second mode is more powerful and also supports version checking: -# FIND_PACKAGE_HANDLE_STANDARD_ARGS(NAME [REQUIRED_VARS ...] -# [VERSION_VAR -# [CONFIG_MODE] -# [FAIL_MESSAGE "Custom failure message"] ) -# -# As above, if through are all valid, _FOUND -# will be set to TRUE. -# After REQUIRED_VARS the variables which are required for this package are listed. -# Following VERSION_VAR the name of the variable can be specified which holds -# the version of the package which has been found. If this is done, this version -# will be checked against the (potentially) specified required version used -# in the find_package() call. The EXACT keyword is also handled. The default -# messages include information about the required version and the version -# which has been actually found, both if the version is ok or not. -# Use the option CONFIG_MODE if your FindXXX.cmake module is a wrapper for -# a find_package(... NO_MODULE) call, in this case all the information -# provided by the config-mode of find_package() will be evaluated -# automatically. -# Via FAIL_MESSAGE a custom failure message can be specified, if this is not -# used, the default message will be displayed. -# -# Example for mode 1: -# -# FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibXml2 DEFAULT_MSG LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR) -# -# LibXml2 is considered to be found, if both LIBXML2_LIBRARY and -# LIBXML2_INCLUDE_DIR are valid. Then also LIBXML2_FOUND is set to TRUE. -# If it is not found and REQUIRED was used, it fails with FATAL_ERROR, -# independent whether QUIET was used or not. -# If it is found, success will be reported, including the content of . -# On repeated Cmake runs, the same message won't be printed again. -# -# Example for mode 2: -# -# FIND_PACKAGE_HANDLE_STANDARD_ARGS(BISON REQUIRED_VARS BISON_EXECUTABLE -# VERSION_VAR BISON_VERSION) -# In this case, BISON is considered to be found if the variable(s) listed -# after REQUIRED_VAR are all valid, i.e. BISON_EXECUTABLE in this case. -# Also the version of BISON will be checked by using the version contained -# in BISON_VERSION. -# Since no FAIL_MESSAGE is given, the default messages will be printed. -# -# Another example for mode 2: -# -# FIND_PACKAGE(Automoc4 QUIET NO_MODULE HINTS /opt/automoc4) -# FIND_PACKAGE_HANDLE_STANDARD_ARGS(Automoc4 CONFIG_MODE) -# In this case, FindAutmoc4.cmake wraps a call to FIND_PACKAGE(Automoc4 NO_MODULE) -# and adds an additional search directory for automoc4. -# The following FIND_PACKAGE_HANDLE_STANDARD_ARGS() call produces a proper -# success/error message. - -#============================================================================= -# Copyright 2007-2009 Kitware, Inc. -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - -INCLUDE(FindPackageMessage) -INCLUDE(CMakeParseArguments) - -# internal helper macro -MACRO(_FPHSA_FAILURE_MESSAGE _msg) - IF (${_NAME}_FIND_REQUIRED) - MESSAGE(FATAL_ERROR "${_msg}") - ELSE (${_NAME}_FIND_REQUIRED) - IF (NOT ${_NAME}_FIND_QUIETLY) - MESSAGE(STATUS "${_msg}") - ENDIF (NOT ${_NAME}_FIND_QUIETLY) - ENDIF (${_NAME}_FIND_REQUIRED) -ENDMACRO(_FPHSA_FAILURE_MESSAGE _msg) - - -# internal helper macro to generate the failure message when used in CONFIG_MODE: -MACRO(_FPHSA_HANDLE_FAILURE_CONFIG_MODE) - # _CONFIG is set, but FOUND is false, this means that some other of the REQUIRED_VARS was not found: - IF(${_NAME}_CONFIG) - _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: missing: ${MISSING_VARS} (found ${${_NAME}_CONFIG} ${VERSION_MSG})") - ELSE(${_NAME}_CONFIG) - # If _CONSIDERED_CONFIGS is set, the config-file has been found, but no suitable version. - # List them all in the error message: - IF(${_NAME}_CONSIDERED_CONFIGS) - SET(configsText "") - LIST(LENGTH ${_NAME}_CONSIDERED_CONFIGS configsCount) - MATH(EXPR configsCount "${configsCount} - 1") - FOREACH(currentConfigIndex RANGE ${configsCount}) - LIST(GET ${_NAME}_CONSIDERED_CONFIGS ${currentConfigIndex} filename) - LIST(GET ${_NAME}_CONSIDERED_VERSIONS ${currentConfigIndex} version) - SET(configsText "${configsText} ${filename} (version ${version})\n") - ENDFOREACH(currentConfigIndex) - _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} ${VERSION_MSG}, checked the following files:\n${configsText}") - - ELSE(${_NAME}_CONSIDERED_CONFIGS) - # Simple case: No Config-file was found at all: - _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: found neither ${_NAME}Config.cmake nor ${_NAME_LOWER}-config.cmake ${VERSION_MSG}") - ENDIF(${_NAME}_CONSIDERED_CONFIGS) - ENDIF(${_NAME}_CONFIG) -ENDMACRO(_FPHSA_HANDLE_FAILURE_CONFIG_MODE) - - -FUNCTION(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG) - -# set up the arguments for CMAKE_PARSE_ARGUMENTS and check whether we are in -# new extended or in the "old" mode: - SET(options CONFIG_MODE) - SET(oneValueArgs FAIL_MESSAGE VERSION_VAR) - SET(multiValueArgs REQUIRED_VARS) - SET(_KEYWORDS_FOR_EXTENDED_MODE ${options} ${oneValueArgs} ${multiValueArgs} ) - LIST(FIND _KEYWORDS_FOR_EXTENDED_MODE "${_FIRST_ARG}" INDEX) - - IF(${INDEX} EQUAL -1) - SET(FPHSA_FAIL_MESSAGE ${_FIRST_ARG}) - SET(FPHSA_REQUIRED_VARS ${ARGN}) - SET(FPHSA_VERSION_VAR) - ELSE(${INDEX} EQUAL -1) - - CMAKE_PARSE_ARGUMENTS(FPHSA "${options}" "${oneValueArgs}" "${multiValueArgs}" ${_FIRST_ARG} ${ARGN}) - - IF(FPHSA_UNPARSED_ARGUMENTS) - MESSAGE(FATAL_ERROR "Unknown keywords given to FIND_PACKAGE_HANDLE_STANDARD_ARGS(): \"${FPHSA_UNPARSED_ARGUMENTS}\"") - ENDIF(FPHSA_UNPARSED_ARGUMENTS) - - IF(NOT FPHSA_FAIL_MESSAGE) - SET(FPHSA_FAIL_MESSAGE "DEFAULT_MSG") - ENDIF(NOT FPHSA_FAIL_MESSAGE) - ENDIF(${INDEX} EQUAL -1) - -# now that we collected all arguments, process them - - IF("${FPHSA_FAIL_MESSAGE}" STREQUAL "DEFAULT_MSG") - SET(FPHSA_FAIL_MESSAGE "Could NOT find ${_NAME}") - ENDIF("${FPHSA_FAIL_MESSAGE}" STREQUAL "DEFAULT_MSG") - - # In config-mode, we rely on the variable _CONFIG, which is set by find_package() - # when it successfully found the config-file, including version checking: - IF(FPHSA_CONFIG_MODE) - LIST(INSERT FPHSA_REQUIRED_VARS 0 ${_NAME}_CONFIG) - LIST(REMOVE_DUPLICATES FPHSA_REQUIRED_VARS) - SET(FPHSA_VERSION_VAR ${_NAME}_VERSION) - ENDIF(FPHSA_CONFIG_MODE) - - IF(NOT FPHSA_REQUIRED_VARS) - MESSAGE(FATAL_ERROR "No REQUIRED_VARS specified for FIND_PACKAGE_HANDLE_STANDARD_ARGS()") - ENDIF(NOT FPHSA_REQUIRED_VARS) - - LIST(GET FPHSA_REQUIRED_VARS 0 _FIRST_REQUIRED_VAR) - - STRING(TOUPPER ${_NAME} _NAME_UPPER) - STRING(TOLOWER ${_NAME} _NAME_LOWER) - - # collect all variables which were not found, so they can be printed, so the - # user knows better what went wrong (#6375) - SET(MISSING_VARS "") - SET(DETAILS "") - SET(${_NAME_UPPER}_FOUND TRUE) - # check if all passed variables are valid - FOREACH(_CURRENT_VAR ${FPHSA_REQUIRED_VARS}) - IF(NOT ${_CURRENT_VAR}) - SET(${_NAME_UPPER}_FOUND FALSE) - SET(MISSING_VARS "${MISSING_VARS} ${_CURRENT_VAR}") - ELSE(NOT ${_CURRENT_VAR}) - SET(DETAILS "${DETAILS}[${${_CURRENT_VAR}}]") - ENDIF(NOT ${_CURRENT_VAR}) - ENDFOREACH(_CURRENT_VAR) - - - # version handling: - SET(VERSION_MSG "") - SET(VERSION_OK TRUE) - SET(VERSION ${${FPHSA_VERSION_VAR}} ) - IF (${_NAME}_FIND_VERSION) - - IF(VERSION) - - IF(${_NAME}_FIND_VERSION_EXACT) # exact version required - IF (NOT "${${_NAME}_FIND_VERSION}" VERSION_EQUAL "${VERSION}") - SET(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"") - SET(VERSION_OK FALSE) - ELSE (NOT "${${_NAME}_FIND_VERSION}" VERSION_EQUAL "${VERSION}") - SET(VERSION_MSG "(found suitable exact version \"${VERSION}\")") - ENDIF (NOT "${${_NAME}_FIND_VERSION}" VERSION_EQUAL "${VERSION}") - - ELSE(${_NAME}_FIND_VERSION_EXACT) # minimum version specified: - IF ("${${_NAME}_FIND_VERSION}" VERSION_GREATER "${VERSION}") - SET(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is at least \"${${_NAME}_FIND_VERSION}\"") - SET(VERSION_OK FALSE) - ELSE ("${${_NAME}_FIND_VERSION}" VERSION_GREATER "${VERSION}") - SET(VERSION_MSG "(found suitable version \"${VERSION}\", required is \"${${_NAME}_FIND_VERSION}\")") - ENDIF ("${${_NAME}_FIND_VERSION}" VERSION_GREATER "${VERSION}") - ENDIF(${_NAME}_FIND_VERSION_EXACT) - - ELSE(VERSION) - - # if the package was not found, but a version was given, add that to the output: - IF(${_NAME}_FIND_VERSION_EXACT) - SET(VERSION_MSG "(Required is exact version \"${${_NAME}_FIND_VERSION}\")") - ELSE(${_NAME}_FIND_VERSION_EXACT) - SET(VERSION_MSG "(Required is at least version \"${${_NAME}_FIND_VERSION}\")") - ENDIF(${_NAME}_FIND_VERSION_EXACT) - - ENDIF(VERSION) - ELSE (${_NAME}_FIND_VERSION) - IF(VERSION) - SET(VERSION_MSG "(found version \"${VERSION}\")") - ENDIF(VERSION) - ENDIF (${_NAME}_FIND_VERSION) - - IF(VERSION_OK) - SET(DETAILS "${DETAILS}[v${VERSION}(${${_NAME}_FIND_VERSION})]") - ELSE(VERSION_OK) - SET(${_NAME_UPPER}_FOUND FALSE) - ENDIF(VERSION_OK) - - - # print the result: - IF (${_NAME_UPPER}_FOUND) - FIND_PACKAGE_MESSAGE(${_NAME} "Found ${_NAME}: ${${_FIRST_REQUIRED_VAR}} ${VERSION_MSG}" "${DETAILS}") - ELSE (${_NAME_UPPER}_FOUND) - - IF(FPHSA_CONFIG_MODE) - _FPHSA_HANDLE_FAILURE_CONFIG_MODE() - ELSE(FPHSA_CONFIG_MODE) - IF(NOT VERSION_OK) - _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: ${VERSION_MSG} (found ${${_FIRST_REQUIRED_VAR}})") - ELSE(NOT VERSION_OK) - _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} (missing: ${MISSING_VARS}) ${VERSION_MSG}") - ENDIF(NOT VERSION_OK) - ENDIF(FPHSA_CONFIG_MODE) - - ENDIF (${_NAME_UPPER}_FOUND) - - SET(${_NAME_UPPER}_FOUND ${${_NAME_UPPER}_FOUND} PARENT_SCOPE) - -ENDFUNCTION(FIND_PACKAGE_HANDLE_STANDARD_ARGS _FIRST_ARG) diff --git a/cmake_modules/opensslConfig.cmake b/cmake_modules/opensslConfig.cmake index bffd91eb..b3f012c8 100644 --- a/cmake_modules/opensslConfig.cmake +++ b/cmake_modules/opensslConfig.cmake @@ -229,7 +229,7 @@ set(OPENSSL_VERSION "${OPENSSL_VERSION_MAJOR}.${OPENSSL_VERSION_MINOR}.${OPENSSL_VERSION_PATCH}") endif (OPENSSL_INCLUDE_DIR) - include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) + include(FindPackageHandleStandardArgs) if (OPENSSL_VERSION) find_package_handle_standard_args(OpenSSL diff --git a/include/Swiften/Server/ServerStanzaChannel.cpp b/include/Swiften/Server/ServerStanzaChannel.cpp index a0f56543..bb3fbf6e 100644 --- a/include/Swiften/Server/ServerStanzaChannel.cpp +++ b/include/Swiften/Server/ServerStanzaChannel.cpp @@ -73,7 +73,7 @@ void ServerStanzaChannel::finishSession(const JID& to, boost::shared_ptrfinishSession(); - std::cout << "FINISH SESSION " << sessions[to.toBare().toString()].size() << "\n"; +// std::cout << "FINISH SESSION " << sessions[to.toBare().toString()].size() << "\n"; if (last) { break; } diff --git a/include/transport/conversation.h b/include/transport/conversation.h index 82a35b0c..8af86993 100644 --- a/include/transport/conversation.h +++ b/include/transport/conversation.h @@ -97,9 +97,7 @@ class Conversation { /// This is used to detect Private messages associated with particular room. /// \param room room name associated with this Conversation. - void setRoom(const std::string &room) { - m_room = room; - } + void setRoom(const std::string &room); /// Returns room name associated with this Conversation. diff --git a/include/transport/localbuddy.h b/include/transport/localbuddy.h index 26b61983..c8f81174 100644 --- a/include/transport/localbuddy.h +++ b/include/transport/localbuddy.h @@ -63,6 +63,7 @@ class LocalBuddy : public Buddy { std::string m_statusMessage; std::string m_iconHash; Swift::StatusShow m_status; + bool m_firstSet; }; } diff --git a/include/transport/mysqlbackend.h b/include/transport/mysqlbackend.h index 04c00b7a..b35a345d 100644 --- a/include/transport/mysqlbackend.h +++ b/include/transport/mysqlbackend.h @@ -48,6 +48,7 @@ class MySQLBackend : public StorageBackend /// automatically. /// \return true if database is opened successfully. bool connect(); + void disconnect(); /// Creates database structure. /// \see connect() @@ -100,7 +101,7 @@ class MySQLBackend : public StorageBackend Statement(MYSQL *conn, const std::string &format, const std::string &statement); ~Statement(); - bool execute(); + int execute(); int fetch(); diff --git a/include/transport/networkplugin.h b/include/transport/networkplugin.h index 691dc6e2..334fab8b 100644 --- a/include/transport/networkplugin.h +++ b/include/transport/networkplugin.h @@ -217,7 +217,6 @@ class NetworkPlugin { private: - void connect(); void handleLoginPayload(const std::string &payload); void handleLogoutPayload(const std::string &payload); void handleStatusChangedPayload(const std::string &payload); diff --git a/plugin/src/CMakeLists.txt b/plugin/src/CMakeLists.txt index 86a0a108..dde42f38 100644 --- a/plugin/src/CMakeLists.txt +++ b/plugin/src/CMakeLists.txt @@ -2,7 +2,11 @@ cmake_minimum_required(VERSION 2.6) FILE(GLOB SRC *.cpp *.h) FILE(GLOB HEADERS ../include/transport/*.h) -ADD_LIBRARY(transport-plugin STATIC ${HEADERS} ${SRC} ${PROTOBUF_SRC} ${PROTOBUF_HDRS} ../../src/memoryusage.cpp ${CMAKE_CURRENT_BINARY_DIR}/../../include/transport/protocol.pb.cc) +if (NOT WIN32) + ADD_LIBRARY(transport-plugin SHARED ${HEADERS} ${SRC} ${PROTOBUF_SRC} ${PROTOBUF_HDRS} ../../src/memoryusage.cpp ${CMAKE_CURRENT_BINARY_DIR}/../../include/transport/protocol.pb.cc) +else() + ADD_LIBRARY(transport-plugin STATIC ${HEADERS} ${SRC} ${PROTOBUF_SRC} ${PROTOBUF_HDRS} ../../src/memoryusage.cpp ${CMAKE_CURRENT_BINARY_DIR}/../../include/transport/protocol.pb.cc) +endif() ADD_DEPENDENCIES(transport-plugin pb) SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/../../include/transport/protocol.pb.cc PROPERTIES GENERATED 1) diff --git a/spectrum/src/sample.cfg b/spectrum/src/sample.cfg index 6efc9561..71b1d23b 100644 --- a/spectrum/src/sample.cfg +++ b/spectrum/src/sample.cfg @@ -4,7 +4,8 @@ password = secret server = 127.0.0.1 port = 5222 server_mode = 1 -backend_host=localhost # < this option doesn't work yet +backend_host=localhost +# < this option doesn't work yet backend_port=10001 admin_username=admin admin_password=test @@ -14,7 +15,7 @@ users_per_backend=10 backend=/home/hanzz/code/libtransport/backends/libpurple/spectrum2_libpurple_backend #backend=/usr/bin/mono /home/hanzz/code/networkplugin-csharp/msnp-sharp-backend/bin/Debug/msnp-sharp-backend.exe #backend=/home/hanzz/code/libtransport/backends/frotz/spectrum2_frotz_backend -#backend=../../backends/libircclient-qt/spectrum2_libircclient-qt_backend +#backend=/home/hanzz/code/libtransport/backends/libircclient-qt/spectrum2_libircclient-qt_backend #protocol=prpl-msn protocol=any #protocol=prpl-icq @@ -25,7 +26,7 @@ protocol=any [logging] #config=logging.cfg # log4cxx/log4j logging configuration file -#backend_config=backend_logging.cfg # log4cxx/log4j logging configuration file for backends +#backend_config=/home/hanzz/code/libtransport/spectrum/src/backend-logging.cfg # log4cxx/log4j logging configuration file for backends [database] type = none # or "none" without database backend diff --git a/spectrum/src/sample2.cfg b/spectrum/src/sample2.cfg index 10347f9e..ca499f66 100644 --- a/spectrum/src/sample2.cfg +++ b/spectrum/src/sample2.cfg @@ -65,7 +65,7 @@ type=xmpp config = /etc/spectrum2/logging.cfg # log4cxx/log4j logging configuration file in ini format used for backends. -backend_config = /etc/spectrum2/backend_logging.cfg # log4cxx/log4j logging configuration file for backends +backend_config = /etc/spectrum2/backend-logging.cfg # log4cxx/log4j logging configuration file for backends [database] # Database backend type diff --git a/spectrum_manager/src/main.cpp b/spectrum_manager/src/main.cpp index 6c74057a..8d2e3ed3 100644 --- a/spectrum_manager/src/main.cpp +++ b/spectrum_manager/src/main.cpp @@ -26,26 +26,26 @@ using namespace boost; static int finished; static std::string *m; -static void handleDisconnected(Swift::Client *client, const boost::optional &) { - std::cout << "[ DISCONNECTED ] " << client->getJID().getDomain() << "\n"; +static void handleDisconnected(Swift::Client *client, const boost::optional &, const std::string &server) { + std::cout << "[ DISCONNECTED ] " << server << "\n"; if (--finished == 0) { exit(0); } } -static void handleConnected(Swift::Client *client) { +static void handleConnected(Swift::Client *client, const std::string &server) { boost::shared_ptr message(new Swift::Message()); - message->setTo(client->getJID().getDomain()); + message->setTo(server); message->setFrom(client->getJID()); message->setBody(*m); client->sendMessage(message); } -static void handleMessageReceived(Swift::Client *client, Swift::Message::ref message) { +static void handleMessageReceived(Swift::Client *client, Swift::Message::ref message, const std::string &server) { std::string body = message->getBody(); - boost::replace_all(body, "\n", "\n[ OK ] " + client->getJID().getDomain() + ": "); - std::cout << "[ OK ] " << client->getJID().getDomain() << ": " << body << "\n"; + boost::replace_all(body, "\n", "\n[ OK ] " + server + ": "); + std::cout << "[ OK ] " << server << ": " << body << "\n"; if (--finished == 0) { exit(0); } @@ -205,6 +205,47 @@ static void stop_all_instances(ManagerConfig *config) { } } +void ask_local_servers(ManagerConfig *config, Swift::BoostNetworkFactories &networkFactories, const std::string &message) { + path p(CONFIG_STRING(config, "service.config_directory")); + + try { + if (!exists(p)) { + std::cerr << "Config directory " << CONFIG_STRING(config, "service.config_directory") << " does not exist\n"; + exit(6); + } + + if (!is_directory(p)) { + std::cerr << "Config directory " << CONFIG_STRING(config, "service.config_directory") << " does not exist\n"; + exit(7); + } + + directory_iterator end_itr; + for (directory_iterator itr(p); itr != end_itr; ++itr) { + if (is_regular(itr->path()) && extension(itr->path()) == ".cfg") { + Config cfg; + if (cfg.load(itr->path().string()) == false) { + std::cerr << "Can't load config file " << itr->path().string() << ". Skipping...\n"; + } + + finished++; + Swift::Client *client = new Swift::Client(CONFIG_STRING(&cfg, "service.admin_username"), CONFIG_STRING(&cfg, "service.admin_password"), &networkFactories); + client->setAlwaysTrustCertificates(); + client->onConnected.connect(boost::bind(&handleConnected, client, CONFIG_STRING(&cfg, "service.jid"))); + client->onDisconnected.connect(bind(&handleDisconnected, client, _1, CONFIG_STRING(&cfg, "service.jid"))); + client->onMessageReceived.connect(bind(&handleMessageReceived, client, _1, CONFIG_STRING(&cfg, "service.jid"))); + Swift::ClientOptions opt; + opt.allowPLAINWithoutTLS = true; + client->connect(opt); + } + } + } + catch (const filesystem_error& ex) { + std::cerr << "boost filesystem error\n"; + exit(5); + } +} + + int main(int argc, char **argv) { ManagerConfig config; @@ -215,7 +256,7 @@ int main(int argc, char **argv) boost::program_options::options_description desc("Usage: spectrum [OPTIONS] \nAllowed options"); desc.add_options() ("help,h", "Show help output") - ("config,c", boost::program_options::value(&config_file)->default_value("/etc/spectrum2/spectrum-manager.cfg"), "Spectrum manager config file") + ("config,c", boost::program_options::value(&config_file)->default_value("/etc/spectrum2/spectrum_manager.cfg"), "Spectrum manager config file") ("command", boost::program_options::value(&command)->default_value(""), "Command") ; try @@ -243,12 +284,16 @@ int main(int argc, char **argv) return 3; } - if (!config.load(config_file)) { std::cerr << "Can't load configuration file.\n"; return 4; } + if (command.empty()) { + std::cout << desc << "\n"; + return 1; + } + if (command == "start") { start_all_instances(&config); } @@ -259,17 +304,19 @@ int main(int argc, char **argv) Swift::SimpleEventLoop eventLoop; Swift::BoostNetworkFactories networkFactories(&eventLoop); - std::string message = argv[1]; + std::string message = command; m = &message; + ask_local_servers(&config, networkFactories, message); + std::vector servers = CONFIG_VECTOR(&config, "servers.server"); for (std::vector::const_iterator it = servers.begin(); it != servers.end(); it++) { finished++; - Swift::Client *client = new Swift::Client(CONFIG_STRING(&config, "service.admin_username") + "@" + (*it), CONFIG_STRING(&config, "service.admin_password"), &networkFactories); + Swift::Client *client = new Swift::Client(CONFIG_STRING(&config, "service.admin_username") + "@" + *it, CONFIG_STRING(&config, "service.admin_password"), &networkFactories); client->setAlwaysTrustCertificates(); - client->onConnected.connect(boost::bind(&handleConnected, client)); - client->onDisconnected.connect(bind(&handleDisconnected, client, _1)); - client->onMessageReceived.connect(bind(&handleMessageReceived, client, _1)); + client->onConnected.connect(boost::bind(&handleConnected, client, *it)); + client->onDisconnected.connect(bind(&handleDisconnected, client, _1, *it)); + client->onMessageReceived.connect(bind(&handleMessageReceived, client, _1, *it)); Swift::ClientOptions opt; opt.allowPLAINWithoutTLS = true; client->connect(opt); diff --git a/src/admininterface.cpp b/src/admininterface.cpp index 44709d8f..3af032d4 100644 --- a/src/admininterface.cpp +++ b/src/admininterface.cpp @@ -61,8 +61,8 @@ void AdminInterface::handleMessageReceived(Swift::Message::ref message) { if (!message->getTo().getNode().empty()) return; - if (message->getFrom().getNode() != CONFIG_STRING(m_component->getConfig(), "service.admin_username")) { - LOG4CXX_WARN(logger, "Message not from admin user, but from " << message->getFrom().getNode()); + if (message->getFrom().toBare().toString() != CONFIG_STRING(m_component->getConfig(), "service.admin_jid")) { + LOG4CXX_WARN(logger, "Message not from admin user, but from " << message->getFrom().toBare().toString()); return; } diff --git a/src/config.cpp b/src/config.cpp index 9b3e55e7..05473249 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -69,7 +69,7 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description ("service.backend_port", value()->default_value("10000"), "Port to bind backend server to") ("service.cert", value()->default_value(""), "PKCS#12 Certificate.") ("service.cert_password", value()->default_value(""), "PKCS#12 Certificate password.") - ("service.admin_username", value()->default_value(""), "Administrator username.") + ("service.admin_jid", value()->default_value(""), "Administrator jid.") ("service.admin_password", value()->default_value(""), "Administrator password.") ("service.reuse_old_backends", value()->default_value(true), "True if Spectrum should use old backends which were full in the past.") ("service.idle_reconnect_time", value()->default_value(0), "Time in seconds after which idle users are reconnected to let their backend die.") diff --git a/src/conversation.cpp b/src/conversation.cpp index 238fe4c8..81b1654d 100644 --- a/src/conversation.cpp +++ b/src/conversation.cpp @@ -42,6 +42,11 @@ Conversation::Conversation(ConversationManager *conversationManager, const std:: Conversation::~Conversation() { } +void Conversation::setRoom(const std::string &room) { + m_room = room; + m_legacyName = m_room + "/" + m_legacyName; +} + void Conversation::handleMessage(boost::shared_ptr &message, const std::string &nickname) { if (m_muc) { message->setType(Swift::Message::Groupchat); @@ -74,8 +79,12 @@ void Conversation::handleMessage(boost::shared_ptr &message, con m_conversationManager->getComponent()->getStanzaChannel()->sendMessage(message); } else { + std::string legacyName = m_legacyName; + if (legacyName.find_last_of("@") != std::string::npos) { + legacyName.replace(legacyName.find_last_of("@"), 1, "%"); // OK + } message->setTo(m_conversationManager->getUser()->getJID().toString()); - message->setFrom(Swift::JID(m_legacyName, m_conversationManager->getComponent()->getJID().toBare(), nickname)); + message->setFrom(Swift::JID(legacyName, m_conversationManager->getComponent()->getJID().toBare(), nickname)); m_conversationManager->getComponent()->getStanzaChannel()->sendMessage(message); } } @@ -83,7 +92,13 @@ void Conversation::handleMessage(boost::shared_ptr &message, con void Conversation::handleParticipantChanged(const std::string &nick, int flag, int status, const std::string &statusMessage, const std::string &newname) { std::string nickname = nick; Swift::Presence::ref presence = Swift::Presence::create(); - presence->setFrom(Swift::JID(m_legacyName, m_conversationManager->getComponent()->getJID().toBare(), nickname)); + std::string legacyName = m_legacyName; + if (m_muc) { + if (legacyName.find_last_of("@") != std::string::npos) { + legacyName.replace(legacyName.find_last_of("@"), 1, "%"); // OK + } + } + presence->setFrom(Swift::JID(legacyName, m_conversationManager->getComponent()->getJID().toBare(), nickname)); presence->setTo(m_conversationManager->getUser()->getJID().toString()); presence->setType(Swift::Presence::Available); diff --git a/src/localbuddy.cpp b/src/localbuddy.cpp index ce64ad87..a12b9ee9 100644 --- a/src/localbuddy.cpp +++ b/src/localbuddy.cpp @@ -25,12 +25,18 @@ namespace Transport { LocalBuddy::LocalBuddy(RosterManager *rosterManager, long id) : Buddy(rosterManager, id) { m_status = Swift::StatusShow::None; + m_firstSet = true; } LocalBuddy::~LocalBuddy() { } void LocalBuddy::setAlias(const std::string &alias) { + if (m_firstSet) { + m_firstSet = false; + m_alias = alias; + return; + } bool changed = m_alias != alias; m_alias = alias; diff --git a/src/mysqlbackend.cpp b/src/mysqlbackend.cpp index 0bad7c63..a10d89ec 100644 --- a/src/mysqlbackend.cpp +++ b/src/mysqlbackend.cpp @@ -29,7 +29,7 @@ using namespace log4cxx; #define MYSQL_DB_VERSION 2 #define CHECK_DB_RESPONSE(stmt) \ if(stmt) { \ - sqlite3_exec(m_db, "ROLLBACK;", NULL, NULL, NULL); \ + sqlite3_EXEC(m_db, "ROLLBACK;", NULL, NULL, NULL); \ return 0; \ } @@ -72,11 +72,27 @@ using namespace log4cxx; LOG4CXX_ERROR(logger, NAME << " " << mysql_error(&m_conn)); \ } +#define EXEC(STMT, METHOD) \ + {\ + int ret = STMT->execute(); \ + if (ret == 0) \ + exec_ok = true; \ + else if (ret == 2013) { \ + LOG4CXX_INFO(logger, "MySQL connection lost. Reconnecting...");\ + disconnect(); \ + connect(); \ + return METHOD; \ + } \ + else \ + exec_ok = false; \ + } + using namespace boost; namespace Transport { static LoggerPtr logger = Logger::getLogger("MySQLBackend"); +static bool exec_ok; MySQLBackend::Statement::Statement(MYSQL *conn, const std::string &format, const std::string &statement) { m_resultOffset = -1; @@ -184,7 +200,7 @@ MySQLBackend::Statement::~Statement() { FINALIZE_STMT(m_stmt); } -bool MySQLBackend::Statement::execute() { +int MySQLBackend::Statement::execute() { // If statement has some input and doesn't have any output, we have // to clear the offset now, because operator>> will not be called. m_offset = 0; @@ -193,9 +209,9 @@ bool MySQLBackend::Statement::execute() { if ((ret = mysql_stmt_execute(m_stmt)) != 0) { LOG4CXX_ERROR(logger, m_string << " " << mysql_stmt_error(m_stmt) << "; " << mysql_error(m_conn)); - return false; + return mysql_stmt_errno(m_stmt); } - return true; + return 0; } int MySQLBackend::Statement::fetch() { @@ -256,13 +272,18 @@ MySQLBackend::Statement& MySQLBackend::Statement::operator >> (std::string& t) { MySQLBackend::MySQLBackend(Config *config) { m_config = config; + m_prefix = CONFIG_STRING(m_config, "database.prefix"); mysql_init(&m_conn); my_bool my_true = 1; mysql_options(&m_conn, MYSQL_OPT_RECONNECT, &my_true); - m_prefix = CONFIG_STRING(m_config, "database.prefix"); } MySQLBackend::~MySQLBackend(){ + disconnect(); +} + +void MySQLBackend::disconnect() { + LOG4CXX_INFO(logger, "Disconnecting"); delete m_setUser; delete m_getUser; delete m_removeUser; @@ -286,7 +307,7 @@ bool MySQLBackend::connect() { CONFIG_STRING(m_config, "database.user") << ", database " << CONFIG_STRING(m_config, "database.database") << ", port " << CONFIG_INT(m_config, "database.port") ); - + if (!mysql_real_connect(&m_conn, CONFIG_STRING(m_config, "database.server").c_str(), CONFIG_STRING(m_config, "database.user").c_str(), CONFIG_STRING(m_config, "database.password").c_str(), @@ -389,12 +410,13 @@ bool MySQLBackend::exec(const std::string &query) { void MySQLBackend::setUser(const UserInfo &user) { *m_setUser << user.jid << user.uin << user.password << user.language << user.encoding << user.vip << user.password; - m_setUser->execute(); + EXEC(m_setUser, setUser(user)); } bool MySQLBackend::getUser(const std::string &barejid, UserInfo &user) { *m_getUser << barejid; - if (!m_getUser->execute()) + EXEC(m_getUser, getUser(barejid, user)); + if (!exec_ok) return false; int ret = false; @@ -408,7 +430,7 @@ bool MySQLBackend::getUser(const std::string &barejid, UserInfo &user) { void MySQLBackend::setUserOnline(long id, bool online) { *m_setUserOnline << online << id; - m_setUserOnline->execute(); + EXEC(m_setUserOnline, setUserOnline(id, online)); } long MySQLBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) { @@ -417,14 +439,14 @@ long MySQLBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) { *m_addBuddy << (buddyInfo.groups.size() == 0 ? "" : buddyInfo.groups[0]); *m_addBuddy << buddyInfo.alias << buddyInfo.flags; - m_addBuddy->execute(); + EXEC(m_addBuddy, addBuddy(userId, buddyInfo)); long id = (long) mysql_insert_id(&m_conn); // INSERT OR REPLACE INTO " + m_prefix + "buddies_settings (user_id, buddy_id, var, type, value) VALUES (?, ?, ?, ?, ?) if (!buddyInfo.settings.find("icon_hash")->second.s.empty()) { *m_updateBuddySetting << userId << id << buddyInfo.settings.find("icon_hash")->first << (int) TYPE_STRING << buddyInfo.settings.find("icon_hash")->second.s << buddyInfo.settings.find("icon_hash")->second.s; - m_updateBuddySetting->execute(); + EXEC(m_updateBuddySetting, addBuddy(userId, buddyInfo)); } return id; @@ -436,7 +458,7 @@ void MySQLBackend::updateBuddy(long userId, const BuddyInfo &buddyInfo) { *m_updateBuddy << buddyInfo.alias << buddyInfo.flags << buddyInfo.subscription; *m_updateBuddy << userId << buddyInfo.legacyName; - m_updateBuddy->execute(); + EXEC(m_updateBuddy, updateBuddy(userId, buddyInfo)); } bool MySQLBackend::getBuddies(long id, std::list &roster) { @@ -450,7 +472,8 @@ bool MySQLBackend::getBuddies(long id, std::list &roster) { long buddy_id = -1; std::string key; - if (!m_getBuddies->execute()) + EXEC(m_getBuddies, getBuddies(id, roster)); + if (!exec_ok) return false; while (m_getBuddies->fetch() == 0) { @@ -465,7 +488,8 @@ bool MySQLBackend::getBuddies(long id, std::list &roster) { roster.push_back(b); } - if (!m_getBuddiesSettings->execute()) + EXEC(m_getBuddiesSettings, getBuddies(id, roster)); + if (!exec_ok) return false; BOOST_FOREACH(BuddyInfo &b, roster) { @@ -511,19 +535,23 @@ bool MySQLBackend::getBuddies(long id, std::list &roster) { bool MySQLBackend::removeUser(long id) { *m_removeUser << (int) id; - if (!m_removeUser->execute()) + EXEC(m_removeUser, removeUser(id)); + if (!exec_ok) return false; *m_removeUserSettings << (int) id; - if (!m_removeUserSettings->execute()) + EXEC(m_removeUserSettings, removeUser(id)); + if (!exec_ok) return false; *m_removeUserBuddies << (int) id; - if (!m_removeUserBuddies->execute()) + EXEC(m_removeUserBuddies, removeUser(id)); + if (!exec_ok) return false; *m_removeUserBuddiesSettings << (int) id; - if (!m_removeUserBuddiesSettings->execute()) + EXEC(m_removeUserBuddiesSettings, removeUser(id)); + if (!exec_ok) return false; return true; @@ -532,11 +560,11 @@ bool MySQLBackend::removeUser(long id) { void MySQLBackend::getUserSetting(long id, const std::string &variable, int &type, std::string &value) { // "SELECT type, value FROM " + m_prefix + "users_settings WHERE user_id=? AND var=?" *m_getUserSetting << id << variable; - m_getUserSetting->execute(); + EXEC(m_getUserSetting, getUserSetting(id, variable, type, value)); if (m_getUserSetting->fetch() != 0) { // "INSERT INTO " + m_prefix + "users_settings (user_id, var, type, value) VALUES (?,?,?,?)" *m_setUserSetting << id << variable << type << value; - m_setUserSetting->execute(); + EXEC(m_setUserSetting, getUserSetting(id, variable, type, value)); } else { *m_getUserSetting >> type >> value; @@ -546,7 +574,7 @@ void MySQLBackend::getUserSetting(long id, const std::string &variable, int &typ void MySQLBackend::updateUserSetting(long id, const std::string &variable, const std::string &value) { // "UPDATE " + m_prefix + "users_settings SET value=? WHERE user_id=? AND var=?" *m_updateUserSetting << value << id << variable; - m_updateUserSetting->execute(); + EXEC(m_updateUserSetting, updateUserSetting(id, variable, value)); } void MySQLBackend::beginTransaction() { diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index e77bca35..4da583eb 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -355,6 +355,7 @@ void NetworkPluginServer::handleConnectedPayload(const std::string &data) { User *user = m_userManager->getUser(payload.user()); if (!user) { + LOG4CXX_ERROR(logger, "Connected payload received for unknown user " << payload.user()); return; } @@ -1300,7 +1301,8 @@ void NetworkPluginServer::handleFTRejected(User *user, const std::string &buddyN void NetworkPluginServer::handleFTStateChanged(Swift::FileTransfer::State state, const std::string &userName, const std::string &buddyName, const std::string &fileName, unsigned long size, unsigned long id) { User *user = m_userManager->getUser(userName); if (!user) { - // TODO: reject and remove filetransfer + // TODO: FIXME We have to remove filetransfer when use disconnects + return; } if (state.state == Swift::FileTransfer::State::Transferring) { handleFTAccepted(user, buddyName, fileName, size, id); diff --git a/src/tests/basictest.cpp b/src/tests/basictest.cpp new file mode 100644 index 00000000..7a4568c9 --- /dev/null +++ b/src/tests/basictest.cpp @@ -0,0 +1,99 @@ +#include "basictest.h" +#include "transport/userregistry.h" +#include "transport/config.h" +#include "transport/storagebackend.h" +#include "transport/user.h" +#include "transport/transport.h" +#include "transport/conversation.h" +#include "transport/usermanager.h" +#include "transport/localbuddy.h" +#include +#include +#include +#include +#include +#include +#include +#include "Swiften/Server/ServerStanzaChannel.h" +#include "Swiften/Server/ServerFromClientSession.h" +#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" + +using namespace Transport; + +void BasicTest::setMeUp (void) { + streamEnded = false; + std::istringstream ifs("service.server_mode = 1\nservice.jid=localhost"); + cfg = new Config(); + cfg->load(ifs); + + factory = new TestingFactory(); + + loop = new Swift::DummyEventLoop(); + factories = new Swift::DummyNetworkFactories(loop); + + userRegistry = new UserRegistry(cfg, factories); + + component = new Component(loop, factories, cfg, factory, userRegistry); + component->start(); + + userManager = new UserManager(component, userRegistry); + + payloadSerializers = new Swift::FullPayloadSerializerCollection(); + payloadParserFactories = new Swift::FullPayloadParserFactoryCollection(); + parser = new Swift::XMPPParser(this, payloadParserFactories, factories->getXMLParserFactory()); + + serverFromClientSession = boost::shared_ptr(new Swift::ServerFromClientSession("id", factories->getConnectionFactory()->createConnection(), + payloadParserFactories, payloadSerializers, userRegistry, factories->getXMLParserFactory(), Swift::JID("user@localhost/resource"))); + serverFromClientSession->startSession(); + + serverFromClientSession->onDataWritten.connect(boost::bind(&BasicTest::handleDataReceived, this, _1)); + + dynamic_cast(component->getStanzaChannel())->addSession(serverFromClientSession); + parser->parse(""); + received.clear(); + loop->processEvents(); +} + +void BasicTest::tearMeDown (void) { + dynamic_cast(component->getStanzaChannel())->removeSession(serverFromClientSession); + delete component; + delete userRegistry; + delete factories; + delete factory; + delete loop; + delete cfg; + delete parser; + received.clear(); +} + +void BasicTest::handleDataReceived(const Swift::SafeByteArray &data) { +// std::cout << safeByteArrayToString(data) << "\n"; + parser->parse(safeByteArrayToString(data)); +} + +void BasicTest::handleStreamStart(const Swift::ProtocolHeader&) { + +} + +void BasicTest::handleElement(boost::shared_ptr element) { +received.push_back(element); +} + +void BasicTest::handleStreamEnd() { + streamEnded = true; +} + +void BasicTest::injectPresence(boost::shared_ptr &response) { + dynamic_cast(component->getStanzaChannel())->onPresenceReceived(response); +} + +void BasicTest::injectIQ(boost::shared_ptr iq) { + dynamic_cast(component->getStanzaChannel())->onIQReceived(iq); +} + +Swift::Stanza *BasicTest::getStanza(boost::shared_ptr element) { + Swift::Stanza *stanza = dynamic_cast(element.get()); + CPPUNIT_ASSERT(stanza); + return stanza; +} + diff --git a/src/tests/basictest.h b/src/tests/basictest.h new file mode 100644 index 00000000..c67691b3 --- /dev/null +++ b/src/tests/basictest.h @@ -0,0 +1,120 @@ +/** + * libtransport -- C++ library for easy XMPP Transports development + * + * Copyright (C) 2011, Jan Kaluza + * + * 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 +#include "Swiften/Swiften.h" +#include "Swiften/Queries/SetResponder.h" +#include "transport/conversation.h" +#include "transport/conversationmanager.h" +#include "transport/userregistry.h" +#include "transport/config.h" +#include "transport/storagebackend.h" +#include "transport/user.h" +#include "transport/transport.h" +#include "transport/conversation.h" +#include "transport/usermanager.h" +#include "transport/localbuddy.h" + +#include +#include +#include +#include +#include +#include "Swiften/Server/ServerStanzaChannel.h" +#include "Swiften/Server/ServerFromClientSession.h" +#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" + +using namespace Transport; + +class TestingConversation : public Conversation { + public: + TestingConversation(ConversationManager *conversationManager, const std::string &legacyName, bool muc = false) : Conversation(conversationManager, legacyName, muc) { + } + + // Called when there's new message to legacy network from XMPP network + void sendMessage(boost::shared_ptr &message) { + + } +}; + +class TestingFactory : public Factory { + public: + TestingFactory() { + } + + // Creates new conversation (NetworkConversation in this case) + Conversation *createConversation(ConversationManager *conversationManager, const std::string &legacyName) { + Conversation *nc = new TestingConversation(conversationManager, legacyName); + return nc; + } + + // Creates new LocalBuddy + Buddy *createBuddy(RosterManager *rosterManager, const BuddyInfo &buddyInfo) { + LocalBuddy *buddy = new LocalBuddy(rosterManager, buddyInfo.id); + buddy->setAlias(buddyInfo.alias); + buddy->setName(buddyInfo.legacyName); + buddy->setSubscription(buddyInfo.subscription); + buddy->setGroups(buddyInfo.groups); + buddy->setFlags((BuddyFlag) buddyInfo.flags); + if (buddyInfo.settings.find("icon_hash") != buddyInfo.settings.end()) + buddy->setIconHash(buddyInfo.settings.find("icon_hash")->second.s); + return buddy; + } +}; + +class BasicTest : public Swift::XMPPParserClient { + + public: + void setMeUp (void); + + void tearMeDown (void); + + void handleDataReceived(const Swift::SafeByteArray &data); + + void handleStreamStart(const Swift::ProtocolHeader&); + + void handleElement(boost::shared_ptr element); + + void handleStreamEnd(); + + void injectPresence(boost::shared_ptr &response); + void injectIQ(boost::shared_ptr iq); + + Swift::Stanza *getStanza(boost::shared_ptr element); + + protected: + bool streamEnded; + UserManager *userManager; + boost::shared_ptr serverFromClientSession; + Swift::FullPayloadSerializerCollection* payloadSerializers; + Swift::FullPayloadParserFactoryCollection* payloadParserFactories; + Swift::XMPPParser *parser; + UserRegistry *userRegistry; + Config *cfg; + Swift::Server *server; + Swift::DummyNetworkFactories *factories; + Swift::DummyEventLoop *loop; + TestingFactory *factory; + Component *component; + std::vector > received; +}; + diff --git a/src/tests/component.cpp b/src/tests/component.cpp index 8d4b3be9..a3f709b5 100644 --- a/src/tests/component.cpp +++ b/src/tests/component.cpp @@ -14,45 +14,11 @@ #include "Swiften/Server/ServerFromClientSession.h" #include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" +#include "basictest.h" + using namespace Transport; -class TestingConversation : public Conversation { - public: - TestingConversation(ConversationManager *conversationManager, const std::string &legacyName, bool muc = false) : Conversation(conversationManager, legacyName, muc) { - } - - // Called when there's new message to legacy network from XMPP network - void sendMessage(boost::shared_ptr &message) { - - } -}; - -class TestingFactory : public Factory { - public: - TestingFactory() { - } - - // Creates new conversation (NetworkConversation in this case) - Conversation *createConversation(ConversationManager *conversationManager, const std::string &legacyName) { - Conversation *nc = new TestingConversation(conversationManager, legacyName); - return nc; - } - - // Creates new LocalBuddy - Buddy *createBuddy(RosterManager *rosterManager, const BuddyInfo &buddyInfo) { - LocalBuddy *buddy = new LocalBuddy(rosterManager, buddyInfo.id); - buddy->setAlias(buddyInfo.alias); - buddy->setName(buddyInfo.legacyName); - buddy->setSubscription(buddyInfo.subscription); - buddy->setGroups(buddyInfo.groups); - buddy->setFlags((BuddyFlag) buddyInfo.flags); - if (buddyInfo.settings.find("icon_hash") != buddyInfo.settings.end()) - buddy->setIconHash(buddyInfo.settings.find("icon_hash")->second.s); - return buddy; - } -}; - -class ComponentTest : public CPPUNIT_NS :: TestFixture, public Swift::XMPPParserClient { +class ComponentTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_TEST_SUITE(ComponentTest); CPPUNIT_TEST(handlePresenceWithNode); CPPUNIT_TEST(handlePresenceWithoutNode); @@ -62,48 +28,14 @@ class ComponentTest : public CPPUNIT_NS :: TestFixture, public Swift::XMPPParser void setUp (void) { onUserPresenceReceived = false; onUserDiscoInfoReceived = false; - std::istringstream ifs("service.server_mode = 1\n"); - cfg = new Config(); - cfg->load(ifs); - factory = new TestingFactory(); - - loop = new Swift::DummyEventLoop(); - factories = new Swift::DummyNetworkFactories(loop); - - userRegistry = new UserRegistry(cfg, factories); - - component = new Component(loop, factories, cfg, factory, userRegistry); + setMeUp(); component->onUserPresenceReceived.connect(boost::bind(&ComponentTest::handleUserPresenceReceived, this, _1)); component->onUserDiscoInfoReceived.connect(boost::bind(&ComponentTest::handleUserDiscoInfoReceived, this, _1, _2)); - component->start(); - - payloadSerializers = new Swift::FullPayloadSerializerCollection(); - payloadParserFactories = new Swift::FullPayloadParserFactoryCollection(); - parser = new Swift::XMPPParser(this, payloadParserFactories, factories->getXMLParserFactory()); - - serverFromClientSession = boost::shared_ptr(new Swift::ServerFromClientSession("id", factories->getConnectionFactory()->createConnection(), - payloadParserFactories, payloadSerializers, userRegistry, factories->getXMLParserFactory(), Swift::JID("user@localhost/resource"))); - serverFromClientSession->startSession(); - - serverFromClientSession->onDataWritten.connect(boost::bind(&ComponentTest::handleDataReceived, this, _1)); - - dynamic_cast(component->getStanzaChannel())->addSession(serverFromClientSession); - parser->parse(""); - received.clear(); - loop->processEvents(); } void tearDown (void) { - dynamic_cast(component->getStanzaChannel())->removeSession(serverFromClientSession); - delete component; - delete userRegistry; - delete factories; - delete factory; - delete loop; - delete cfg; - delete parser; - received.clear(); + tearMeDown(); } void handleUserDiscoInfoReceived(const Swift::JID& jid, boost::shared_ptr info) { @@ -114,22 +46,6 @@ class ComponentTest : public CPPUNIT_NS :: TestFixture, public Swift::XMPPParser onUserPresenceReceived = true; } - void handleDataReceived(const Swift::SafeByteArray &data) { - parser->parse(safeByteArrayToString(data)); - } - - void handleStreamStart(const Swift::ProtocolHeader&) { - - } - - void handleElement(boost::shared_ptr element) { - received.push_back(element); - } - - void handleStreamEnd() { - - } - void handlePresenceWithNode() { Swift::Presence::ref response = Swift::Presence::create(); response->setTo("somebody@localhost"); @@ -151,27 +67,9 @@ class ComponentTest : public CPPUNIT_NS :: TestFixture, public Swift::XMPPParser CPPUNIT_ASSERT(onUserPresenceReceived); } - Swift::Stanza *getStanza(boost::shared_ptr element) { - Swift::Stanza *stanza = dynamic_cast(element.get()); - CPPUNIT_ASSERT(stanza); - return stanza; - } - private: bool onUserPresenceReceived; bool onUserDiscoInfoReceived; - boost::shared_ptr serverFromClientSession; - Swift::FullPayloadSerializerCollection* payloadSerializers; - Swift::FullPayloadParserFactoryCollection* payloadParserFactories; - Swift::XMPPParser *parser; - UserRegistry *userRegistry; - Config *cfg; - Swift::Server *server; - Swift::DummyNetworkFactories *factories; - Swift::DummyEventLoop *loop; - TestingFactory *factory; - Component *component; - std::vector > received; }; CPPUNIT_TEST_SUITE_REGISTRATION (ComponentTest); diff --git a/src/tests/rostermanager.cpp b/src/tests/rostermanager.cpp new file mode 100644 index 00000000..85238a97 --- /dev/null +++ b/src/tests/rostermanager.cpp @@ -0,0 +1,156 @@ +#include "transport/userregistry.h" +#include "transport/config.h" +#include "transport/storagebackend.h" +#include "transport/user.h" +#include "transport/transport.h" +#include "transport/conversation.h" +#include "transport/usermanager.h" +#include "transport/localbuddy.h" +#include +#include +#include +#include +#include +#include +#include +#include "Swiften/Server/ServerStanzaChannel.h" +#include "Swiften/Server/ServerFromClientSession.h" +#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" +#include "basictest.h" + +using namespace Transport; + +class RosterManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest { + CPPUNIT_TEST_SUITE(RosterManagerTest); + CPPUNIT_TEST(setBuddy); + CPPUNIT_TEST(sendCurrentPresences); + CPPUNIT_TEST_SUITE_END(); + + public: + void setUp (void) { + setMeUp(); + userManager->onUserCreated.connect(boost::bind(&RosterManagerTest::handleUserCreated, this, _1)); + connectUser(); + received.clear(); + } + + void tearDown (void) { + received.clear(); + disconnectUser(); + tearMeDown(); + } + + void handleUserCreated(User *user) { + + } + + void connectUser() { + CPPUNIT_ASSERT_EQUAL(0, userManager->getUserCount()); + userRegistry->isValidUserPassword(Swift::JID("user@localhost/resource"), serverFromClientSession.get(), Swift::createSafeByteArray("password")); + loop->processEvents(); + CPPUNIT_ASSERT_EQUAL(1, userManager->getUserCount()); + + User *user = userManager->getUser("user@localhost"); + CPPUNIT_ASSERT(user); + + UserInfo userInfo = user->getUserInfo(); + CPPUNIT_ASSERT_EQUAL(std::string("password"), userInfo.password); + CPPUNIT_ASSERT(user->isReadyToConnect() == true); + CPPUNIT_ASSERT(user->isConnected() == false); + + user->setConnected(true); + CPPUNIT_ASSERT(user->isConnected() == true); + + CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); + CPPUNIT_ASSERT(getStanza(received[0])->getPayload()); + received.clear(); + } + + void add2Buddies() { + User *user = userManager->getUser("user@localhost"); + CPPUNIT_ASSERT(user); + + LocalBuddy *buddy = new LocalBuddy(user->getRosterManager(), -1); + buddy->setFlags(BUDDY_JID_ESCAPING); + buddy->setName("buddy1"); + buddy->setAlias("Buddy 1"); + std::vector grp; + grp.push_back("group1"); + buddy->setGroups(grp); + buddy->setStatus(Swift::StatusShow(Swift::StatusShow::Away), "status1"); + user->getRosterManager()->setBuddy(buddy); + + buddy = new LocalBuddy(user->getRosterManager(), -1); + buddy->setFlags(BUDDY_JID_ESCAPING); + buddy->setName("buddy2"); + buddy->setAlias("Buddy 2"); + std::vector grp2; + grp2.push_back("group2"); + buddy->setGroups(grp2); + buddy->setStatus(Swift::StatusShow(Swift::StatusShow::Away), "status2"); + user->getRosterManager()->setBuddy(buddy); + } + + void setBuddy() { + add2Buddies(); + CPPUNIT_ASSERT_EQUAL(2, (int) received.size()); + + Swift::RosterPayload::ref payload1 = getStanza(received[0])->getPayload(); + CPPUNIT_ASSERT(payload1); + CPPUNIT_ASSERT_EQUAL(1, (int) payload1->getItems().size()); + Swift::RosterItemPayload item = payload1->getItems()[0]; + CPPUNIT_ASSERT_EQUAL(std::string("buddy1"), Buddy::JIDToLegacyName(item.getJID())); + CPPUNIT_ASSERT_EQUAL(std::string("Buddy 1"), item.getName()); + + Swift::RosterPayload::ref payload2 = getStanza(received[1])->getPayload(); + CPPUNIT_ASSERT(payload2); + CPPUNIT_ASSERT_EQUAL(1, (int) payload2->getItems().size()); + item = payload2->getItems()[0]; + CPPUNIT_ASSERT_EQUAL(std::string("buddy2"), Buddy::JIDToLegacyName(item.getJID())); + CPPUNIT_ASSERT_EQUAL(std::string("Buddy 2"), item.getName()); + + // send responses back + injectIQ(Swift::IQ::createResult(getStanza(received[0])->getFrom(), getStanza(received[0])->getTo(), getStanza(received[0])->getID())); + injectIQ(Swift::IQ::createResult(getStanza(received[1])->getFrom(), getStanza(received[1])->getTo(), getStanza(received[1])->getID())); + + // we should get presences + CPPUNIT_ASSERT_EQUAL(4, (int) received.size()); + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[2]))); + CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::Away, dynamic_cast(getStanza(received[2]))->getShow()); + CPPUNIT_ASSERT_EQUAL(std::string("status1"), dynamic_cast(getStanza(received[2]))->getStatus()); + + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[3]))); + CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::Away, dynamic_cast(getStanza(received[3]))->getShow()); + CPPUNIT_ASSERT_EQUAL(std::string("status2"), dynamic_cast(getStanza(received[3]))->getStatus()); + } + + void sendCurrentPresences() { + setBuddy(); + received.clear(); + + User *user = userManager->getUser("user@localhost"); + user->getRosterManager()->sendCurrentPresences("user@localhost/resource"); + + CPPUNIT_ASSERT_EQUAL(2, (int) received.size()); +// CPPUNIT_ASSERT(dynamic_cast(getStanza(received[2]))); +// CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::Away, dynamic_cast(getStanza(received[2]))->getShow()); +// CPPUNIT_ASSERT_EQUAL(std::string("status1"), dynamic_cast(getStanza(received[2]))->getStatus()); +// +// CPPUNIT_ASSERT(dynamic_cast(getStanza(received[3]))); +// CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::Away, dynamic_cast(getStanza(received[3]))->getShow()); +// CPPUNIT_ASSERT_EQUAL(std::string("status2"), dynamic_cast(getStanza(received[3]))->getStatus()); + } + + void disconnectUser() { + userManager->disconnectUser("user@localhost"); + dynamic_cast(factories->getTimerFactory())->setTime(10); + loop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(0, userManager->getUserCount()); + CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[0]))); + } + +}; + +CPPUNIT_TEST_SUITE_REGISTRATION (RosterManagerTest); diff --git a/src/tests/user.cpp b/src/tests/user.cpp new file mode 100644 index 00000000..a35ac423 --- /dev/null +++ b/src/tests/user.cpp @@ -0,0 +1,206 @@ +#include "transport/userregistry.h" +#include "transport/config.h" +#include "transport/storagebackend.h" +#include "transport/user.h" +#include "transport/transport.h" +#include "transport/conversation.h" +#include "transport/usermanager.h" +#include "transport/localbuddy.h" +#include +#include +#include +#include +#include +#include +#include +#include "Swiften/Server/ServerStanzaChannel.h" +#include "Swiften/Server/ServerFromClientSession.h" +#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" +#include "basictest.h" + +using namespace Transport; + +class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { + CPPUNIT_TEST_SUITE(UserTest); + CPPUNIT_TEST(sendCurrentPresence); + CPPUNIT_TEST(handlePresence); + CPPUNIT_TEST(handlePresenceJoinRoom); + CPPUNIT_TEST(handlePresenceLeaveRoom); + CPPUNIT_TEST(handleDisconnected); + CPPUNIT_TEST_SUITE_END(); + + public: + std::string room; + std::string roomNickname; + std::string roomPassword; + bool readyToConnect; + bool disconnected; + Swift::Presence::ref changedPresence; + + void setUp (void) { + disconnected = false; + readyToConnect = false; + changedPresence = Swift::Presence::ref(); + room = ""; + roomNickname = ""; + roomPassword = ""; + + setMeUp(); + userManager->onUserCreated.connect(boost::bind(&UserTest::handleUserCreated, this, _1)); + connectUser(); + received.clear(); + } + + void tearDown (void) { + received.clear(); + disconnectUser(); + tearMeDown(); + } + + void handleUserCreated(User *user) { + user->onReadyToConnect.connect(boost::bind(&UserTest::handleUserReadyToConnect, this, user)); + user->onPresenceChanged.connect(boost::bind(&UserTest::handleUserPresenceChanged, this, user, _1)); + user->onRoomJoined.connect(boost::bind(&UserTest::handleRoomJoined, this, user, _1, _2, _3)); + user->onRoomLeft.connect(boost::bind(&UserTest::handleRoomLeft, this, user, _1)); + } + + void handleUserReadyToConnect(User *user) { + readyToConnect = true; + } + + void handleUserPresenceChanged(User *user, Swift::Presence::ref presence) { + changedPresence = presence; + } + + void handleRoomJoined(User *user, const std::string &r, const std::string &nickname, const std::string &password) { + room = r; + roomNickname = nickname; + roomPassword = password; + } + + void handleRoomLeft(User *user, const std::string &r) { + room = r; + } + + void connectUser() { + CPPUNIT_ASSERT_EQUAL(0, userManager->getUserCount()); + userRegistry->isValidUserPassword(Swift::JID("user@localhost/resource"), serverFromClientSession.get(), Swift::createSafeByteArray("password")); + loop->processEvents(); + CPPUNIT_ASSERT_EQUAL(1, userManager->getUserCount()); + + User *user = userManager->getUser("user@localhost"); + CPPUNIT_ASSERT(user); + + UserInfo userInfo = user->getUserInfo(); + CPPUNIT_ASSERT_EQUAL(std::string("password"), userInfo.password); + CPPUNIT_ASSERT(user->isReadyToConnect() == true); + CPPUNIT_ASSERT(user->isConnected() == false); + + CPPUNIT_ASSERT_EQUAL(true, readyToConnect); + + user->setConnected(true); + CPPUNIT_ASSERT(user->isConnected() == true); + + CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); + CPPUNIT_ASSERT(getStanza(received[0])->getPayload()); + received.clear(); + } + + void sendCurrentPresence() { + User *user = userManager->getUser("user@localhost"); + user->sendCurrentPresence(); + + // We're not forwarding current presence in server-mode + CPPUNIT_ASSERT_EQUAL(0, (int) received.size()); + } + + void handlePresence() { + Swift::Presence::ref response = Swift::Presence::create(); + response->setTo("localhost"); + response->setFrom("user@localhost/resource"); + response->setShow(Swift::StatusShow::Away); + + injectPresence(response); + loop->processEvents(); + + // no presence received in server mode, just disco#info + CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); + CPPUNIT_ASSERT(getStanza(received[0])->getPayload()); + + CPPUNIT_ASSERT(changedPresence); + CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::Away, changedPresence->getShow()); + } + + void handlePresenceJoinRoom() { + Swift::Presence::ref response = Swift::Presence::create(); + response->setTo("#room@localhost/hanzz"); + response->setFrom("user@localhost/resource"); + + Swift::MUCPayload *payload = new Swift::MUCPayload(); + payload->setPassword("password"); + response->addPayload(boost::shared_ptr(payload)); + injectPresence(response); + loop->processEvents(); + + // no presence received in server mode, just disco#info + CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); + CPPUNIT_ASSERT(getStanza(received[0])->getPayload()); + + CPPUNIT_ASSERT_EQUAL(std::string("#room"), room); + CPPUNIT_ASSERT_EQUAL(std::string("hanzz"), roomNickname); + CPPUNIT_ASSERT_EQUAL(std::string("password"), roomPassword); + } + + void handlePresenceLeaveRoom() { + Swift::Presence::ref response = Swift::Presence::create(); + response->setTo("#room@localhost/hanzz"); + response->setFrom("user@localhost/resource"); + response->setType(Swift::Presence::Unavailable); + + Swift::MUCPayload *payload = new Swift::MUCPayload(); + payload->setPassword("password"); + response->addPayload(boost::shared_ptr(payload)); + injectPresence(response); + loop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(0, (int) received.size()); + + CPPUNIT_ASSERT_EQUAL(std::string("#room"), room); + CPPUNIT_ASSERT_EQUAL(std::string(""), roomNickname); + CPPUNIT_ASSERT_EQUAL(std::string(""), roomPassword); + } + + void handleDisconnected() { + User *user = userManager->getUser("user@localhost"); + user->handleDisconnected("Connection error"); + loop->processEvents(); + + CPPUNIT_ASSERT(streamEnded); + user = userManager->getUser("user@localhost"); + CPPUNIT_ASSERT(!user); + + CPPUNIT_ASSERT_EQUAL(2, (int) received.size()); + Swift::Message *m = dynamic_cast(getStanza(received[0])); + CPPUNIT_ASSERT_EQUAL(std::string("Connection error"), m->getBody()); + + CPPUNIT_ASSERT(dynamic_cast(received[1].get())); + CPPUNIT_ASSERT_EQUAL(std::string("Connection error"), dynamic_cast(received[1].get())->getText()); + + disconnected = true; + } + + void disconnectUser() { + if (disconnected) + return; + userManager->disconnectUser("user@localhost"); + dynamic_cast(factories->getTimerFactory())->setTime(10); + loop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(0, userManager->getUserCount()); + CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[0]))); + } + +}; + +CPPUNIT_TEST_SUITE_REGISTRATION (UserTest); diff --git a/src/tests/usermanager.cpp b/src/tests/usermanager.cpp index d0084ddf..b67c8e88 100644 --- a/src/tests/usermanager.cpp +++ b/src/tests/usermanager.cpp @@ -16,46 +16,11 @@ #include "Swiften/Server/ServerStanzaChannel.h" #include "Swiften/Server/ServerFromClientSession.h" #include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" +#include "basictest.h" using namespace Transport; -class TestingConversation : public Conversation { - public: - TestingConversation(ConversationManager *conversationManager, const std::string &legacyName, bool muc = false) : Conversation(conversationManager, legacyName, muc) { - } - - // Called when there's new message to legacy network from XMPP network - void sendMessage(boost::shared_ptr &message) { - - } -}; - -class TestingFactory : public Factory { - public: - TestingFactory() { - } - - // Creates new conversation (NetworkConversation in this case) - Conversation *createConversation(ConversationManager *conversationManager, const std::string &legacyName) { - Conversation *nc = new TestingConversation(conversationManager, legacyName); - return nc; - } - - // Creates new LocalBuddy - Buddy *createBuddy(RosterManager *rosterManager, const BuddyInfo &buddyInfo) { - LocalBuddy *buddy = new LocalBuddy(rosterManager, buddyInfo.id); - buddy->setAlias(buddyInfo.alias); - buddy->setName(buddyInfo.legacyName); - buddy->setSubscription(buddyInfo.subscription); - buddy->setGroups(buddyInfo.groups); - buddy->setFlags((BuddyFlag) buddyInfo.flags); - if (buddyInfo.settings.find("icon_hash") != buddyInfo.settings.end()) - buddy->setIconHash(buddyInfo.settings.find("icon_hash")->second.s); - return buddy; - } -}; - -class UserManagerTest : public CPPUNIT_NS :: TestFixture, public Swift::XMPPParserClient { +class UserManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_TEST_SUITE(UserManagerTest); CPPUNIT_TEST(connectUser); CPPUNIT_TEST(handleProbePresence); @@ -64,67 +29,13 @@ class UserManagerTest : public CPPUNIT_NS :: TestFixture, public Swift::XMPPPars public: void setUp (void) { - streamEnded = false; - std::istringstream ifs("service.server_mode = 1\n"); - cfg = new Config(); - cfg->load(ifs); - - factory = new TestingFactory(); - - loop = new Swift::DummyEventLoop(); - factories = new Swift::DummyNetworkFactories(loop); - - userRegistry = new UserRegistry(cfg, factories); - - component = new Component(loop, factories, cfg, factory, userRegistry); - component->start(); - - userManager = new UserManager(component, userRegistry); - - payloadSerializers = new Swift::FullPayloadSerializerCollection(); - payloadParserFactories = new Swift::FullPayloadParserFactoryCollection(); - parser = new Swift::XMPPParser(this, payloadParserFactories, factories->getXMLParserFactory()); - - serverFromClientSession = boost::shared_ptr(new Swift::ServerFromClientSession("id", factories->getConnectionFactory()->createConnection(), - payloadParserFactories, payloadSerializers, userRegistry, factories->getXMLParserFactory(), Swift::JID("user@localhost/resource"))); - serverFromClientSession->startSession(); - - serverFromClientSession->onDataWritten.connect(boost::bind(&UserManagerTest::handleDataReceived, this, _1)); - - dynamic_cast(component->getStanzaChannel())->addSession(serverFromClientSession); - parser->parse(""); - received.clear(); - loop->processEvents(); + setMeUp(); } void tearDown (void) { - dynamic_cast(component->getStanzaChannel())->removeSession(serverFromClientSession); - delete component; - delete userRegistry; - delete factories; - delete factory; - delete loop; - delete cfg; - delete parser; - received.clear(); + tearMeDown(); } - void handleDataReceived(const Swift::SafeByteArray &data) { - parser->parse(safeByteArrayToString(data)); - } - - void handleStreamStart(const Swift::ProtocolHeader&) { - - } - - void handleElement(boost::shared_ptr element) { - received.push_back(element); - } - - void handleStreamEnd() { - streamEnded = true; - } - void connectUser() { CPPUNIT_ASSERT_EQUAL(0, userManager->getUserCount()); userRegistry->isValidUserPassword(Swift::JID("user@localhost/resource"), serverFromClientSession.get(), Swift::createSafeByteArray("password")); @@ -169,30 +80,12 @@ class UserManagerTest : public CPPUNIT_NS :: TestFixture, public Swift::XMPPPars CPPUNIT_ASSERT_EQUAL(2, (int) received.size()); CPPUNIT_ASSERT(getStanza(received[0])->getPayload()); - CPPUNIT_ASSERT(dynamic_cast(getStanza(received[1]))); + + Swift::Presence *presence = dynamic_cast(getStanza(received[1])); + CPPUNIT_ASSERT(presence); + CPPUNIT_ASSERT_EQUAL(Swift::Presence::Unavailable, presence->getType()); } - Swift::Stanza *getStanza(boost::shared_ptr element) { - Swift::Stanza *stanza = dynamic_cast(element.get()); - CPPUNIT_ASSERT(stanza); - return stanza; - } - - private: - bool streamEnded; - UserManager *userManager; - boost::shared_ptr serverFromClientSession; - Swift::FullPayloadSerializerCollection* payloadSerializers; - Swift::FullPayloadParserFactoryCollection* payloadParserFactories; - Swift::XMPPParser *parser; - UserRegistry *userRegistry; - Config *cfg; - Swift::Server *server; - Swift::DummyNetworkFactories *factories; - Swift::DummyEventLoop *loop; - TestingFactory *factory; - Component *component; - std::vector > received; }; CPPUNIT_TEST_SUITE_REGISTRATION (UserManagerTest); diff --git a/src/user.cpp b/src/user.cpp index bd4c2726..c66da595 100644 --- a/src/user.cpp +++ b/src/user.cpp @@ -194,7 +194,8 @@ void User::handlePresence(Swift::Presence::ref presence) { if (isMUC) { if (presence->getType() == Swift::Presence::Unavailable) { LOG4CXX_INFO(logger, m_jid.toString() << ": Going to left room " << presence->getTo().getNode()); - onRoomLeft(presence->getTo().getNode()); + std::string room = Buddy::JIDToLegacyName(presence->getTo()); + onRoomLeft(room); } else { // force connection to legacy network to let backend to handle auto-join on connect. @@ -204,7 +205,12 @@ void User::handlePresence(Swift::Presence::ref presence) { onReadyToConnect(); } LOG4CXX_INFO(logger, m_jid.toString() << ": Going to join room " << presence->getTo().getNode() << " as " << presence->getTo().getResource()); - onRoomJoined(presence->getTo().getNode(), presence->getTo().getResource(), ""); + std::string room = Buddy::JIDToLegacyName(presence->getTo()); + std::string password = ""; + if (presence->getPayload() != NULL) { + password = presence->getPayload()->getPassword() ? *presence->getPayload()->getPassword() : ""; + } + onRoomJoined(room, presence->getTo().getResource(), password); } return; } @@ -298,7 +304,7 @@ void User::handleDisconnected(const std::string &error) { // We can't be sure finishSession sends unavailable presence everytime, so check if user gets removed // in finishSession(...) call and if not, remove it here. std::string jid = m_jid.toBare().toString(); - dynamic_cast(m_component->getStanzaChannel())->finishSession(m_jid, boost::shared_ptr(new Swift::StreamError(Swift::StreamError::UndefinedCondition, "test"))); + dynamic_cast(m_component->getStanzaChannel())->finishSession(m_jid, boost::shared_ptr(new Swift::StreamError(Swift::StreamError::UndefinedCondition, error))); if (m_userManager->getUser(jid) != NULL) { m_userManager->removeUser(this); } diff --git a/src/userregistry.cpp b/src/userregistry.cpp index b044ed49..00b72135 100644 --- a/src/userregistry.cpp +++ b/src/userregistry.cpp @@ -40,7 +40,7 @@ UserRegistry::UserRegistry(Config *cfg, Swift::NetworkFactories *factories) { UserRegistry::~UserRegistry() { m_removeTimer->stop(); } void UserRegistry::isValidUserPassword(const Swift::JID& user, Swift::ServerFromClientSession *session, const Swift::SafeByteArray& password) { - if (!CONFIG_STRING(config, "service.admin_username").empty() && user.getNode() == CONFIG_STRING(config, "service.admin_username")) { + if (!CONFIG_STRING(config, "service.admin_jid").empty() && user.toBare().toString() == CONFIG_STRING(config, "service.admin_jid")) { if (Swift::safeByteArrayToString(password) == CONFIG_STRING(config, "service.admin_password")) { session->handlePasswordValid(); }