/* * Copyright (c) 2013 Remko Tronçon * Licensed under the GNU General Public License. * See the COPYING file for more information. */ #include #include #include #include #include #include #include #include #include #include #include using namespace Swift; SluiftClient::SluiftClient( const JID& jid, const std::string& password, NetworkFactories* networkFactories, SimpleEventLoop* eventLoop) : networkFactories(networkFactories), eventLoop(eventLoop), tracer(NULL) { client = new Client(jid, password, networkFactories); client->setAlwaysTrustCertificates(); client->onDisconnected.connect(boost::bind(&SluiftClient::handleDisconnected, this, _1)); client->onMessageReceived.connect(boost::bind(&SluiftClient::handleIncomingMessage, this, _1)); client->onPresenceReceived.connect(boost::bind(&SluiftClient::handleIncomingPresence, this, _1)); client->getPubSubManager()->onEvent.connect(boost::bind(&SluiftClient::handleIncomingPubSubEvent, this, _1, _2)); client->getRoster()->onInitialRosterPopulated.connect(boost::bind(&SluiftClient::handleInitialRosterPopulated, this)); } SluiftClient::~SluiftClient() { delete tracer; delete client; } void SluiftClient::connect() { rosterReceived = false; disconnectedError = boost::optional(); client->connect(options); } void SluiftClient::connect(const std::string& host, int port) { rosterReceived = false; options.manualHostname = host; options.manualPort = port; disconnectedError = boost::optional(); client->connect(options); } void SluiftClient::setTraceEnabled(bool b) { if (b && !tracer) { tracer = new ClientXMLTracer(client, options.boshURL.isEmpty()? false: true); } else if (!b && tracer) { delete tracer; tracer = NULL; } } void SluiftClient::waitConnected(int timeout) { Watchdog watchdog(timeout, networkFactories->getTimerFactory()); while (!watchdog.getTimedOut() && client->isActive() && !client->isAvailable()) { eventLoop->runUntilEvents(); } if (watchdog.getTimedOut()) { client->disconnect(); throw Lua::Exception("Timeout while connecting"); } if (disconnectedError) { throw Lua::Exception(getClientErrorString(*disconnectedError)); } } bool SluiftClient::isConnected() const { return client->isAvailable(); } void SluiftClient::disconnect() { client->disconnect(); while (client->isActive()) { eventLoop->runUntilEvents(); } } void SluiftClient::setSoftwareVersion(const std::string& name, const std::string& version, const std::string& os) { client->setSoftwareVersion(name, version, os); } boost::optional SluiftClient::getNextEvent( int timeout, boost::function condition) { Watchdog watchdog(timeout, networkFactories->getTimerFactory()); while (true) { // Look for pending events in the queue while (!pendingEvents.empty()) { Event event = pendingEvents.front(); pendingEvents.pop_front(); if (!condition || condition(event)) { return event; } } // Wait for new events while (!watchdog.getTimedOut() && pendingEvents.empty() && client->isActive()) { eventLoop->runUntilEvents(); } // Finish if we're disconnected or timed out if (watchdog.getTimedOut() || !client->isActive()) { return boost::optional(); } } } std::vector SluiftClient::getRoster() { if (!rosterReceived) { // If we haven't requested it yet, request it for the first time client->requestRoster(); } while (!rosterReceived) { eventLoop->runUntilEvents(); } return client->getRoster()->getItems(); } void SluiftClient::handleIncomingMessage(boost::shared_ptr stanza) { if (stanza->getPayload()) { // Already handled by pubsub manager return; } pendingEvents.push_back(Event(stanza)); } void SluiftClient::handleIncomingPresence(boost::shared_ptr stanza) { pendingEvents.push_back(Event(stanza)); } void SluiftClient::handleIncomingPubSubEvent(const JID& from, boost::shared_ptr event) { pendingEvents.push_back(Event(from, event)); } void SluiftClient::handleInitialRosterPopulated() { rosterReceived = true; } void SluiftClient::handleRequestResponse(boost::shared_ptr response, boost::shared_ptr error) { requestResponse = response; requestError = error; requestResponseReceived = true; } void SluiftClient::handleDisconnected(const boost::optional& error) { disconnectedError = error; } Sluift::Response SluiftClient::doSendRequest(boost::shared_ptr request, int timeout) { requestResponse.reset(); requestError.reset(); requestResponseReceived = false; request->send(); Watchdog watchdog(timeout, networkFactories->getTimerFactory()); while (!watchdog.getTimedOut() && !requestResponseReceived) { eventLoop->runUntilEvents(); } return Sluift::Response(requestResponse, watchdog.getTimedOut() ? boost::make_shared(ErrorPayload::RemoteServerTimeout) : requestError); }