summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swift/Controllers')
-rw-r--r--Swift/Controllers/Chat/ChatController.cpp1
-rw-r--r--Swift/Controllers/Chat/ChatController.h2
-rw-r--r--Swift/Controllers/Chat/ChatControllerBase.cpp22
-rw-r--r--Swift/Controllers/Chat/ChatControllerBase.h5
-rw-r--r--Swift/Controllers/Chat/UnitTest/ChatControllerTest.cpp162
-rw-r--r--Swift/Controllers/SConscript1
-rw-r--r--Swift/Controllers/UIInterfaces/ChatWindow.h1
7 files changed, 192 insertions, 2 deletions
diff --git a/Swift/Controllers/Chat/ChatController.cpp b/Swift/Controllers/Chat/ChatController.cpp
index e299d03..5f441f8 100644
--- a/Swift/Controllers/Chat/ChatController.cpp
+++ b/Swift/Controllers/Chat/ChatController.cpp
@@ -359,6 +359,7 @@ void ChatController::setOnline(bool online) {
if (!online) {
for (auto& stanzaIdPair : unackedStanzas_) {
chatWindow_->setAckState(stanzaIdPair.second, ChatWindow::Failed);
+ failedStanzas_[stanzaIdPair.second] = stanzaIdPair.first;
}
unackedStanzas_.clear();
diff --git a/Swift/Controllers/Chat/ChatController.h b/Swift/Controllers/Chat/ChatController.h
index 716b3ed..447e263 100644
--- a/Swift/Controllers/Chat/ChatController.h
+++ b/Swift/Controllers/Chat/ChatController.h
@@ -96,8 +96,6 @@ namespace Swift {
std::string myLastMessageUIID_;
bool isInMUC_;
std::string lastStatusChangeString_;
- std::map<std::shared_ptr<Stanza>, std::string> unackedStanzas_;
- std::map<std::string, std::string> requestedReceipts_;
StatusShow::Type lastShownStatus_;
Tristate contactSupportsReceipts_;
diff --git a/Swift/Controllers/Chat/ChatControllerBase.cpp b/Swift/Controllers/Chat/ChatControllerBase.cpp
index 0e86d6c..4d4ca86 100644
--- a/Swift/Controllers/Chat/ChatControllerBase.cpp
+++ b/Swift/Controllers/Chat/ChatControllerBase.cpp
@@ -20,6 +20,8 @@
#include <Swiften/Client/StanzaChannel.h>
#include <Swiften/Disco/EntityCapsProvider.h>
#include <Swiften/Elements/Delay.h>
+#include <Swiften/Elements/DeliveryReceipt.h>
+#include <Swiften/Elements/DeliveryReceiptRequest.h>
#include <Swiften/Elements/MUCInvitationPayload.h>
#include <Swiften/Elements/MUCUserPayload.h>
#include <Swiften/Queries/Requests/GetSecurityLabelsCatalogRequest.h>
@@ -44,6 +46,7 @@ ChatControllerBase::ChatControllerBase(const JID& self, StanzaChannel* stanzaCha
chatWindow_->onAllMessagesRead.connect(boost::bind(&ChatControllerBase::handleAllMessagesRead, this));
chatWindow_->onSendMessageRequest.connect(boost::bind(&ChatControllerBase::handleSendMessageRequest, this, _1, _2));
chatWindow_->onContinuationsBroken.connect(boost::bind(&ChatControllerBase::handleContinuationsBroken, this));
+ scopedConnectionResendMessage_ = chatWindow_->onResendMessageRequest.connect(boost::bind(&ChatControllerBase::handleResendMessageRequest, this, _1));
entityCapsProvider_->onCapsChanged.connect(boost::bind(&ChatControllerBase::handleCapsChanged, this, _1));
highlighter_ = highlightManager->createHighlighter(nickResolver);
ChatControllerBase::setOnline(stanzaChannel->isAvailable() && iqRouter->isAvailable());
@@ -62,6 +65,7 @@ ChatWindow* ChatControllerBase::detachChatWindow() {
chatWindow_->onContinuationsBroken.disconnect(boost::bind(&ChatControllerBase::handleContinuationsBroken, this));
chatWindow_->onSendMessageRequest.disconnect(boost::bind(&ChatControllerBase::handleSendMessageRequest, this, _1, _2));
chatWindow_->onAllMessagesRead.disconnect(boost::bind(&ChatControllerBase::handleAllMessagesRead, this));
+ scopedConnectionResendMessage_.disconnect();
ChatWindow* chatWindow = chatWindow_;
chatWindow_ = nullptr;
return chatWindow;
@@ -397,4 +401,22 @@ void ChatControllerBase::handleMediatedMUCInvitation(Message::ref message) {
handleGeneralMUCInvitation(inviteEvent);
}
+void ChatControllerBase::handleResendMessageRequest(const std::string& id) {
+ if (failedStanzas_.find(id) != failedStanzas_.end()) {
+ if (auto resendMsg = std::dynamic_pointer_cast<Message>(failedStanzas_[id])) {
+ stanzaChannel_->sendMessage(resendMsg);
+ if (stanzaChannel_->getStreamManagementEnabled()) {
+ chatWindow_->setAckState(id, ChatWindow::Pending);
+ unackedStanzas_[failedStanzas_[id]] = id;
+ }
+ if (resendMsg->getPayload<DeliveryReceiptRequest>()) {
+ requestedReceipts_[resendMsg->getID()] = id;
+ chatWindow_->setMessageReceiptState(id, ChatWindow::ReceiptRequested);
+ }
+ lastWasPresence_ = false;
+ failedStanzas_.erase(id);
+ }
+ }
+}
+
}
diff --git a/Swift/Controllers/Chat/ChatControllerBase.h b/Swift/Controllers/Chat/ChatControllerBase.h
index 9da4d88..527196c 100644
--- a/Swift/Controllers/Chat/ChatControllerBase.h
+++ b/Swift/Controllers/Chat/ChatControllerBase.h
@@ -115,6 +115,7 @@ namespace Swift {
* What JID should be used for last message correction (XEP-0308) tracking.
*/
virtual JID messageCorrectionJID(const JID& fromJID) = 0;
+ virtual void handleResendMessageRequest(const std::string& id);
private:
IDGenerator idGenerator_;
@@ -155,6 +156,10 @@ namespace Swift {
std::string roomSecurityMarking_;
std::string previousMessageSecurityMarking_;
SettingsProvider* settings_;
+ boost::signals2::scoped_connection scopedConnectionResendMessage_;
+ std::map<std::string, std::string> requestedReceipts_;
+ std::map<std::shared_ptr<Stanza>, std::string> unackedStanzas_;
+ std::map<std::string, std::shared_ptr<Stanza>> failedStanzas_;
Chattables& chattables_;
};
}
diff --git a/Swift/Controllers/Chat/UnitTest/ChatControllerTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatControllerTest.cpp
new file mode 100644
index 0000000..e010656
--- /dev/null
+++ b/Swift/Controllers/Chat/UnitTest/ChatControllerTest.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <memory>
+#include <string>
+
+#include <gtest/gtest.h>
+#include <hippomocks.h>
+
+#include <Swiften/Avatars/NullAvatarManager.h>
+#include <Swiften/Client/ClientBlockListManager.h>
+#include <Swiften/Client/DummyStanzaChannel.h>
+#include <Swiften/Client/NickResolver.h>
+#include <Swiften/Disco/DummyEntityCapsProvider.h>
+#include <Swiften/Network/DummyTimerFactory.h>
+#include <Swiften/Queries/DummyIQChannel.h>
+#include <Swiften/Roster/XMPPRoster.h>
+#include <Swiften/Roster/XMPPRosterImpl.h>
+#include <Swiften/VCards/VCardManager.h>
+#include <Swiften/VCards/VCardMemoryStorage.h>
+
+#include <Swift/Controllers/Chat/AutoAcceptMUCInviteDecider.h>
+#include <Swift/Controllers/Chat/ChatController.h>
+#include <Swift/Controllers/Chat/ChatMessageParser.h>
+#include <Swift/Controllers/Chat/Chattables.h>
+#include <Swift/Controllers/Settings/DummySettingsProvider.h>
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
+#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h>
+#include <Swift/Controllers/UnitTest/MockChatWindow.h>
+#include <Swift/Controllers/XMPPEvents/EventController.h>
+
+using namespace Swift;
+
+/**
+ * Most of the ChatController tests are in ChatsManagerTest.
+ * New tests related with ChatController should be added here,
+ * and old tests should be migrated when possible.
+ */
+
+class ExtendedChatController : public ChatController {
+public:
+ ExtendedChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency, UIEventStream* eventStream, TimerFactory* timerFactory, EventController* eventController, EntityCapsProvider* entityCapsProvider, bool userWantsReceipts, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, std::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider, SettingsProvider* settings, Chattables& chattables) :
+ ChatController(self, stanzaChannel, iqRouter, chatWindowFactory, contact, nickResolver, presenceOracle, avatarManager, isInMUC, useDelayForLatency, eventStream, timerFactory, eventController, entityCapsProvider, userWantsReceipts, historyController, mucRegistry, highlightManager, clientBlockListManager, chatMessageParser, autoAcceptMUCInviteDecider, settings, chattables) {
+ }
+
+ std::map<std::shared_ptr<Stanza>, std::string> getUnackedStanzas() { return unackedStanzas_; }
+ std::map<std::string, std::shared_ptr<Stanza>> getFailedStanzas() { return failedStanzas_; }
+};
+
+class ChatControllerTest : public ::testing::Test {
+protected:
+ virtual void SetUp() {
+ self_ = JID("alice@wonderland.lit");
+ other_ = JID("whiterabbit@wonderland.lit");
+ stanzaChannel_ = new DummyStanzaChannel();
+ iqChannel_ = new DummyIQChannel();
+ iqRouter_ = new IQRouter(iqChannel_);
+ eventController_ = new EventController();
+ xmppRoster_ = new XMPPRosterImpl();
+ vCardManager_ = new VCardManager(self_, iqRouter_, vCardMemoryStorage_);
+ mucRegistry_ = new MUCRegistry();
+ nickResolver_ = new NickResolver(self_, xmppRoster_, vCardManager_, mucRegistry_);
+ presenceOracle_ = new PresenceOracle(stanzaChannel_, xmppRoster_);
+ avatarManager_ = new NullAvatarManager();
+ uiEventStream_ = new UIEventStream();
+ timerFactory_ = new DummyTimerFactory();
+ entityCapsProvider_ = new DummyEntityCapsProvider();
+ settings_ = new DummySettingsProvider();
+ highlightManager_ = new HighlightManager(settings_);
+ highlightManager_->resetToDefaultConfiguration();
+ clientBlockListManager_ = new ClientBlockListManager(iqRouter_);
+ autoAcceptMUCInviteDecider_ = new AutoAcceptMUCInviteDecider(self_.getDomain(), xmppRoster_, settings_);
+ chatMessageParser_ = std::make_shared<ChatMessageParser>(std::map<std::string, std::string>(), highlightManager_->getConfiguration(), ChatMessageParser::Mode::GroupChat);
+ mocks_ = new MockRepository();
+ window_ = new MockChatWindow();
+ chatWindowFactory_ = mocks_->InterfaceMock<ChatWindowFactory>();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(other_, uiEventStream_).Return(window_);
+ chattables_ = std::make_unique<Chattables>();
+
+ controller_ = new ExtendedChatController(self_, stanzaChannel_, iqRouter_, chatWindowFactory_, other_, nickResolver_, presenceOracle_, avatarManager_, false, false, uiEventStream_, timerFactory_, eventController_, entityCapsProvider_, false, nullptr, mucRegistry_, highlightManager_, clientBlockListManager_, chatMessageParser_, nullptr, settings_, *chattables_);
+ }
+ virtual void TearDown() {
+ delete controller_;
+ chattables_.reset();
+ chatMessageParser_.reset();
+ delete autoAcceptMUCInviteDecider_;
+ delete clientBlockListManager_;
+ delete highlightManager_;
+ delete settings_;
+ delete entityCapsProvider_;
+ delete timerFactory_;
+ delete uiEventStream_;
+ delete avatarManager_;
+ delete presenceOracle_;
+ delete nickResolver_;
+ delete mucRegistry_;
+ delete vCardManager_;
+ delete xmppRoster_;
+ delete eventController_;
+ delete iqRouter_;
+ delete iqChannel_;
+ delete stanzaChannel_;
+ }
+
+ JID self_, other_;
+ AvatarManager* avatarManager_ = nullptr;
+ ExtendedChatController* controller_ = nullptr;
+ ChatWindowFactory* chatWindowFactory_;
+ ClientBlockListManager* clientBlockListManager_;
+ EventController* eventController_ = nullptr;
+ EntityCapsProvider* entityCapsProvider_ = nullptr;
+ IQChannel* iqChannel_ = nullptr;
+ IQRouter* iqRouter_ = nullptr;
+ MockRepository* mocks_;
+ MockChatWindow* window_;
+ MUCRegistry* mucRegistry_ = nullptr;
+ NickResolver* nickResolver_ = nullptr;
+ PresenceOracle* presenceOracle_ = nullptr;
+ DummyStanzaChannel* stanzaChannel_ = nullptr;
+ TimerFactory* timerFactory_;
+ XMPPRosterImpl* xmppRoster_ = nullptr;
+ UIEventStream* uiEventStream_;
+ VCardManager* vCardManager_ = nullptr;
+ VCardMemoryStorage* vCardMemoryStorage_ = nullptr;
+ DummySettingsProvider* settings_;
+ HighlightManager* highlightManager_;
+ std::shared_ptr<ChatMessageParser> chatMessageParser_;
+ AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider_;
+ std::unique_ptr<Chattables> chattables_;
+
+};
+
+TEST_F(ChatControllerTest, testResendMessage) {
+ std::string msgBody("TestMsg");
+ stanzaChannel_->setStreamManagementEnabled(true);
+ window_->onSendMessageRequest(msgBody, false);
+ {
+ auto failedStanzas = controller_->getFailedStanzas();
+ auto unackedStanzas = controller_->getUnackedStanzas();
+ ASSERT_EQ(failedStanzas.size(), 0);
+ ASSERT_EQ(unackedStanzas.size(), 1);
+ }
+ //Disconnecting to fail the stanza
+ controller_->setOnline(false);
+ controller_->setOnline(true);
+ {
+ auto failedStanzas = controller_->getFailedStanzas();
+ auto unackedStanzas = controller_->getUnackedStanzas();
+ ASSERT_EQ(failedStanzas.size(), 1);
+ ASSERT_EQ(unackedStanzas.size(), 0);
+ }
+ window_->onResendMessageRequest("id");
+ {
+ auto failedStanzas = controller_->getFailedStanzas();
+ auto unackedStanzas = controller_->getUnackedStanzas();
+ ASSERT_EQ(failedStanzas.size(), 0);
+ ASSERT_EQ(unackedStanzas.size(), 1);
+ }
+}
diff --git a/Swift/Controllers/SConscript b/Swift/Controllers/SConscript
index 0f50ac9..31b4541 100644
--- a/Swift/Controllers/SConscript
+++ b/Swift/Controllers/SConscript
@@ -97,6 +97,7 @@ if env["SCONS_STAGE"] == "build" :
File("Chat/UnitTest/ChatListWindowChatTest.cpp"),
File("Chat/UnitTest/ChatMessageParserTest.cpp"),
File("Chat/UnitTest/ChatsManagerTest.cpp"),
+ File("Chat/UnitTest/ChatControllerTest.cpp"),
File("Chat/UnitTest/MUCControllerTest.cpp"),
File("Roster/UnitTest/LeastCommonSubsequenceTest.cpp"),
File("Roster/UnitTest/RosterControllerTest.cpp"),
diff --git a/Swift/Controllers/UIInterfaces/ChatWindow.h b/Swift/Controllers/UIInterfaces/ChatWindow.h
index 13cbb7d..507269f 100644
--- a/Swift/Controllers/UIInterfaces/ChatWindow.h
+++ b/Swift/Controllers/UIInterfaces/ChatWindow.h
@@ -254,6 +254,7 @@ namespace Swift {
boost::signals2::signal<void ()> onClosed;
boost::signals2::signal<void ()> onAllMessagesRead;
boost::signals2::signal<void (const std::string&, bool isCorrection)> onSendMessageRequest;
+ boost::signals2::signal<void (const std::string&)> onResendMessageRequest;
boost::signals2::signal<void ()> onSendCorrectionMessageRequest;
boost::signals2::signal<void ()> onUserTyping;
boost::signals2::signal<void ()> onUserCancelsTyping;