summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Markmann <tm@ayena.de>2016-11-22 07:51:50 (GMT)
committerKevin Smith <kevin.smith@isode.com>2016-11-30 10:29:11 (GMT)
commitc65a90e2a73814d09ad8c60adc4a259e90006db7 (patch)
treec6b0f90fba9aa2c64e94e35e99c9b30557d5e4ad /Swift/Controllers/Chat
parent2039930eadd4756068a8a60c8340d9908a7136d3 (diff)
downloadswift-c65a90e2a73814d09ad8c60adc4a259e90006db7.zip
swift-c65a90e2a73814d09ad8c60adc4a259e90006db7.tar.bz2
Show MUC PM item-not-found error in MUC PM window
Previously, if one would send a MUC PM to a user that has left a room the error response from the MUC would be shown in the MUC room. Now the error will show in the MUC PM window, if the MUC PM full JID has a ChatController. Test-Information: Added unit test verifying new behaviour. Manually verified that the error is shown in the MUC PM window instead of the MUC room window. Change-Id: I1b259d5eee9e22217bbe7e5c09294d2166a77895
Diffstat (limited to 'Swift/Controllers/Chat')
-rw-r--r--Swift/Controllers/Chat/ChatControllerBase.cpp8
-rw-r--r--Swift/Controllers/Chat/ChatsManager.cpp14
-rw-r--r--Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp71
3 files changed, 78 insertions, 15 deletions
diff --git a/Swift/Controllers/Chat/ChatControllerBase.cpp b/Swift/Controllers/Chat/ChatControllerBase.cpp
index b339bd0..da9064e 100644
--- a/Swift/Controllers/Chat/ChatControllerBase.cpp
+++ b/Swift/Controllers/Chat/ChatControllerBase.cpp
@@ -243,61 +243,67 @@ std::string ChatControllerBase::addMessage(const ChatWindow::ChatMessage& chatMe
}
void ChatControllerBase::replaceMessage(const ChatWindow::ChatMessage& chatMessage, const std::string& id, const boost::posix_time::ptime& time) {
if (chatMessage.isMeCommand()) {
chatWindow_->replaceWithAction(chatMessage, id, time);
}
else {
chatWindow_->replaceMessage(chatMessage, id, time);
}
}
bool ChatControllerBase::isFromContact(const JID& from) {
return from.toBare() == toJID_.toBare();
}
void ChatControllerBase::handleIncomingMessage(std::shared_ptr<MessageEvent> messageEvent) {
preHandleIncomingMessage(messageEvent);
if (messageEvent->isReadable() && !messageEvent->getConcluded()) {
unreadMessages_.push_back(messageEvent);
if (messageEvent->targetsMe()) {
targetedUnreadMessages_.push_back(messageEvent);
}
}
std::shared_ptr<Message> message = messageEvent->getStanza();
ChatWindow::ChatMessage chatMessage;
boost::optional<std::string> optionalBody = message->getBody();
std::string body = optionalBody.get_value_or("");
if (message->isError()) {
if (!message->getTo().getResource().empty()) {
- std::string errorMessage = str(format(QT_TRANSLATE_NOOP("", "Couldn't send message: %1%")) % getErrorMessage(message->getPayload<ErrorPayload>()));
+ std::string errorMessage;
+ if (message->getPayload<Swift::ErrorPayload>()->getCondition() == ErrorPayload::ItemNotFound) {
+ errorMessage = QT_TRANSLATE_NOOP("", "This user could not be found in the room.");
+ }
+ else {
+ errorMessage = str(format(QT_TRANSLATE_NOOP("", "Couldn't send message: %1%")) % getErrorMessage(message->getPayload<ErrorPayload>()));
+ }
chatWindow_->addErrorMessage(chatMessageParser_->parseMessageBody(errorMessage));
}
}
else if (messageEvent->getStanza()->getPayload<MUCInvitationPayload>()) {
handleMUCInvitation(messageEvent->getStanza());
return;
}
else if (messageEvent->getStanza()->getPayload<MUCUserPayload>() && messageEvent->getStanza()->getPayload<MUCUserPayload>()->getInvite()) {
handleMediatedMUCInvitation(messageEvent->getStanza());
return;
}
else {
if (!messageEvent->isReadable()) {
return;
}
showChatWindow();
JID from = message->getFrom();
std::vector<std::shared_ptr<Delay> > delayPayloads = message->getPayloads<Delay>();
for (size_t i = 0; useDelayForLatency_ && i < delayPayloads.size(); i++) {
if (!delayPayloads[i]->getFrom()) {
continue;
}
boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
std::ostringstream s;
s << "The following message took " << (now - delayPayloads[i]->getStamp()).total_milliseconds() / 1000.0 << " seconds to be delivered from " << delayPayloads[i]->getFrom()->toString() << ".";
chatWindow_->addSystemMessage(chatMessageParser_->parseMessageBody(std::string(s.str())), ChatWindow::DefaultDirection);
}
std::shared_ptr<SecurityLabel> label = message->getPayload<SecurityLabel>();
// Determine the timestamp
diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp
index b9e2cf4..4f95d71 100644
--- a/Swift/Controllers/Chat/ChatsManager.cpp
+++ b/Swift/Controllers/Chat/ChatsManager.cpp
@@ -910,62 +910,72 @@ void ChatsManager::handleIncomingMessage(std::shared_ptr<Message> incomingMessag
(forwardedMessage = std::dynamic_pointer_cast<Message>(forwarded->getStanza()))) {
message = forwardedMessage;
}
else if ((carbonsSent = incomingMessage->getPayload<CarbonsSent>()) &&
(forwarded = carbonsSent->getForwarded()) &&
(forwardedMessage = std::dynamic_pointer_cast<Message>(forwarded->getStanza()))) {
JID toJID = forwardedMessage->getTo();
ChatController* controller = getChatControllerOrCreate(toJID);
if (controller) {
controller->handleIncomingOwnMessage(forwardedMessage);
}
else {
SWIFT_LOG(error) << "Carbons message ignored." << std::endl;
}
return;
}
}
JID fromJID = message->getFrom();
std::shared_ptr<MessageEvent> event(new MessageEvent(message));
bool isInvite = !!message->getPayload<MUCInvitationPayload>();
bool isMediatedInvite = (message->getPayload<MUCUserPayload>() && message->getPayload<MUCUserPayload>()->getInvite());
if (isMediatedInvite) {
fromJID = (*message->getPayload<MUCUserPayload>()->getInvite()).from;
}
if (!event->isReadable() && !message->getPayload<ChatState>() && !message->getPayload<DeliveryReceipt>() && !message->getPayload<DeliveryReceiptRequest>() && !isInvite && !isMediatedInvite && !message->hasSubject()) {
return;
}
- // Try to deliver it to a MUC
- if (message->getType() == Message::Groupchat || message->getType() == Message::Error /*|| (isInvite && message->getType() == Message::Normal)*/) {
+ // Try to deliver MUC errors to a MUC PM window if a suitable window is open.
+ if (message->getType() == Message::Error) {
+ auto controller = getChatControllerIfExists(fromJID, messageCausesSessionBinding(message));
+ if (controller) {
+ controller->handleIncomingMessage(event);
+ return;
+ }
+ }
+
+ // Try to deliver it to a MUC.
+ if (message->getType() == Message::Groupchat || message->getType() == Message::Error) {
+ // Try to deliver it to a MUC room.
std::map<JID, MUCController*>::iterator i = mucControllers_.find(fromJID.toBare());
if (i != mucControllers_.end()) {
i->second->handleIncomingMessage(event);
return;
}
else if (message->getType() == Message::Groupchat) {
//FIXME: Error handling - groupchat messages from an unknown muc.
return;
}
}
// check for impromptu invite to potentially auto-accept
MUCInvitationPayload::ref invite = message->getPayload<MUCInvitationPayload>();
if (invite && autoAcceptMUCInviteDecider_->isAutoAcceptedInvite(message->getFrom(), invite)) {
if (invite->getIsContinuation()) {
// check for existing chat controller for the from JID
ChatController* controller = getChatControllerIfExists(fromJID);
if (controller) {
ChatWindow* window = controller->detachChatWindow();
chatControllers_.erase(fromJID);
delete controller;
handleJoinMUCRequest(invite->getJID(), boost::optional<std::string>(), boost::optional<std::string>(), false, false, true, window);
return;
}
} else {
handleJoinMUCRequest(invite->getJID(), boost::optional<std::string>(), boost::optional<std::string>(), false, false, true);
return;
}
}
diff --git a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
index a5e68cf..cff54f8 100644
--- a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
+++ b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
@@ -54,64 +54,67 @@
#include <Swift/Controllers/UIEvents/RequestChatUIEvent.h>
#include <Swift/Controllers/UIEvents/UIEventStream.h>
#include <Swift/Controllers/UIInterfaces/ChatListWindowFactory.h>
#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h>
#include <Swift/Controllers/UIInterfaces/JoinMUCWindowFactory.h>
#include <Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h>
#include <Swift/Controllers/UIInterfaces/WhiteboardWindowFactory.h>
#include <Swift/Controllers/UnitTest/MockChatWindow.h>
#include <Swift/Controllers/WhiteboardManager.h>
#include <Swift/Controllers/XMPPEvents/EventController.h>
using namespace Swift;
class ChatsManagerTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(ChatsManagerTest);
CPPUNIT_TEST(testFirstOpenWindowIncoming);
CPPUNIT_TEST(testSecondOpenWindowIncoming);
CPPUNIT_TEST(testFirstOpenWindowOutgoing);
CPPUNIT_TEST(testFirstOpenWindowBareToFull);
CPPUNIT_TEST(testSecondWindow);
CPPUNIT_TEST(testUnbindRebind);
CPPUNIT_TEST(testNoDuplicateUnbind);
CPPUNIT_TEST(testThreeMUCWindows);
CPPUNIT_TEST(testChatControllerPresenceAccessUpdatedOnRemoveFromRoster);
CPPUNIT_TEST(testChatControllerPresenceAccessUpdatedOnAddToRoster);
CPPUNIT_TEST(testChatControllerPresenceAccessUpdatedOnSubscriptionChangeToBoth);
CPPUNIT_TEST(testChatControllerPresenceAccessUpdatedOnSubscriptionChangeToFrom);
CPPUNIT_TEST(testChatControllerFullJIDBindingOnMessageAndNotReceipt);
CPPUNIT_TEST(testChatControllerFullJIDBindingOnTypingAndNotActive);
- CPPUNIT_TEST(testChatControllerPMPresenceHandling);
CPPUNIT_TEST(testLocalMUCServiceDiscoveryResetOnDisconnect);
CPPUNIT_TEST(testPresenceChangeDoesNotReplaceMUCInvite);
+ // MUC PM Tests
+ CPPUNIT_TEST(testChatControllerPMPresenceHandling);
+ CPPUNIT_TEST(testChatControllerMucPmUnavailableErrorHandling);
+
// Highlighting tests
CPPUNIT_TEST(testChatControllerHighlightingNotificationTesting);
CPPUNIT_TEST(testChatControllerHighlightingNotificationDeduplicateSounds);
CPPUNIT_TEST(testChatControllerMeMessageHandling);
CPPUNIT_TEST(testRestartingMUCComponentCrash);
CPPUNIT_TEST(testChatControllerMeMessageHandlingInMUC);
// Carbons tests
CPPUNIT_TEST(testCarbonsForwardedIncomingMessageToSecondResource);
CPPUNIT_TEST(testCarbonsForwardedOutgoingMessageFromSecondResource);
CPPUNIT_TEST_SUITE_END();
public:
void setUp() {
mocks_ = new MockRepository();
jid_ = JID("test@test.com/resource");
stanzaChannel_ = new DummyStanzaChannel();
iqRouter_ = new IQRouter(stanzaChannel_);
eventController_ = new EventController();
chatWindowFactory_ = mocks_->InterfaceMock<ChatWindowFactory>();
joinMUCWindowFactory_ = mocks_->InterfaceMock<JoinMUCWindowFactory>();
xmppRoster_ = new XMPPRosterImpl();
mucRegistry_ = new MUCRegistry();
nickResolver_ = new NickResolver(jid_.toBare(), xmppRoster_, nullptr, mucRegistry_);
presenceOracle_ = new PresenceOracle(stanzaChannel_, xmppRoster_);
serverDiscoInfo_ = std::make_shared<DiscoInfo>();
presenceSender_ = new StanzaChannelPresenceSender(stanzaChannel_);
directedPresenceSender_ = new DirectedPresenceSender(presenceSender_);
mucManager_ = new MUCManager(stanzaChannel_, iqRouter_, directedPresenceSender_, mucRegistry_);
@@ -163,202 +166,202 @@ public:
delete mucRegistry_;
delete iqRouter_;
delete stanzaChannel_;
delete eventController_;
delete uiEventStream_;
delete mucManager_;
delete xmppRoster_;
delete entityCapsProvider_;
delete chatListWindow_;
delete mocks_;
delete settings_;
}
void testFirstOpenWindowIncoming() {
JID messageJID("testling@test.com/resource1");
MockChatWindow* window = new MockChatWindow();
mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window);
std::shared_ptr<Message> message(new Message());
message->setFrom(messageJID);
std::string body("This is a legible message. >HEH@)oeueu");
message->setBody(body);
manager_->handleIncomingMessage(message);
CPPUNIT_ASSERT_EQUAL(body, MockChatWindow::bodyFromMessage(window->lastAddedMessage_));
}
void testSecondOpenWindowIncoming() {
JID messageJID1("testling@test.com/resource1");
- MockChatWindow* window1 = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
+ MockChatWindow* window1 = new MockChatWindow();
mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID1, uiEventStream_).Return(window1);
std::shared_ptr<Message> message1(new Message());
message1->setFrom(messageJID1);
std::string body1("This is a legible message. >HEH@)oeueu");
message1->setBody(body1);
manager_->handleIncomingMessage(message1);
CPPUNIT_ASSERT_EQUAL(body1, MockChatWindow::bodyFromMessage(window1->lastAddedMessage_));
JID messageJID2("testling@test.com/resource2");
std::shared_ptr<Message> message2(new Message());
message2->setFrom(messageJID2);
std::string body2("This is a legible message. .cmaulm.chul");
message2->setBody(body2);
manager_->handleIncomingMessage(message2);
CPPUNIT_ASSERT_EQUAL(body2, MockChatWindow::bodyFromMessage(window1->lastAddedMessage_));
}
void testFirstOpenWindowOutgoing() {
std::string messageJIDString("testling@test.com");
- ChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
+ ChatWindow* window = new MockChatWindow();
mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString), uiEventStream_).Return(window);
uiEventStream_->send(std::make_shared<RequestChatUIEvent>(JID(messageJIDString)));
}
void testFirstOpenWindowBareToFull() {
std::string bareJIDString("testling@test.com");
std::string fullJIDString("testling@test.com/resource1");
- MockChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
+ MockChatWindow* window = new MockChatWindow();
mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(bareJIDString), uiEventStream_).Return(window);
uiEventStream_->send(std::make_shared<RequestChatUIEvent>(JID(bareJIDString)));
std::shared_ptr<Message> message(new Message());
message->setFrom(JID(fullJIDString));
std::string body("This is a legible message. mjuga3089gm8G(*>M)@*(");
message->setBody(body);
manager_->handleIncomingMessage(message);
CPPUNIT_ASSERT_EQUAL(body, MockChatWindow::bodyFromMessage(window->lastAddedMessage_));
}
void testSecondWindow() {
std::string messageJIDString1("testling1@test.com");
- ChatWindow* window1 = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
+ ChatWindow* window1 = new MockChatWindow();
mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString1), uiEventStream_).Return(window1);
uiEventStream_->send(std::make_shared<RequestChatUIEvent>(JID(messageJIDString1)));
std::string messageJIDString2("testling2@test.com");
- ChatWindow* window2 = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
+ ChatWindow* window2 = new MockChatWindow();
mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString2), uiEventStream_).Return(window2);
uiEventStream_->send(std::make_shared<RequestChatUIEvent>(JID(messageJIDString2)));
}
/** Complete cycle.
Create unbound window.
Bind it.
Unbind it.
Rebind it.
*/
void testUnbindRebind() {
std::string bareJIDString("testling@test.com");
std::string fullJIDString1("testling@test.com/resource1");
std::string fullJIDString2("testling@test.com/resource2");
- MockChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
+ MockChatWindow* window = new MockChatWindow();
mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(bareJIDString), uiEventStream_).Return(window);
uiEventStream_->send(std::make_shared<RequestChatUIEvent>(JID(bareJIDString)));
std::shared_ptr<Message> message1(new Message());
message1->setFrom(JID(fullJIDString1));
std::string messageBody1("This is a legible message.");
message1->setBody(messageBody1);
manager_->handleIncomingMessage(message1);
CPPUNIT_ASSERT_EQUAL(messageBody1, MockChatWindow::bodyFromMessage(window->lastAddedMessage_));
std::shared_ptr<Presence> jid1Online(new Presence());
jid1Online->setFrom(JID(fullJIDString1));
std::shared_ptr<Presence> jid1Offline(new Presence());
jid1Offline->setFrom(JID(fullJIDString1));
jid1Offline->setType(Presence::Unavailable);
presenceOracle_->onPresenceChange(jid1Offline);
std::shared_ptr<Message> message2(new Message());
message2->setFrom(JID(fullJIDString2));
std::string messageBody2("This is another legible message.");
message2->setBody(messageBody2);
manager_->handleIncomingMessage(message2);
CPPUNIT_ASSERT_EQUAL(messageBody2, MockChatWindow::bodyFromMessage(window->lastAddedMessage_));
}
/**
* Test that MUC PMs get opened in the right windows
*/
void testThreeMUCWindows() {
JID muc("testling@test.com");
ChatWindow* mucWindow = new MockChatWindow();
mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(muc, uiEventStream_).Return(mucWindow);
uiEventStream_->send(std::make_shared<JoinMUCUIEvent>(muc, std::string("nick")));
std::string messageJIDString1("testling@test.com/1");
- ChatWindow* window1 = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
+ ChatWindow* window1 = new MockChatWindow();
mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString1), uiEventStream_).Return(window1);
uiEventStream_->send(std::make_shared<RequestChatUIEvent>(JID(messageJIDString1)));
std::string messageJIDString2("testling@test.com/2");
- ChatWindow* window2 = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
+ ChatWindow* window2 = new MockChatWindow();
mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString2), uiEventStream_).Return(window2);
uiEventStream_->send(std::make_shared<RequestChatUIEvent>(JID(messageJIDString2)));
std::string messageJIDString3("testling@test.com/3");
- ChatWindow* window3 = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
+ ChatWindow* window3 = new MockChatWindow();
mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString3), uiEventStream_).Return(window3);
uiEventStream_->send(std::make_shared<RequestChatUIEvent>(JID(messageJIDString3)));
/* Refetch an earlier window */
/* We do not expect a new window to be created */
uiEventStream_->send(std::make_shared<RequestChatUIEvent>(JID(messageJIDString1)));
}
/**
Test that a second window isn't unbound where there's already an unbound one.
Bind 1
Bind 2
Unbind 1
Unbind 2 (but it doesn't)
Sent to bound 2
Rebind 1
*/
void testNoDuplicateUnbind() {
JID messageJID1("testling@test.com/resource1");
- MockChatWindow* window1 = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
+ MockChatWindow* window1 = new MockChatWindow();
mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID1, uiEventStream_).Return(window1);
std::shared_ptr<Message> message1(new Message());
message1->setFrom(messageJID1);
message1->setBody("This is a legible message1.");
manager_->handleIncomingMessage(message1);
JID messageJID2("testling@test.com/resource2");
std::shared_ptr<Message> message2(new Message());
message2->setFrom(messageJID2);
message2->setBody("This is a legible message2.");
manager_->handleIncomingMessage(message2);
std::shared_ptr<Presence> jid1Online(new Presence());
jid1Online->setFrom(JID(messageJID1));
std::shared_ptr<Presence> jid1Offline(new Presence());
jid1Offline->setFrom(JID(messageJID1));
jid1Offline->setType(Presence::Unavailable);
presenceOracle_->onPresenceChange(jid1Offline);
std::shared_ptr<Presence> jid2Online(new Presence());
jid2Online->setFrom(JID(messageJID2));
std::shared_ptr<Presence> jid2Offline(new Presence());
jid2Offline->setFrom(JID(messageJID2));
jid2Offline->setType(Presence::Unavailable);
presenceOracle_->onPresenceChange(jid2Offline);
JID messageJID3("testling@test.com/resource3");
@@ -380,61 +383,61 @@ public:
/**
* Test that ChatController doesn't send receipts anymore after removal of the contact from the roster.
*/
void testChatControllerPresenceAccessUpdatedOnRemoveFromRoster() {
JID messageJID("testling@test.com/resource1");
xmppRoster_->addContact(messageJID, "foo", std::vector<std::string>(), RosterItemPayload::Both);
MockChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window);
settings_->storeSetting(SettingConstants::REQUEST_DELIVERYRECEIPTS, true);
std::shared_ptr<Message> message = makeDeliveryReceiptTestMessage(messageJID, "1");
manager_->handleIncomingMessage(message);
Stanza::ref stanzaContactOnRoster = stanzaChannel_->getStanzaAtIndex<Stanza>(1);
CPPUNIT_ASSERT_EQUAL(st(1), stanzaChannel_->countSentStanzaOfType<Message>());
CPPUNIT_ASSERT(stanzaContactOnRoster->getPayload<DeliveryReceipt>() != nullptr);
xmppRoster_->removeContact(messageJID);
message->setID("2");
manager_->handleIncomingMessage(message);
CPPUNIT_ASSERT_EQUAL(st(1), stanzaChannel_->countSentStanzaOfType<Message>());
}
/**
* Test that ChatController sends receipts after the contact has been added to the roster.
*/
void testChatControllerPresenceAccessUpdatedOnAddToRoster() {
JID messageJID("testling@test.com/resource1");
- MockChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
+ MockChatWindow* window = new MockChatWindow();
mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window);
settings_->storeSetting(SettingConstants::REQUEST_DELIVERYRECEIPTS, true);
std::shared_ptr<Message> message = makeDeliveryReceiptTestMessage(messageJID, "1");
manager_->handleIncomingMessage(message);
CPPUNIT_ASSERT_EQUAL(st(0), stanzaChannel_->countSentStanzaOfType<Message>());
xmppRoster_->addContact(messageJID, "foo", std::vector<std::string>(), RosterItemPayload::Both);
message->setID("2");
manager_->handleIncomingMessage(message);
CPPUNIT_ASSERT_EQUAL(st(1), stanzaChannel_->countSentStanzaOfType<Message>());
Stanza::ref stanzaContactOnRoster = stanzaChannel_->getStanzaAtIndex<Stanza>(1);
CPPUNIT_ASSERT(stanzaContactOnRoster->getPayload<DeliveryReceipt>() != nullptr);
}
/**
* Test that ChatController sends receipts if requested after change from subscription state To to subscription state Both.
*/
void testChatControllerPresenceAccessUpdatedOnSubscriptionChangeToBoth() {
testhelperChatControllerPresenceAccessUpdatedOnSubscriptionChangeReceiptsAllowed(RosterItemPayload::To, RosterItemPayload::Both);
}
/**
* Test that ChatController sends receipts if requested after change from subscription state To to subscription state From.
*/
void testChatControllerPresenceAccessUpdatedOnSubscriptionChangeToFrom() {
testhelperChatControllerPresenceAccessUpdatedOnSubscriptionChangeReceiptsAllowed(RosterItemPayload::To, RosterItemPayload::From);
}
@@ -661,60 +664,104 @@ public:
void testChatControllerPMPresenceHandling() {
JID participantA = JID("test@rooms.test.com/participantA");
JID participantB = JID("test@rooms.test.com/participantB");
mucRegistry_->addMUC("test@rooms.test.com");
MockChatWindow* window = new MockChatWindow();
mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(participantA, uiEventStream_).Return(window);
uiEventStream_->send(std::make_shared<RequestChatUIEvent>(JID(participantA)));
Presence::ref presence = Presence::create();
presence->setFrom(participantA);
presence->setShow(StatusShow::Online);
stanzaChannel_->onPresenceReceived(presence);
CPPUNIT_ASSERT_EQUAL(std::string("participantA has become available."), MockChatWindow::bodyFromMessage(window->lastAddedPresence_));
presence = Presence::create();
presence->setFrom(participantB);
presence->setShow(StatusShow::Away);
stanzaChannel_->onPresenceReceived(presence);
presence = Presence::create();
presence->setFrom(participantA);
presence->setShow(StatusShow::None);
presence->setType(Presence::Unavailable);
stanzaChannel_->onPresenceReceived(presence);
CPPUNIT_ASSERT_EQUAL(std::string("participantA has gone offline."), MockChatWindow::bodyFromMessage(window->lastReplacedMessage_));
}
+ void testChatControllerMucPmUnavailableErrorHandling() {
+ auto mucJID = JID("test@rooms.test.com");
+ auto participantA = mucJID.withResource("participantA");
+ auto participantB = mucJID.withResource("participantB");
+
+ auto mucWindow = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(mucJID, uiEventStream_).Return(mucWindow);
+ uiEventStream_->send(std::make_shared<JoinMUCUIEvent>(mucJID, participantB.getResource()));
+ CPPUNIT_ASSERT_EQUAL(true, mucWindow->mucType_.is_initialized());
+
+ auto window = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(participantA, uiEventStream_).Return(window);
+ uiEventStream_->send(std::make_shared<RequestChatUIEvent>(participantA));
+ CPPUNIT_ASSERT_EQUAL(false, window->mucType_.is_initialized());
+
+ Presence::ref presence = Presence::create();
+ presence->setFrom(participantA);
+ presence->setShow(StatusShow::Online);
+ stanzaChannel_->onPresenceReceived(presence);
+ CPPUNIT_ASSERT_EQUAL(std::string("participantA has become available."), MockChatWindow::bodyFromMessage(window->lastAddedPresence_));
+
+ // send message to participantA
+ auto messageBody = std::string("message body to send");
+ window->onSendMessageRequest(messageBody, false);
+ auto sendMessageStanza = stanzaChannel_->getStanzaAtIndex<Message>(2);
+ CPPUNIT_ASSERT_EQUAL(messageBody, *sendMessageStanza->getBody());
+
+ // receive reply with error
+ auto messageErrorReply = std::make_shared<Message>();
+ messageErrorReply->setID(stanzaChannel_->getNewIQID());
+ messageErrorReply->setType(Message::Error);
+ messageErrorReply->setFrom(participantA);
+ messageErrorReply->setTo(jid_);
+ messageErrorReply->addPayload(std::make_shared<ErrorPayload>(ErrorPayload::ItemNotFound, ErrorPayload::Cancel, "Recipient not in room"));
+
+ auto lastMUCWindowErrorMessageBeforeError = MockChatWindow::bodyFromMessage(mucWindow->lastAddedErrorMessage_);
+ manager_->handleIncomingMessage(messageErrorReply);
+
+ // assert that error is not routed to MUC window
+ CPPUNIT_ASSERT_EQUAL(lastMUCWindowErrorMessageBeforeError, MockChatWindow::bodyFromMessage(mucWindow->lastAddedErrorMessage_));
+ // assert that error is routed to PM
+ CPPUNIT_ASSERT_EQUAL(std::string("This user could not be found in the room."), MockChatWindow::bodyFromMessage(window->lastAddedErrorMessage_));
+ }
+
void testLocalMUCServiceDiscoveryResetOnDisconnect() {
JID ownJID("test@test.com/resource");
JID sender("foo@test.com");
manager_->setOnline(true);
// Open chat window to a sender.
MockChatWindow* window = new MockChatWindow();
mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(sender, uiEventStream_).Return(window);
uiEventStream_->send(std::make_shared<RequestChatUIEvent>(sender));
CPPUNIT_ASSERT_EQUAL(false, window->impromptuMUCSupported_);
std::shared_ptr<IQ> infoRequest = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[1]);
std::shared_ptr<IQ> infoResponse = IQ::createResult(infoRequest->getFrom(), infoRequest->getTo(), infoRequest->getID());
DiscoInfo info;
info.addIdentity(DiscoInfo::Identity("Shakespearean Chat Service", "conference", "text"));
info.addFeature("http://jabber.org/protocol/muc");
infoResponse->addPayload(std::make_shared<DiscoInfo>(info));
stanzaChannel_->onIQReceived(infoResponse);
CPPUNIT_ASSERT_EQUAL(true, window->impromptuMUCSupported_);
manager_->setOnline(false);
CPPUNIT_ASSERT_EQUAL(false, window->impromptuMUCSupported_);
}
void testhelperChatControllerPresenceAccessUpdatedOnSubscriptionChangeReceiptsAllowed(RosterItemPayload::Subscription from, RosterItemPayload::Subscription to) {
JID messageJID("testling@test.com/resource1");