summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Sluift/SluiftClient.cpp35
-rw-r--r--Sluift/SluiftClient.h16
-rw-r--r--Sluift/client.cpp37
3 files changed, 83 insertions, 5 deletions
diff --git a/Sluift/SluiftClient.cpp b/Sluift/SluiftClient.cpp
index f1c0191..4680d4b 100644
--- a/Sluift/SluiftClient.cpp
+++ b/Sluift/SluiftClient.cpp
@@ -1,84 +1,89 @@
/*
- * Copyright (c) 2013-2016 Isode Limited.
+ * Copyright (c) 2013-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#include <Sluift/SluiftClient.h>
#include <boost/numeric/conversion/cast.hpp>
#include <Swiften/Client/Client.h>
+#include <Swiften/Client/ClientBlockListManager.h>
#include <Swiften/Client/ClientXMLTracer.h>
#include <Swiften/Elements/Message.h>
#include <Swiften/Elements/Presence.h>
#include <Swiften/Elements/PubSubEvent.h>
#include <Swiften/Queries/RawRequest.h>
#include <Swiften/Roster/XMPPRoster.h>
#include <Sluift/Helpers.h>
#include <Sluift/Lua/Exception.h>
#include <Sluift/SluiftGlobals.h>
using namespace Swift;
SluiftClient::SluiftClient(
const JID& jid,
const std::string& password,
NetworkFactories* networkFactories,
SimpleEventLoop* eventLoop) :
networkFactories(networkFactories),
eventLoop(eventLoop),
tracer(nullptr) {
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));
+ client->getClientBlockListManager()->getBlockList()->onItemAdded.connect(boost::bind(&SluiftClient::handleIncomingBlockEvent, this, _1));
+ client->getClientBlockListManager()->getBlockList()->onItemRemoved.connect(boost::bind(&SluiftClient::handleIncomingUnblockEvent, this, _1));
}
SluiftClient::~SluiftClient() {
delete tracer;
delete client;
}
void SluiftClient::connect() {
rosterReceived = false;
+ blockListReceived = false;
disconnectedError = boost::optional<ClientError>();
client->connect(options);
}
void SluiftClient::connect(const std::string& host, int port) {
rosterReceived = false;
+ blockListReceived = false;
options.manualHostname = host;
options.manualPort = port;
disconnectedError = boost::optional<ClientError>();
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 = nullptr;
}
}
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(getErrorString(*disconnectedError));
}
}
@@ -99,92 +104,120 @@ void SluiftClient::setSoftwareVersion(const std::string& name, const std::string
boost::optional<SluiftClient::Event> SluiftClient::getNextEvent(
int timeout, boost::function<bool (const Event&)> condition) {
Watchdog watchdog(timeout, networkFactories->getTimerFactory());
size_t currentIndex = 0;
while (true) {
// Look for pending events in the queue
while (currentIndex < pendingEvents.size()) {
Event event = pendingEvents[currentIndex];
if (!condition || condition(event)) {
pendingEvents.erase(
pendingEvents.begin()
+ boost::numeric_cast<int>(currentIndex));
return event;
}
++currentIndex;
}
// Wait for new events
while (!watchdog.getTimedOut() && currentIndex >= pendingEvents.size() && client->isActive()) {
eventLoop->runUntilEvents();
}
// Finish if we're disconnected or timed out
if (watchdog.getTimedOut() || !client->isActive()) {
return boost::optional<Event>();
}
}
}
+std::vector<JID> SluiftClient::getBlockList(int timeout) {
+ Watchdog watchdog(timeout, networkFactories->getTimerFactory());
+ if (!blockListReceived) {
+ // If we haven't requested it yet, request it for the first time
+ client->getClientBlockListManager()->requestBlockList();
+
+ // Wait for new events
+ while (!watchdog.getTimedOut() && client->getClientBlockListManager()->getBlockList()->getState() != BlockList::Available) {
+ eventLoop->runUntilEvents();
+ }
+
+ // Throw an error if we're timed out
+ if (watchdog.getTimedOut()) {
+ throw Lua::Exception("Timeout while requesting blocklist");
+ }
+ }
+ blockListReceived = true;
+ return client->getClientBlockListManager()->getBlockList()->getItems();
+}
+
std::vector<XMPPRosterItem> SluiftClient::getRoster(int timeout) {
Watchdog watchdog(timeout, networkFactories->getTimerFactory());
if (!rosterReceived) {
// If we haven't requested it yet, request it for the first time
client->requestRoster();
// Wait for new events
while (!watchdog.getTimedOut() && !rosterReceived) {
eventLoop->runUntilEvents();
}
// Throw an error if we're timed out
if (watchdog.getTimedOut()) {
throw Lua::Exception("Timeout while requesting roster");
}
}
return client->getRoster()->getItems();
}
void SluiftClient::handleIncomingMessage(std::shared_ptr<Message> stanza) {
if (stanza->getPayload<PubSubEvent>()) {
// Already handled by pubsub manager
return;
}
pendingEvents.push_back(Event(stanza));
}
void SluiftClient::handleIncomingPresence(std::shared_ptr<Presence> stanza) {
pendingEvents.push_back(Event(stanza));
}
void SluiftClient::handleIncomingPubSubEvent(const JID& from, std::shared_ptr<PubSubEventPayload> event) {
pendingEvents.push_back(Event(from, event));
}
+void SluiftClient::handleIncomingBlockEvent(const JID& item) {
+ pendingEvents.push_back(Event(item, Event::BlockEventType));
+}
+
+void SluiftClient::handleIncomingUnblockEvent(const JID& item) {
+ pendingEvents.push_back(Event(item, Event::UnblockEventType));
+}
+
void SluiftClient::handleInitialRosterPopulated() {
rosterReceived = true;
}
void SluiftClient::handleRequestResponse(std::shared_ptr<Payload> response, std::shared_ptr<ErrorPayload> error) {
requestResponse = response;
requestError = error;
requestResponseReceived = true;
}
void SluiftClient::handleDisconnected(const boost::optional<ClientError>& error) {
disconnectedError = error;
}
Sluift::Response SluiftClient::doSendRequest(std::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() ?
std::make_shared<ErrorPayload>(ErrorPayload::RemoteServerTimeout) : requestError);
}
diff --git a/Sluift/SluiftClient.h b/Sluift/SluiftClient.h
index 2c221e6..a48c681 100644
--- a/Sluift/SluiftClient.h
+++ b/Sluift/SluiftClient.h
@@ -1,133 +1,143 @@
/*
- * Copyright (c) 2013-2016 Isode Limited.
+ * Copyright (c) 2013-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#pragma once
#include <deque>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/optional.hpp>
#include <Swiften/Client/Client.h>
+#include <Swiften/Client/ClientBlockListManager.h>
#include <Swiften/Client/ClientError.h>
#include <Swiften/Client/ClientOptions.h>
#include <Swiften/Elements/IQ.h>
#include <Swiften/Elements/Message.h>
#include <Swiften/Elements/Presence.h>
#include <Swiften/EventLoop/SimpleEventLoop.h>
#include <Swiften/Network/NetworkFactories.h>
#include <Swiften/PubSub/PubSubManager.h>
#include <Swiften/Queries/GenericRequest.h>
#include <Swiften/Roster/XMPPRosterItem.h>
#include <Sluift/Response.h>
#include <Sluift/Watchdog.h>
namespace Swift {
struct SluiftGlobals;
class ClientXMLTracer;
class Client;
class Stanza;
class Payload;
class ErrorPayload;
class JID;
class SluiftClient {
public:
struct Event {
enum Type {
MessageType,
PresenceType,
- PubSubEventType
+ PubSubEventType,
+ BlockEventType,
+ UnblockEventType
};
Event(std::shared_ptr<Message> stanza) : type(MessageType), stanza(stanza) {}
Event(std::shared_ptr<Presence> stanza) : type(PresenceType), stanza(stanza) {}
Event(const JID& from, std::shared_ptr<PubSubEventPayload> payload) : type(PubSubEventType), from(from), pubsubEvent(payload) {}
-
+ Event(const JID& item, Type type) : type(type), item(item) {}
Type type;
// Message & Presence
std::shared_ptr<Stanza> stanza;
// PubSubEvent
JID from;
std::shared_ptr<PubSubEventPayload> pubsubEvent;
+
+ // Blocklist
+ JID item;
};
SluiftClient(
const JID& jid,
const std::string& password,
NetworkFactories* networkFactories,
SimpleEventLoop* eventLoop);
~SluiftClient();
Client* getClient() {
return client;
}
ClientOptions& getOptions() {
return options;
}
void connect();
void connect(const std::string& host, int port);
void waitConnected(int timeout);
bool isConnected() const;
void setTraceEnabled(bool b);
template<typename T>
Sluift::Response sendPubSubRequest(
IQ::Type type, const JID& jid, std::shared_ptr<T> payload, int timeout) {
return sendRequest(client->getPubSubManager()->createRequest(
type, jid, payload), timeout);
}
template<typename REQUEST_TYPE>
Sluift::Response sendRequest(REQUEST_TYPE request, int timeout) {
boost::signals2::scoped_connection c(request->onResponse.connect(
boost::bind(&SluiftClient::handleRequestResponse, this, _1, _2)));
return doSendRequest(request, timeout);
}
template<typename REQUEST_TYPE>
Sluift::Response sendVoidRequest(REQUEST_TYPE request, int timeout) {
boost::signals2::scoped_connection c(request->onResponse.connect(
boost::bind(&SluiftClient::handleRequestResponse, this, std::shared_ptr<Payload>(), _1)));
return doSendRequest(request, timeout);
}
void disconnect();
void setSoftwareVersion(const std::string& name, const std::string& version, const std::string& os);
boost::optional<SluiftClient::Event> getNextEvent(int timeout,
boost::function<bool (const Event&)> condition = 0);
std::vector<XMPPRosterItem> getRoster(int timeout);
+ std::vector<JID> getBlockList(int timeout);
private:
Sluift::Response doSendRequest(std::shared_ptr<Request> request, int timeout);
void handleIncomingMessage(std::shared_ptr<Message> stanza);
void handleIncomingPresence(std::shared_ptr<Presence> stanza);
void handleIncomingPubSubEvent(const JID& from, std::shared_ptr<PubSubEventPayload> event);
+ void handleIncomingBlockEvent(const JID& item);
+ void handleIncomingUnblockEvent(const JID& item);
void handleInitialRosterPopulated();
void handleRequestResponse(std::shared_ptr<Payload> response, std::shared_ptr<ErrorPayload> error);
void handleDisconnected(const boost::optional<ClientError>& error);
private:
NetworkFactories* networkFactories;
SimpleEventLoop* eventLoop;
Client* client;
ClientOptions options;
ClientXMLTracer* tracer;
bool rosterReceived = false;
+ bool blockListReceived = false;
std::deque<Event> pendingEvents;
boost::optional<ClientError> disconnectedError;
bool requestResponseReceived = false;
std::shared_ptr<Payload> requestResponse;
std::shared_ptr<ErrorPayload> requestError;
};
}
diff --git a/Sluift/client.cpp b/Sluift/client.cpp
index 186effc..53e253f 100644
--- a/Sluift/client.cpp
+++ b/Sluift/client.cpp
@@ -1,32 +1,32 @@
/*
- * Copyright (c) 2013-2016 Isode Limited.
+ * Copyright (c) 2013-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#include <boost/assign/list_of.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/lambda/lambda.hpp>
#include <Swiften/Base/IDGenerator.h>
#include <Swiften/Disco/ClientDiscoManager.h>
#include <Swiften/Elements/DiscoInfo.h>
#include <Swiften/Elements/Message.h>
#include <Swiften/Elements/Presence.h>
#include <Swiften/Elements/RawXMLPayload.h>
#include <Swiften/Elements/RosterItemPayload.h>
#include <Swiften/Elements/RosterPayload.h>
#include <Swiften/Elements/SoftwareVersion.h>
#include <Swiften/JID/JID.h>
#include <Swiften/Presence/PresenceSender.h>
#include <Swiften/Presence/SubscriptionManager.h>
#include <Swiften/Queries/GenericRequest.h>
#include <Swiften/Queries/IQRouter.h>
#include <Swiften/Queries/Requests/GetSoftwareVersionRequest.h>
#include <Swiften/Roster/SetRosterRequest.h>
#include <Swiften/Roster/XMPPRoster.h>
#include <Swiften/Roster/XMPPRosterItem.h>
#include <Swiften/TLS/PKCS12Certificate.h>
#include <Sluift/ElementConvertors/IQConvertor.h>
#include <Sluift/ElementConvertors/MessageConvertor.h>
@@ -179,60 +179,78 @@ SLUIFT_LUA_FUNCTION_WITH_HELP(
"Returns a table of all the contacts in the contact list.",
"self\n",
""
) {
Sluift::globals.eventLoop.runOnce();
SluiftClient* client = getClient(L);
Lua::Table contactsTable;
for (const auto& item : client->getRoster(getGlobalTimeout(L))) {
std::string subscription;
switch(item.getSubscription()) {
case RosterItemPayload::None: subscription = "none"; break;
case RosterItemPayload::To: subscription = "to"; break;
case RosterItemPayload::From: subscription = "from"; break;
case RosterItemPayload::Both: subscription = "both"; break;
case RosterItemPayload::Remove: subscription = "remove"; break;
}
Lua::Table itemTable = boost::assign::map_list_of
("jid", std::make_shared<Lua::Value>(item.getJID().toString()))
("name", std::make_shared<Lua::Value>(item.getName()))
("subscription", std::make_shared<Lua::Value>(subscription))
("groups", std::make_shared<Lua::Value>(std::vector<Lua::Value>(item.getGroups().begin(), item.getGroups().end())));
contactsTable[item.getJID().toString()] = std::make_shared<Lua::Value>(itemTable);
}
pushValue(L, contactsTable);
Lua::registerTableToString(L, -1);
return 1;
}
SLUIFT_LUA_FUNCTION_WITH_HELP(
+ Client, get_block_list,
+ "Returns a table of all the items in the blocking list.",
+ "self\n",
+ ""
+) {
+ Sluift::globals.eventLoop.runOnce();
+ SluiftClient* client = getClient(L);
+ lua_newtable(L);
+ int i = 0;
+ for (const auto& item : client->getBlockList(getGlobalTimeout(L))) {
+ lua_pushstring(L, item.toString().c_str());
+ lua_rawseti(L, -2, boost::numeric_cast<int>(++i));
+ }
+ Lua::registerTableToString(L, -1);
+ return 1;
+}
+
+SLUIFT_LUA_FUNCTION_WITH_HELP(
Client, send_message,
"Send a message.",
"self\n"
"to the JID to send the message to\n"
"body the body of the message. Can alternatively be specified using the `body` option\n",
"to the JID to send the message to\n"
"body the body of the message\n"
"subject the subject of the MUC room to set\n"
"type the type of message to send (`normal`, `chat`, `error`, `groupchat`, `headline`)\n"
"payloads payloads to add to the message\n"
) {
Sluift::globals.eventLoop.runOnce();
JID to;
boost::optional<std::string> body;
boost::optional<std::string> subject;
std::vector<std::shared_ptr<Payload> > payloads;
int index = 2;
Message::Type type = Message::Chat;
if (lua_isstring(L, index)) {
to = std::string(lua_tostring(L, index));
++index;
if (lua_isstring(L, index)) {
body = lua_tostring(L, index);
++index;
}
}
if (lua_istable(L, index)) {
if (boost::optional<std::string> value = Lua::getStringField(L, index, "to")) {
to = *value;
@@ -491,60 +509,77 @@ static void pushEvent(lua_State* L, const SluiftClient::Event& event) {
Lua::pushValue(L, result);
addPayloadsToTable(L, message->getPayloads());
Lua::registerTableToString(L, -1);
break;
}
case SluiftClient::Event::PresenceType: {
Presence::ref presence = std::dynamic_pointer_cast<Presence>(event.stanza);
Lua::Table result = boost::assign::map_list_of
("type", std::make_shared<Lua::Value>(std::string("presence")))
("from", std::make_shared<Lua::Value>(presence->getFrom().toString()))
("to", std::make_shared<Lua::Value>(presence->getTo().toString()))
("status", std::make_shared<Lua::Value>(presence->getStatus()))
("presence_type", std::make_shared<Lua::Value>(PresenceConvertor::convertPresenceTypeToString(presence->getType())));
Lua::pushValue(L, result);
addPayloadsToTable(L, presence->getPayloads());
Lua::registerTableToString(L, -1);
break;
}
case SluiftClient::Event::PubSubEventType: {
Sluift::globals.elementConvertor.convertToLua(L, event.pubsubEvent);
lua_pushstring(L, "pubsub");
lua_setfield(L, -2, "type");
lua_pushstring(L, event.from.toString().c_str());
lua_setfield(L, -2, "from");
lua_rawgeti(L, LUA_REGISTRYINDEX, Sluift::globals.coreLibIndex);
lua_getfield(L, -1, "process_pubsub_event");
lua_pushvalue(L, -3);
lua_call(L, 1, 0);
lua_pop(L, 1);
+ break;
+ }
+ case SluiftClient::Event::BlockEventType: {
+ Lua::Table result = boost::assign::map_list_of
+ ("type", std::make_shared<Lua::Value>(std::string("block")))
+ ("jid", std::make_shared<Lua::Value>(event.item.toString()));
+ Lua::pushValue(L, result);
+ Lua::registerTableToString(L, -1);
+ break;
+ }
+ case SluiftClient::Event::UnblockEventType: {
+ Lua::Table result = boost::assign::map_list_of
+ ("type", std::make_shared<Lua::Value>(std::string("unblock")))
+ ("jid", std::make_shared<Lua::Value>(event.item.toString()));
+ Lua::pushValue(L, result);
+ Lua::registerTableToString(L, -1);
+ break;
}
}
}
struct CallUnaryLuaPredicateOnEvent {
CallUnaryLuaPredicateOnEvent(lua_State* L, int index) : L(L), index(index) {
}
bool operator()(const SluiftClient::Event& event) {
lua_pushvalue(L, index);
pushEvent(L, event);
if (lua_pcall(L, 1, 1, 0) != 0) {
throw Lua::Exception(lua_tostring(L, -1));
}
bool result = lua_toboolean(L, -1);
lua_pop(L, 1);
return result;
}
lua_State* L;
int index;
};
SLUIFT_LUA_FUNCTION(Client, get_next_event) {
Sluift::globals.eventLoop.runOnce();
SluiftClient* client = getClient(L);
int timeout = getGlobalTimeout(L);
boost::optional<SluiftClient::Event::Type> type;