Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add joining a MIX channel by invitation #86

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Add joining a channel by invitation
Add requesting invitation token, sending to invitee and acknowledging invitee's response.

License:
This patch is BSD-licensed, see Documentation/Licenses/BSD-simplified.txt for details.

Test-Information:
Added tests for requesting invitation token based on examples in XEP 0369, which passes.
Tested on Ubuntu 16.04 LTS.

Change-Id: Icd822b440cb633b12c6dd15798e97d2fc302cb40
  • Loading branch information
tarun018 committed Jul 22, 2017
commit 09e012493d95e9d398db84d3012505d3cb26167c
11 changes: 10 additions & 1 deletion Swiften/Elements/MIXJoin.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <Swiften/Base/API.h>
#include <Swiften/Elements/Payload.h>
#include <Swiften/Elements/Form.h>
#include <Swiften/Elements/MIXInvitation.h>
#include <Swiften/JID/JID.h>

namespace Swift {
Expand Down Expand Up @@ -67,11 +68,19 @@ namespace Swift {
return form_;
}

const boost::optional<MIXInvitation::ref>& getInvitation() const {
return invitation_;
}

void setInvitation(MIXInvitation::ref invitation) {
invitation_ = invitation;
}

private:
boost::optional<JID> jid_;
boost::optional<JID> channel_;
std::unordered_set<std::string> subscribeItems_;
std::shared_ptr<Form> form_;
// FIXME: MIXInvitation to be implemented. boost::optional<MIXInvitation> invitation_;
boost::optional<MIXInvitation::ref> invitation_;
};
}
31 changes: 29 additions & 2 deletions Swiften/MIX/MIX.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@
#include <Swiften/Base/API.h>
#include <Swiften/JID/JID.h>
#include <Swiften/Elements/Form.h>
#include <Swiften/Elements/Message.h>
#include <Swiften/Elements/MIXJoin.h>
#include <Swiften/Elements/MIXLeave.h>
#include <Swiften/Elements/MIXUpdateSubscription.h>
#include <Swiften/Elements/MIXUserPreference.h>
#include <Swiften/Elements/MIXInvite.h>
#include <Swiften/Elements/MIXInvitation.h>
#include <Swiften/Elements/MIXInvitationAck.h>
#include <Swiften/Elements/ErrorPayload.h>

