diff options
Diffstat (limited to 'Sluift/SluiftClient.cpp')
-rw-r--r-- | Sluift/SluiftClient.cpp | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/Sluift/SluiftClient.cpp b/Sluift/SluiftClient.cpp new file mode 100644 index 0000000..726a683 --- /dev/null +++ b/Sluift/SluiftClient.cpp @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/SluiftClient.h> + +#include <Swiften/Client/ClientXMLTracer.h> +#include <Swiften/Client/Client.h> +#include <Swiften/Roster/XMPPRoster.h> +#include <Sluift/SluiftGlobals.h> +#include <Sluift/Lua/Exception.h> +#include <Swiften/Elements/Message.h> +#include <Swiften/Elements/PubSubEvent.h> +#include <Swiften/Queries/RawRequest.h> +#include <Sluift/ClientHelpers.h> +#include <Swiften/Elements/Presence.h> + +using namespace Swift; + +SluiftClient::SluiftClient( + const JID& jid, + const std::string& password, + NetworkFactories* networkFactories, + SimpleEventLoop* eventLoop, + SluiftGlobals* globals) : + networkFactories(networkFactories), + eventLoop(eventLoop), + globals(globals), + 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)); + if (globals->debug) { + tracer = new ClientXMLTracer(client); + } +} + +SluiftClient::~SluiftClient() { + delete tracer; + delete client; +} + +void SluiftClient::connect() { + rosterReceived = false; + disconnectedError = boost::optional<ClientError>(); + client->connect(options); +} + +void SluiftClient::connect(const std::string& host) { + rosterReceived = false; + options.manualHostname = host; + client->connect(options); +} + +void SluiftClient::waitConnected() { + Watchdog watchdog(globals->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::Event> SluiftClient::getNextEvent(boost::optional<Event::Type> type, int timeout) { + 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 (!type || *type == event.type) { + 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<Event>(); + } + } +} + +std::vector<XMPPRosterItem> 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<Message> stanza) { + if (stanza->getPayload<PubSubEvent>()) { + // Already handled by pubsub manager + return; + } + pendingEvents.push_back(Event(stanza)); +} + +void SluiftClient::handleIncomingPresence(boost::shared_ptr<Presence> stanza) { + pendingEvents.push_back(Event(stanza)); +} + +void SluiftClient::handleIncomingPubSubEvent(const JID& from, boost::shared_ptr<PubSubEventPayload> event) { + pendingEvents.push_back(Event(from, event)); +} + +void SluiftClient::handleInitialRosterPopulated() { + rosterReceived = true; +} + +void SluiftClient::handleRequestResponse(boost::shared_ptr<Payload> response, boost::shared_ptr<ErrorPayload> error) { + requestResponse = response; + requestError = error; + requestResponseReceived = true; +} + +void SluiftClient::handleDisconnected(const boost::optional<ClientError>& error) { + disconnectedError = error; +} + +Sluift::Response SluiftClient::doSendRequest(boost::shared_ptr<Request> 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>(ErrorPayload::RemoteServerTimeout) : requestError); +} |