From d3387ffd20f1bb549bd8f17691c8691a955f4df8 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sat, 9 Feb 2013 11:19:40 +0100 Subject: [PATCH] added missing files --- backends/swiften_raw/CMakeLists.txt | 14 + backends/swiften_raw/main.cpp | 427 ++++++++++++++++++++++++++++ 2 files changed, 441 insertions(+) create mode 100644 backends/swiften_raw/CMakeLists.txt create mode 100644 backends/swiften_raw/main.cpp diff --git a/backends/swiften_raw/CMakeLists.txt b/backends/swiften_raw/CMakeLists.txt new file mode 100644 index 00000000..ccd50e8e --- /dev/null +++ b/backends/swiften_raw/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 2.6) + +FILE(GLOB SRC *.cpp) + +ADD_EXECUTABLE(spectrum2_swiften_raw_backend ${SRC}) + +IF (NOT WIN32) +target_link_libraries(spectrum2_swiften_raw_backend transport pthread ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) +else() +target_link_libraries(spectrum2_swiften_raw_backend transport ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) +endif() + +INSTALL(TARGETS spectrum2_swiften_raw_backend RUNTIME DESTINATION bin) + diff --git a/backends/swiften_raw/main.cpp b/backends/swiften_raw/main.cpp new file mode 100644 index 00000000..9f164a81 --- /dev/null +++ b/backends/swiften_raw/main.cpp @@ -0,0 +1,427 @@ +// Transport includes +#include "transport/config.h" +#include "transport/networkplugin.h" +#include "transport/logging.h" + +#include "boost/date_time/posix_time/posix_time.hpp" + +// Swiften +#include "Swiften/Swiften.h" + +#ifndef WIN32 +// for signal handler +#include "unistd.h" +#include "signal.h" +#include "sys/wait.h" +#include "sys/signal.h" +#endif + +#ifndef __FreeBSD__ +#ifndef __MACH__ +// malloc_trim +#include "malloc.h" +#endif +#endif + +// Boost +#include +using namespace boost::filesystem; +using namespace boost::program_options; +using namespace Transport; + +DEFINE_LOGGER(logger, "Swiften"); +DEFINE_LOGGER(logger_xml, "backend.xml"); + +// eventloop +Swift::SimpleEventLoop *loop_; + +// Plugins +class SwiftenPlugin; +NetworkPlugin *np = NULL; +Swift::XMPPSerializer *serializer; + +class ForwardIQHandler : public Swift::IQHandler { + public: + std::map m_id2resource; + + ForwardIQHandler(NetworkPlugin *np, const std::string &user) { + m_np = np; + m_user = user; + } + + bool handleIQ(boost::shared_ptr iq) { + if (iq->getPayload() != NULL) { + return false; + } + if (iq->getType() == Swift::IQ::Get) { + m_id2resource[iq->getID()] = iq->getFrom().getResource(); + } + + iq->setTo(m_user); + std::string xml = safeByteArrayToString(serializer->serializeElement(iq)); + m_np->sendRawXML(xml); + return true; + } + + private: + NetworkPlugin *m_np; + std::string m_user; + +}; + +class SwiftenPlugin : public NetworkPlugin, Swift::XMPPParserClient { + public: + Swift::BoostNetworkFactories *m_factories; + Swift::BoostIOServiceThread m_boostIOServiceThread; + boost::shared_ptr m_conn; + bool m_firstPing; + + Swift::FullPayloadSerializerCollection collection; + Swift::XMPPParser *m_xmppParser; + Swift::FullPayloadParserFactoryCollection m_collection2; + + SwiftenPlugin(Config *config, Swift::SimpleEventLoop *loop, const std::string &host, int port) : NetworkPlugin() { + this->config = config; + m_firstPing = true; + m_factories = new Swift::BoostNetworkFactories(loop); + m_conn = m_factories->getConnectionFactory()->createConnection(); + m_conn->onDataRead.connect(boost::bind(&SwiftenPlugin::_handleDataRead, this, _1)); + m_conn->connect(Swift::HostAddressPort(Swift::HostAddress(host), port)); + + serializer = new Swift::XMPPSerializer(&collection, Swift::ClientStreamType); + m_xmppParser = new Swift::XMPPParser(this, &m_collection2, m_factories->getXMLParserFactory()); + m_xmppParser->parse(""); + + LOG4CXX_INFO(logger, "Starting the plugin."); + } + + // NetworkPlugin uses this method to send the data to networkplugin server + void sendData(const std::string &string) { + m_conn->write(Swift::createSafeByteArray(string)); + } + + // This method has to call handleDataRead with all received data from network plugin server + void _handleDataRead(boost::shared_ptr data) { + if (m_firstPing) { + m_firstPing = false; + NetworkPlugin::PluginConfig cfg; + cfg.setRawXML(true); + sendConfig(cfg); + } + std::string d(data->begin(), data->end()); + handleDataRead(d); + } + + void handleStreamStart(const Swift::ProtocolHeader&) {} + + void handleElement(boost::shared_ptr element) { + boost::shared_ptr stanza = boost::dynamic_pointer_cast(element); + if (!stanza) { + return; + } + + std::string user = stanza->getFrom().toBare(); + + boost::shared_ptr client = m_users[user]; + if (!client) + return; + + stanza->setFrom(client->getJID()); + + boost::shared_ptr message = boost::dynamic_pointer_cast(stanza); + if (message) { + client->sendMessage(message); + return; + } + + boost::shared_ptr presence = boost::dynamic_pointer_cast(stanza); + if (presence) { + client->sendPresence(presence); + return; + } + + boost::shared_ptr iq = boost::dynamic_pointer_cast(stanza); + if (iq) { + if (m_handlers[user]->m_id2resource.find(stanza->getID()) != m_handlers[user]->m_id2resource.end()) { + iq->setTo(Swift::JID(iq->getTo().getNode(), iq->getTo().getDomain(), m_handlers[user]->m_id2resource[stanza->getID()])); + m_handlers[user]->m_id2resource.erase(stanza->getID()); + } + client->getIQRouter()->sendIQ(iq); + return; + } + } + + void handleStreamEnd() {} + + void handleRawXML(const std::string &xml) { + m_xmppParser->parse(xml); + } + + void handleSwiftDisconnected(const std::string &user, const boost::optional &error) { + std::string message = ""; + bool reconnect = false; + if (error) { + switch(error->getType()) { + case Swift::ClientError::UnknownError: message = ("Unknown Error"); reconnect = true; break; + case Swift::ClientError::DomainNameResolveError: message = ("Unable to find server"); break; + case Swift::ClientError::ConnectionError: message = ("Error connecting to server"); break; + case Swift::ClientError::ConnectionReadError: message = ("Error while receiving server data"); reconnect = true; break; + case Swift::ClientError::ConnectionWriteError: message = ("Error while sending data to the server"); reconnect = true; break; + case Swift::ClientError::XMLError: message = ("Error parsing server data"); reconnect = true; break; + case Swift::ClientError::AuthenticationFailedError: message = ("Login/password invalid"); break; + case Swift::ClientError::CompressionFailedError: message = ("Error while compressing stream"); break; + case Swift::ClientError::ServerVerificationFailedError: message = ("Server verification failed"); break; + case Swift::ClientError::NoSupportedAuthMechanismsError: message = ("Authentication mechanisms not supported"); break; + case Swift::ClientError::UnexpectedElementError: message = ("Unexpected response"); break; + case Swift::ClientError::ResourceBindError: message = ("Error binding resource"); break; + case Swift::ClientError::SessionStartError: message = ("Error starting session"); break; + case Swift::ClientError::StreamError: message = ("Stream error"); break; + case Swift::ClientError::TLSError: message = ("Encryption error"); break; + case Swift::ClientError::ClientCertificateLoadError: message = ("Error loading certificate (Invalid password?)"); break; + case Swift::ClientError::ClientCertificateError: message = ("Certificate not authorized"); break; + + case Swift::ClientError::UnknownCertificateError: message = ("Unknown certificate"); break; + case Swift::ClientError::CertificateExpiredError: message = ("Certificate has expired"); break; + case Swift::ClientError::CertificateNotYetValidError: message = ("Certificate is not yet valid"); break; + case Swift::ClientError::CertificateSelfSignedError: message = ("Certificate is self-signed"); break; + case Swift::ClientError::CertificateRejectedError: message = ("Certificate has been rejected"); break; + case Swift::ClientError::CertificateUntrustedError: message = ("Certificate is not trusted"); break; + case Swift::ClientError::InvalidCertificatePurposeError: message = ("Certificate cannot be used for encrypting your connection"); break; + case Swift::ClientError::CertificatePathLengthExceededError: message = ("Certificate path length constraint exceeded"); break; + case Swift::ClientError::InvalidCertificateSignatureError: message = ("Invalid certificate signature"); break; + case Swift::ClientError::InvalidCAError: message = ("Invalid Certificate Authority"); break; + case Swift::ClientError::InvalidServerIdentityError: message = ("Certificate does not match the host identity"); break; + } + } + LOG4CXX_INFO(logger, user << ": Disconnected " << message); + handleDisconnected(user, reconnect ? 0 : 3, message); + + boost::shared_ptr client = m_users[user]; + if (client) { + client->onConnected.disconnect(boost::bind(&SwiftenPlugin::handleSwiftConnected, this, user)); + client->onDisconnected.disconnect(boost::bind(&SwiftenPlugin::handleSwiftDisconnected, this, user, _1)); + client->onMessageReceived.disconnect(boost::bind(&SwiftenPlugin::handleSwiftMessageReceived, this, user, _1)); + m_users.erase(user); + m_handlers.erase(user); + } + +#ifndef WIN32 +#ifndef __FreeBSD__ +#ifndef __MACH__ + // force returning of memory chunks allocated by libxml2 to kernel + malloc_trim(0); +#endif +#endif +#endif + } + + void handleSwiftConnected(const std::string &user) { + LOG4CXX_INFO(logger, user << ": Connected to XMPP server."); + handleConnected(user); + m_users[user]->requestRoster(); + Swift::Presence::ref response = Swift::Presence::create(); + response->setFrom(m_users[user]->getJID()); + m_users[user]->sendPresence(response); + } + + void handleSwiftRosterReceived(const std::string &user) { + Swift::PresenceOracle *oracle = m_users[user]->getPresenceOracle(); + BOOST_FOREACH(const Swift::XMPPRosterItem &item, m_users[user]->getRoster()->getItems()) { + Swift::Presence::ref lastPresence = oracle->getLastPresence(item.getJID()); + pbnetwork::StatusType status = lastPresence ? ((pbnetwork::StatusType) lastPresence->getShow()) : pbnetwork::STATUS_NONE; + handleBuddyChanged(user, item.getJID().toBare().toString(), + item.getName(), item.getGroups(), status); + } + } + + void handleSwiftPresenceChanged(const std::string &user, Swift::Presence::ref presence) { +// boost::shared_ptr client = m_users[user]; +// if (client->getMUCRegistry()->isMUC(presence->getFrom().toBare())) { +// return; +// } +// +// if (presence->getPayload() != NULL || presence->getPayload() != NULL) { +// return; +// } +// +// LOG4CXX_INFO(logger, user << ": " << presence->getFrom().toBare().toString() << " presence changed"); +// +// std::string message = presence->getStatus(); +// std::string photo = ""; +// +// boost::shared_ptr update = presence->getPayload(); +// if (update) { +// photo = update->getPhotoHash(); +// } +// +// boost::optional item = m_users[user]->getRoster()->getItem(presence->getFrom()); +// if (item) { +// handleBuddyChanged(user, presence->getFrom().toBare().toString(), item->getName(), item->getGroups(), (pbnetwork::StatusType) presence->getShow(), message, photo); +// } +// else { +// std::vector groups; +// handleBuddyChanged(user, presence->getFrom().toBare().toString(), presence->getFrom().toBare(), groups, (pbnetwork::StatusType) presence->getShow(), message, photo); +// } + presence->setTo(user); + std::string xml = safeByteArrayToString(serializer->serializeElement(presence)); + sendRawXML(xml); + } + + void handleSwiftMessageReceived(const std::string &user, Swift::Message::ref message) { + message->setTo(user); + std::string xml = safeByteArrayToString(serializer->serializeElement(message)); + sendRawXML(xml); + } + + void handleSwiftenDataRead(const Swift::SafeByteArray &data) { + std::string d = safeByteArrayToString(data); + if (!boost::starts_with(d, " client = boost::make_shared(Swift::JID(legacyName), password, m_factories); + m_users[user] = client; + client->setAlwaysTrustCertificates(); + client->onConnected.connect(boost::bind(&SwiftenPlugin::handleSwiftConnected, this, user)); + client->onDisconnected.connect(boost::bind(&SwiftenPlugin::handleSwiftDisconnected, this, user, _1)); + client->onMessageReceived.connect(boost::bind(&SwiftenPlugin::handleSwiftMessageReceived, this, user, _1)); + client->getRoster()->onInitialRosterPopulated.connect(boost::bind(&SwiftenPlugin::handleSwiftRosterReceived, this, user)); + client->getPresenceOracle()->onPresenceChange.connect(boost::bind(&SwiftenPlugin::handleSwiftPresenceChanged, this, user, _1)); + client->onDataRead.connect(boost::bind(&SwiftenPlugin::handleSwiftenDataRead, this, _1)); + client->onDataWritten.connect(boost::bind(&SwiftenPlugin::handleSwiftenDataWritten, this, _1)); + Swift::ClientOptions opt; + opt.allowPLAINWithoutTLS = true; + client->connect(opt); + + boost::shared_ptr handler = boost::make_shared(this, user); + client->getIQRouter()->addHandler(handler); + m_handlers[user] = handler; + } + + void handleLogoutRequest(const std::string &user, const std::string &legacyName) { + boost::shared_ptr client = m_users[user]; + if (client) { + client->onConnected.disconnect(boost::bind(&SwiftenPlugin::handleSwiftConnected, this, user)); +// client->onDisconnected.disconnect(boost::bind(&SwiftenPlugin::handleSwiftDisconnected, this, user, _1)); + client->onMessageReceived.disconnect(boost::bind(&SwiftenPlugin::handleSwiftMessageReceived, this, user, _1)); + client->getRoster()->onInitialRosterPopulated.disconnect(boost::bind(&SwiftenPlugin::handleSwiftRosterReceived, this, user)); + client->getPresenceOracle()->onPresenceChange.disconnect(boost::bind(&SwiftenPlugin::handleSwiftPresenceChanged, this, user, _1)); + client->disconnect(); + } + } + + void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &msg, const std::string &xhtml = "", const std::string &id = "") { + } + + void handleVCardRequest(const std::string &user, const std::string &legacyName, unsigned int id) { + } + + void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector &groups) { + boost::shared_ptr client = m_users[user]; + if (client) { + LOG4CXX_INFO(logger, user << ": Added/Updated buddy " << buddyName << "."); + if (!client->getRoster()->containsJID(buddyName) || client->getRoster()->getSubscriptionStateForJID(buddyName) != Swift::RosterItemPayload::Both) { + Swift::RosterItemPayload item; + item.setName(alias); + item.setJID(buddyName); + item.setGroups(groups); + boost::shared_ptr roster(new Swift::RosterPayload()); + roster->addItem(item); + Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(roster, client->getIQRouter()); +// request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster)); + request->send(); + client->getSubscriptionManager()->requestSubscription(buddyName); + } + else { + Swift::JID contact(buddyName); + Swift::RosterItemPayload item(contact, alias, client->getRoster()->getSubscriptionStateForJID(contact)); + item.setGroups(groups); + boost::shared_ptr roster(new Swift::RosterPayload()); + roster->addItem(item); + Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(roster, client->getIQRouter()); +// request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster)); + request->send(); + } + + } + } + + void handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector &groups) { + boost::shared_ptr client = m_users[user]; + if (client) { + Swift::RosterItemPayload item(buddyName, "", Swift::RosterItemPayload::Remove); + boost::shared_ptr roster(new Swift::RosterPayload()); + roster->addItem(item); + Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(roster, client->getIQRouter()); +// request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster)); + request->send(); + } + } + + 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) { + + } + + private: + Config *config; + std::map > m_users; + std::map > m_handlers; +}; + +#ifndef WIN32 +static void spectrum_sigchld_handler(int sig) +{ + int status; + pid_t pid; + + do { + pid = waitpid(-1, &status, WNOHANG); + } while (pid != 0 && pid != (pid_t)-1); + + if ((pid == (pid_t) - 1) && (errno != ECHILD)) { + char errmsg[BUFSIZ]; + snprintf(errmsg, BUFSIZ, "Warning: waitpid() returned %d", pid); + perror(errmsg); + } +} +#endif + + +int main (int argc, char* argv[]) { + std::string host; + int port; + +#ifndef WIN32 + if (signal(SIGCHLD, spectrum_sigchld_handler) == SIG_ERR) { + std::cout << "SIGCHLD handler can't be set\n"; + return -1; + } +#endif + + std::string error; + Config *cfg = Config::createFromArgs(argc, argv, error, host, port); + if (cfg == NULL) { + std::cerr << error; + return 1; + } + + Logging::initBackendLogging(cfg); + + Swift::SimpleEventLoop eventLoop; + loop_ = &eventLoop; + np = new SwiftenPlugin(cfg, &eventLoop, host, port); + loop_->run(); + + return 0; +}