namespace Swift {
Expand All @@ -29,16 +33,26 @@ namespace Swift {
public:
virtual ~MIX();

/**
* Join Channel with preferences and subscriptions to node with invitation.
*/
virtual void joinChannel(const std::unordered_set<std::string>& nodes, Form::ref form, MIXInvitation::ref invitation) = 0;

/**
* Join a MIX channel and subscribe to nodes.
*/
virtual void joinChannel(const std::unordered_set<std::string>& nodes) = 0;
virtual void joinChannelWithSubscriptions(const std::unordered_set<std::string>& nodes) = 0;

/**
* Join Channel with a set of preferences.
* Join Channel with preferences and subscriptions to node with invitation.
*/
virtual void joinChannelWithPreferences(const std::unordered_set<std::string>& nodes, Form::ref form) = 0;

/**
* Join channel with invite and subscribe to nodes.
*/
virtual void joinChannelWithInvite(const std::unordered_set<std::string>& nodes, MIXInvitation::ref invitation) = 0;

/**
* Update subscription of nodes.
*/
Expand All @@ -59,6 +73,16 @@ namespace Swift {
*/
virtual void updatePreferences(Form::ref form) = 0;

/**
* Request invitation payload along with token for invitee.
*/
virtual void requestInvitation(const JID& invitee) = 0;

/**
* Invite invitee based on received token from requestInvitation.
*/
virtual void sendInvitation(MIXInvitation::ref invitation, std::string invitationMessage) = 0;

public:
boost::signals2::signal<void (MIXJoin::ref /* joinResponse */)> onJoinComplete;
boost::signals2::signal<void (ErrorPayload::ref /* joinError */)> onJoinFailed;
Expand All @@ -68,5 +92,8 @@ namespace Swift {
boost::signals2::signal<void (ErrorPayload::ref /* updateError */)> onSubscriptionUpdateFailed;
boost::signals2::signal<void (Form::ref /* preferencesForm */)> onPreferencesFormReceived;
boost::signals2::signal<void (ErrorPayload::ref /* failedConfiguration */)> onPreferencesUpdateFailed;
boost::signals2::signal<void (MIXInvitation::ref /* inviteResponse */)> onInvitationReceived;
boost::signals2::signal<void (ErrorPayload::ref /* failedConfiguration */)> onInvitationRequestFailed;
boost::signals2::signal<void (Message::ref /* message */)> onMessageReceived;
};
}
55 changes: 48 additions & 7 deletions Swiften/MIX/MIXImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,15 @@

namespace Swift {

MIXImpl::MIXImpl(const JID& ownJID, const JID& channelJID, IQRouter* iqRouter) : ownJID_(ownJID), channelJID_(channelJID), iqRouter_(iqRouter) {

MIXImpl::MIXImpl(const JID& ownJID, const JID& channelJID, IQRouter* iqRouter, StanzaChannel* stanzaChannel) : ownJID_(ownJID), channelJID_(channelJID), iqRouter_(iqRouter), stanzaChannel_(stanzaChannel) {
stanzaChannel_->onMessageReceived.connect(boost::bind(&MIXImpl::handleIncomingMessage, this, _1));
}

MIXImpl::~MIXImpl() {

}

void MIXImpl::joinChannel(const std::unordered_set<std::string>& nodes) {
joinChannelWithPreferences(nodes, nullptr);
}

void MIXImpl::joinChannelWithPreferences(const std::unordered_set<std::string>& nodes, Form::ref form) {
void MIXImpl::joinChannel(const std::unordered_set<std::string>& nodes, Form::ref form, MIXInvitation::ref invitation) {
auto joinPayload = std::make_shared<MIXJoin>();
joinPayload->setChannel(channelJID_);
for (auto node : nodes) {
Expand All @@ -34,11 +30,26 @@ void MIXImpl::joinChannelWithPreferences(const std::unordered_set<std::string>&
if (form) {
joinPayload->setForm(form);
}
if (invitation) {
joinPayload->setInvitation(invitation);
}
auto request = std::make_shared<GenericRequest<MIXJoin>>(IQ::Set, getJID(), joinPayload, iqRouter_);
request->onResponse.connect(boost::bind(&MIXImpl::handleJoinResponse, this, _1, _2));
request->send();
}

void MIXImpl::joinChannelWithSubscriptions(const std::unordered_set<std::string>& nodes) {
joinChannel(nodes, nullptr, nullptr);
}

void MIXImpl::joinChannelWithPreferences(const std::unordered_set<std::string>& nodes, Form::ref form) {
joinChannel(nodes, form, nullptr);
}

void MIXImpl::joinChannelWithInvite(const std::unordered_set<std::string>& nodes, MIXInvitation::ref invitation) {
joinChannel(nodes, nullptr, invitation);
}

void MIXImpl::handleJoinResponse(MIXJoin::ref payload, ErrorPayload::ref error) {
if (error) {
onJoinFailed(error);
Expand Down Expand Up @@ -112,4 +123,34 @@ void MIXImpl::updatePreferences(Form::ref form) {
request->send();
}

void MIXImpl::handleIncomingMessage(Message::ref message) {
onMessageReceived(message);
}

void MIXImpl::requestInvitation(const JID& invitee) {
auto invitePayload = std::make_shared<MIXInvite>();
invitePayload->setInvitee(invitee);
auto request = std::make_shared<GenericRequest<MIXInvite>>(IQ::Get, channelJID_, invitePayload, iqRouter_);
request->onResponse.connect(boost::bind(&MIXImpl::handleInvitationReceived, this, _1, _2));
request->send();
}

void MIXImpl::handleInvitationReceived(MIXInvite::ref invite, ErrorPayload::ref error) {
if (error) {
onInvitationRequestFailed(error);
} else {
if (invite->getInvitation()) {
onInvitationReceived(*invite->getInvitation());
}
}
}

void MIXImpl::sendInvitation(MIXInvitation::ref invitation, std::string invitationMessage) {
auto message = std::make_shared<Message>();
message->setTo(invitation->getInvitee());
message->setBody(invitationMessage);
message->addPayload(invitation);
stanzaChannel_->sendMessage(message);
}

}
15 changes: 13 additions & 2 deletions Swiften/MIX/MIXImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace Swift {
using ref = std::shared_ptr<MIXImpl>;

public:
MIXImpl(const JID& ownJID, const JID& channelJID, IQRouter* iqRouter);
MIXImpl(const JID& ownJID, const JID& channelJID, IQRouter* iqRouter, StanzaChannel* stanzaChannel);
virtual ~MIXImpl();

/**
Expand All @@ -34,10 +34,14 @@ namespace Swift {
return channelJID_;
}

virtual void joinChannel(const std::unordered_set<std::string>& nodes) override;
virtual void joinChannel(const std::unordered_set<std::string>& nodes, Form::ref form, MIXInvitation::ref invitation) override;

virtual void joinChannelWithSubscriptions(const std::unordered_set<std::string>& nodes) override;

virtual void joinChannelWithPreferences(const std::unordered_set<std::string>& nodes, Form::ref form) override;

virtual void joinChannelWithInvite(const std::unordered_set<std::string>& nodes, MIXInvitation::ref invitation) override;

virtual void updateSubscription(const std::unordered_set<std::string>& nodes) override;

virtual void leaveChannel() override;
Expand All @@ -46,16 +50,23 @@ namespace Swift {

virtual void updatePreferences(Form::ref form) override;

virtual void requestInvitation(const JID& invitee) override;

virtual void sendInvitation(MIXInvitation::ref invitation, std::string invitationMessage) override;

private:
void handleJoinResponse(MIXJoin::ref, ErrorPayload::ref);
void handleLeaveResponse(MIXLeave::ref, ErrorPayload::ref);
void handleUpdateSubscriptionResponse(MIXUpdateSubscription::ref, ErrorPayload::ref);
void handlePreferencesFormReceived(MIXUserPreference::ref, ErrorPayload::ref);
void handlePreferencesResultReceived(MIXUserPreference::ref /*payload*/, ErrorPayload::ref error);
void handleInvitationReceived(MIXInvite::ref invite, ErrorPayload::ref error);
void handleIncomingMessage(Message::ref message);

private:
JID ownJID_;
JID channelJID_;
IQRouter* iqRouter_;
StanzaChannel* stanzaChannel_;
};
}
39 changes: 34 additions & 5 deletions Swiften/MIX/UnitTest/MIXImplTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,12 @@ class MIXImplTest : public ::testing::Test {
}

MIX::ref createMIXClient() {
auto mix = std::make_shared<MIXImpl>(ownJID_, channelJID_, router_);
auto mix = std::make_shared<MIXImpl>(ownJID_, channelJID_, router_, channel_);
mix->onJoinComplete.connect(boost::bind(&MIXImplTest::handleJoinComplete, this, _1));
mix->onLeaveComplete.connect(boost::bind(&MIXImplTest::handleLeaveComplete, this, _1));
mix->onSubscriptionUpdated.connect(boost::bind(&MIXImplTest::handleSubscriptionUpdated, this, _1));
mix->onPreferencesFormReceived.connect(boost::bind(&MIXImplTest::handlePreferenceForm, this, _1));
mix->onInvitationReceived.connect(boost::bind(&MIXImplTest::handleInvitation, this, _1));
return mix;
}

Expand All @@ -51,6 +52,10 @@ class MIXImplTest : public ::testing::Test {
subscribedNodes_ = joinPayload->getSubscriptions();
}

void handleInvitation(MIXInvitation::ref invitation) {
invitation_ = invitation;
}

void handleLeaveComplete(MIXLeave::ref leavePayload) {
ASSERT_TRUE(leavePayload);
ASSERT_EQ(static_cast<int>(0), subscribedNodes_.size());
Expand Down Expand Up @@ -98,12 +103,13 @@ class MIXImplTest : public ::testing::Test {
IQRouter* router_;
int successfulJoins_;
Form::ref preferenceForm_;
MIXInvitation::ref invitation_;
std::unordered_set<std::string> subscribedNodes_;
};

TEST_F(MIXImplTest, testJoinError) {
MIX::ref testling = createMIXClient();
testling->joinChannel(std::unordered_set<std::string>());
testling->joinChannelWithSubscriptions(std::unordered_set<std::string>());

ASSERT_EQ(1, static_cast<int>(channel_->sentStanzas.size()));
ASSERT_TRUE(channel_->isRequestAtIndex<MIXJoin>(0, ownJID_.toBare(), IQ::Set));
Expand All @@ -127,7 +133,7 @@ TEST_F(MIXImplTest, testJoinWithAllSubscriptions) {
nodes.insert(std::string("urn:xmpp:mix:nodes:participants"));
nodes.insert(std::string("urn:xmpp:mix:nodes:config"));

testling->joinChannel(nodes);
testling->joinChannelWithSubscriptions(nodes);

ASSERT_EQ(1, static_cast<int>(channel_->sentStanzas.size()));
ASSERT_TRUE(channel_->isRequestAtIndex<MIXJoin>(0, ownJID_.toBare(), IQ::Set));
Expand All @@ -143,6 +149,29 @@ TEST_F(MIXImplTest, testJoinWithAllSubscriptions) {
ASSERT_EQ(static_cast<int>(4), subscribedNodes_.size());
}

TEST_F(MIXImplTest, testInvite) {
MIX::ref testling = createMIXClient();
testling->requestInvitation(JID("cat@shakespeare.lit"));

ASSERT_EQ(1, static_cast<int>(channel_->sentStanzas.size()));
ASSERT_TRUE(channel_->isRequestAtIndex<MIXInvite>(0, channelJID_, IQ::Get));

//fake response
auto invite = std::make_shared<MIXInvite>();

auto invitation = std::make_shared<MIXInvitation>();
invitation->setInviter(JID("hag66@shakespeare.lit"));
invitation->setInvitee(JID("cat@shakespeare.lit"));
invitation->setChannel(JID("coven@mix.shakespeare.lit"));
invitation->setToken(std::string("ABCDEF"));

invite->setInvitation(invitation);

channel_->onIQReceived(IQ::createResult(ownJID_, channel_->sentStanzas[0]->getTo(), channel_->sentStanzas[0]->getID(), invite));
ASSERT_TRUE(invitation_);
ASSERT_EQ(invitation_->getInvitee(), JID("cat@shakespeare.lit"));
}

TEST_F(MIXImplTest, testJoinWithSomeSubscriptions) {
MIX::ref testling = createMIXClient();
std::unordered_set<std::string> nodes;
Expand All @@ -151,7 +180,7 @@ TEST_F(MIXImplTest, testJoinWithSomeSubscriptions) {
nodes.insert(std::string("urn:xmpp:mix:nodes:participants"));
nodes.insert(std::string("urn:xmpp:mix:nodes:config"));

testling->joinChannel(nodes);
testling->joinChannelWithSubscriptions(nodes);

ASSERT_EQ(1, static_cast<int>(channel_->sentStanzas.size()));
ASSERT_TRUE(channel_->isRequestAtIndex<MIXJoin>(0, ownJID_.toBare(), IQ::Set));
Expand Down Expand Up @@ -191,7 +220,7 @@ TEST_F(MIXImplTest, testUpdateSubscription) {
nodes.insert(std::string("urn:xmpp:mix:nodes:messages"));
nodes.insert(std::string("urn:xmpp:mix:nodes:presence"));

testling->joinChannel(nodes);
testling->joinChannelWithSubscriptions(nodes);

ASSERT_EQ(1, static_cast<int>(channel_->sentStanzas.size()));
ASSERT_TRUE(channel_->isRequestAtIndex<MIXJoin>(0, ownJID_.toBare(), IQ::Set));
Expand Down
7 changes: 7 additions & 0 deletions Swiften/Parser/PayloadParsers/MIXJoinParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include <Swiften/Parser/PayloadParserFactory.h>
#include <Swiften/Parser/PayloadParsers/FormParser.h>
#include <Swiften/Parser/PayloadParsers/MIXInvitationParser.h>

using namespace Swift;

Expand Down Expand Up @@ -42,6 +43,9 @@ void MIXJoinParser::handleStartElement(const std::string& element, const std::st
if (element == "x" && ns == "jabber:x:data") {
currentPayloadParser_ = std::make_shared<FormParser>();
}
if (element == "invitation" && ns == "urn:xmpp:mix:0") {
currentPayloadParser_ = std::make_shared<MIXInvitationParser>();
}
}

if (level_ >= 1 && currentPayloadParser_) {
Expand All @@ -61,6 +65,9 @@ void MIXJoinParser::handleEndElement(const std::string& element, const std::stri
if (element == "x" && ns == "jabber:x:data") {
getPayloadInternal()->setForm(std::dynamic_pointer_cast<Form>(currentPayloadParser_->getPayload()));
}
if (element == "invitation" && ns == "urn:xmpp:mix:0") {
getPayloadInternal()->setInvitation(std::dynamic_pointer_cast<MIXInvitation>(currentPayloadParser_->getPayload()));
}
currentPayloadParser_.reset();
}
}
Expand Down
Loading