diff options
-rw-r--r-- | Swift/Controllers/Chat/ChatController.cpp | 6 | ||||
-rw-r--r-- | Swift/Controllers/Chat/ChatController.h | 5 | ||||
-rw-r--r-- | Swift/Controllers/Chat/ChatControllerBase.cpp | 30 | ||||
-rw-r--r-- | Swift/Controllers/Chat/ChatControllerBase.h | 8 | ||||
-rw-r--r-- | Swift/Controllers/Chat/ChatsManager.cpp | 6 | ||||
-rw-r--r-- | Swift/Controllers/Chat/MUCController.cpp | 19 | ||||
-rw-r--r-- | Swift/Controllers/Chat/MUCController.h | 5 | ||||
-rw-r--r-- | Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp | 325 | ||||
-rw-r--r-- | Swift/Controllers/SettingConstants.cpp | 3 | ||||
-rw-r--r-- | Swift/Controllers/SettingConstants.h | 13 | ||||
-rw-r--r-- | Swift/Controllers/UnitTest/MockChatWindow.h | 4 | ||||
-rw-r--r-- | Swift/QtUI/QtChatWindow.cpp | 2 | ||||
-rw-r--r-- | Swift/QtUI/QtHistoryWindow.cpp | 2 | ||||
-rw-r--r-- | Swift/QtUI/QtWebKitChatView.cpp | 21 | ||||
-rw-r--r-- | Swift/QtUI/QtWebKitChatView.h | 7 | ||||
-rw-r--r-- | Swiften/Elements/SecurityLabel.h | 1 |
16 files changed, 365 insertions, 92 deletions
diff --git a/Swift/Controllers/Chat/ChatController.cpp b/Swift/Controllers/Chat/ChatController.cpp index fe8e870..7fb9c59 100644 --- a/Swift/Controllers/Chat/ChatController.cpp +++ b/Swift/Controllers/Chat/ChatController.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2017 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -52,8 +52,8 @@ namespace Swift { /** * The controller does not gain ownership of the stanzaChannel, nor the factory. */ -ChatController::ChatController(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, SettingsProvider* settings, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, std::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider) - : ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, contact, nickResolver, presenceOracle, avatarManager, useDelayForLatency, eventStream, eventController, entityCapsProvider, historyController, mucRegistry, highlightManager, chatMessageParser, autoAcceptMUCInviteDecider), userWantsReceipts_(userWantsReceipts), settings_(settings), clientBlockListManager_(clientBlockListManager) { +ChatController::ChatController(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) + : ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, contact, nickResolver, presenceOracle, avatarManager, useDelayForLatency, eventStream, eventController, entityCapsProvider, historyController, mucRegistry, highlightManager, chatMessageParser, autoAcceptMUCInviteDecider, settings), userWantsReceipts_(userWantsReceipts), clientBlockListManager_(clientBlockListManager) { isInMUC_ = isInMUC; lastWasPresence_ = false; chatStateNotifier_ = new ChatStateNotifier(stanzaChannel, contact, entityCapsProvider, timerFactory, 20000); diff --git a/Swift/Controllers/Chat/ChatController.h b/Swift/Controllers/Chat/ChatController.h index d290d05..c65eb9c 100644 --- a/Swift/Controllers/Chat/ChatController.h +++ b/Swift/Controllers/Chat/ChatController.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2017 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -30,7 +30,7 @@ namespace Swift { class ChatController : public ChatControllerBase { public: - ChatController(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, SettingsProvider* settings, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, std::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider); + ChatController(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); virtual ~ChatController() override; virtual void setToJID(const JID& jid) override; virtual void setAvailableServerFeatures(std::shared_ptr<DiscoInfo> info) override; @@ -104,7 +104,6 @@ namespace Swift { bool receivingPresenceFromUs_ = false; bool userWantsReceipts_; std::map<std::string, FileTransferController*> ftControllers; - SettingsProvider* settings_; std::string lastWbID_; std::string lastHandledMessageID_; diff --git a/Swift/Controllers/Chat/ChatControllerBase.cpp b/Swift/Controllers/Chat/ChatControllerBase.cpp index 0fc735a..2ef91fa 100644 --- a/Swift/Controllers/Chat/ChatControllerBase.cpp +++ b/Swift/Controllers/Chat/ChatControllerBase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2017 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -38,7 +38,7 @@ namespace Swift { -ChatControllerBase::ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, EntityCapsProvider* entityCapsProvider, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, std::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider) : selfJID_(self), stanzaChannel_(stanzaChannel), iqRouter_(iqRouter), chatWindowFactory_(chatWindowFactory), toJID_(toJID), labelsEnabled_(false), presenceOracle_(presenceOracle), avatarManager_(avatarManager), useDelayForLatency_(useDelayForLatency), eventController_(eventController), entityCapsProvider_(entityCapsProvider), historyController_(historyController), mucRegistry_(mucRegistry), chatMessageParser_(chatMessageParser), autoAcceptMUCInviteDecider_(autoAcceptMUCInviteDecider), eventStream_(eventStream) { +ChatControllerBase::ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, EntityCapsProvider* entityCapsProvider, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, std::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider, SettingsProvider* settings) : selfJID_(self), stanzaChannel_(stanzaChannel), iqRouter_(iqRouter), chatWindowFactory_(chatWindowFactory), toJID_(toJID), labelsEnabled_(false), presenceOracle_(presenceOracle), avatarManager_(avatarManager), useDelayForLatency_(useDelayForLatency), eventController_(eventController), entityCapsProvider_(entityCapsProvider), historyController_(historyController), mucRegistry_(mucRegistry), chatMessageParser_(chatMessageParser), autoAcceptMUCInviteDecider_(autoAcceptMUCInviteDecider), eventStream_(eventStream), roomSecurityMarking_(""), previousMessageSecurityMarking_(""), settings_(settings) { chatWindow_ = chatWindowFactory_->createChatWindow(toJID, eventStream); chatWindow_->onAllMessagesRead.connect(boost::bind(&ChatControllerBase::handleAllMessagesRead, this)); chatWindow_->onSendMessageRequest.connect(boost::bind(&ChatControllerBase::handleSendMessageRequest, this, _1, _2)); @@ -190,11 +190,33 @@ void ChatControllerBase::updateMessageCount() { } std::string ChatControllerBase::addMessage(const ChatWindow::ChatMessage& chatMessage, const std::string& senderName, bool senderIsSelf, const std::shared_ptr<SecurityLabel> label, const boost::filesystem::path& avatarPath, const boost::posix_time::ptime& time) { + auto displayedLabel = label; + + if (settings_->getSetting(SettingConstants::MUC_MARKING_ELISION)) { + if (roomSecurityMarking_ != "") { + + if (label && label->getDisplayMarking() == roomSecurityMarking_) { + if (label->getDisplayMarking() == previousMessageSecurityMarking_) { + displayedLabel = std::make_shared<SecurityLabel>(); + } + previousMessageSecurityMarking_ = label->getDisplayMarking(); + } + else if (!label || label->getDisplayMarking().empty()) { + displayedLabel = std::make_shared<SecurityLabel>(); + displayedLabel->setDisplayMarking("Unmarked"); + previousMessageSecurityMarking_ = "Unmarked"; + } + else { + previousMessageSecurityMarking_ = displayedLabel->getDisplayMarking(); + } + } + } + if (chatMessage.isMeCommand()) { - return chatWindow_->addAction(chatMessage, senderName, senderIsSelf, label, pathToString(avatarPath), time); + return chatWindow_->addAction(chatMessage, senderName, senderIsSelf, displayedLabel, pathToString(avatarPath), time); } else { - return chatWindow_->addMessage(chatMessage, senderName, senderIsSelf, label, pathToString(avatarPath), time); + return chatWindow_->addMessage(chatMessage, senderName, senderIsSelf, displayedLabel, pathToString(avatarPath), time); } } diff --git a/Swift/Controllers/Chat/ChatControllerBase.h b/Swift/Controllers/Chat/ChatControllerBase.h index 88cb95c..f635a46 100644 --- a/Swift/Controllers/Chat/ChatControllerBase.h +++ b/Swift/Controllers/Chat/ChatControllerBase.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2017 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -28,6 +28,7 @@ #include <Swift/Controllers/Highlighting/HighlightManager.h> #include <Swift/Controllers/HistoryController.h> +#include <Swift/Controllers/Settings/SettingsProvider.h> #include <Swift/Controllers/UIInterfaces/ChatWindow.h> #include <Swift/Controllers/XMPPEvents/MUCInviteEvent.h> #include <Swift/Controllers/XMPPEvents/MessageEvent.h> @@ -79,7 +80,7 @@ namespace Swift { boost::signals2::signal<void(ChatWindow* /*window to reuse*/, const std::vector<JID>& /*invite people*/, const std::string& /*reason*/)> onConvertToMUC; protected: - ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, EntityCapsProvider* entityCapsProvider, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, std::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider); + ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, EntityCapsProvider* entityCapsProvider, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, std::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider, SettingsProvider* settings); /** * Pass the Message appended, and the stanza used to send it. @@ -150,5 +151,8 @@ namespace Swift { AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider_; UIEventStream* eventStream_; bool lastWasPresence_ = false; + std::string roomSecurityMarking_; + std::string previousMessageSecurityMarking_; + SettingsProvider* settings_; }; } diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp index b7087fd..dd74f6a 100644 --- a/Swift/Controllers/Chat/ChatsManager.cpp +++ b/Swift/Controllers/Chat/ChatsManager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2017 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -771,7 +771,7 @@ ChatController* ChatsManager::getChatControllerOrFindAnother(const JID &contact) ChatController* ChatsManager::createNewChatController(const JID& contact) { assert(chatControllers_.find(contact) == chatControllers_.end()); std::shared_ptr<ChatMessageParser> chatMessageParser = std::make_shared<ChatMessageParser>(emoticons_, highlightManager_->getConfiguration(), ChatMessageParser::Mode::Chat); /* a message parser that knows this is a chat (not a room/MUC) */ - ChatController* controller = new ChatController(jid_, stanzaChannel_, iqRouter_, chatWindowFactory_, contact, nickResolver_, presenceOracle_, avatarManager_, mucRegistry_->isMUC(contact.toBare()), useDelayForLatency_, uiEventStream_, timerFactory_, eventController_, entityCapsProvider_, userWantsReceipts_, settings_, historyController_, mucRegistry_, highlightManager_, clientBlockListManager_, chatMessageParser, autoAcceptMUCInviteDecider_); + auto controller = new ChatController(jid_, stanzaChannel_, iqRouter_, chatWindowFactory_, contact, nickResolver_, presenceOracle_, avatarManager_, mucRegistry_->isMUC(contact.toBare()), useDelayForLatency_, uiEventStream_, timerFactory_, eventController_, entityCapsProvider_, userWantsReceipts_, historyController_, mucRegistry_, highlightManager_, clientBlockListManager_, chatMessageParser, autoAcceptMUCInviteDecider_, settings_); chatControllers_[contact] = controller; controller->setAvailableServerFeatures(serverDiscoInfo_); controller->onActivity.connect(boost::bind(&ChatsManager::handleChatActivity, this, contact, _1, false)); @@ -860,7 +860,7 @@ MUC::ref ChatsManager::handleJoinMUCRequest(const JID &mucJID, const boost::opti chatWindowFactoryAdapter = new SingleChatWindowFactoryAdapter(reuseChatwindow); } std::shared_ptr<ChatMessageParser> chatMessageParser = std::make_shared<ChatMessageParser>(emoticons_, highlightManager_->getConfiguration(), ChatMessageParser::Mode::GroupChat); /* a message parser that knows this is a room/MUC (not a chat) */ - controller = new MUCController(jid_, muc, password, nick, stanzaChannel_, iqRouter_, reuseChatwindow ? chatWindowFactoryAdapter : chatWindowFactory_, nickResolver_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory_, eventController_, entityCapsProvider_, roster_, historyController_, mucRegistry_, highlightManager_, clientBlockListManager_, chatMessageParser, isImpromptu, autoAcceptMUCInviteDecider_, vcardManager_, mucBookmarkManager_); + controller = new MUCController(jid_, muc, password, nick, stanzaChannel_, iqRouter_, reuseChatwindow ? chatWindowFactoryAdapter : chatWindowFactory_, nickResolver_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory_, eventController_, entityCapsProvider_, roster_, historyController_, mucRegistry_, highlightManager_, clientBlockListManager_, chatMessageParser, isImpromptu, autoAcceptMUCInviteDecider_, vcardManager_, mucBookmarkManager_, settings_); if (chatWindowFactoryAdapter) { /* The adapters are only passed to chat windows, which are deleted in their * controllers' dtor, which are deleted in ChatManager's dtor. The adapters diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp index 9e12a66..4c3f524 100644 --- a/Swift/Controllers/Chat/MUCController.cpp +++ b/Swift/Controllers/Chat/MUCController.cpp @@ -99,8 +99,9 @@ MUCController::MUCController ( bool isImpromptu, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider, VCardManager* vcardManager, - MUCBookmarkManager* mucBookmarkManager) : - ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, muc->getJID(), nickResolver, presenceOracle, avatarManager, useDelayForLatency, uiEventStream, eventController, entityCapsProvider, historyController, mucRegistry, highlightManager, chatMessageParser, autoAcceptMUCInviteDecider), muc_(muc), nick_(nick), desiredNick_(nick), password_(password), renameCounter_(0), isImpromptu_(isImpromptu), isImpromptuAlreadyConfigured_(false), clientBlockListManager_(clientBlockListManager), mucBookmarkManager_(mucBookmarkManager) { + MUCBookmarkManager* mucBookmarkManager, + SettingsProvider* settings) : + ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, muc->getJID(), nickResolver, presenceOracle, avatarManager, useDelayForLatency, uiEventStream, eventController, entityCapsProvider, historyController, mucRegistry, highlightManager, chatMessageParser, autoAcceptMUCInviteDecider, settings), muc_(muc), nick_(nick), desiredNick_(nick), password_(password), renameCounter_(0), isImpromptu_(isImpromptu), isImpromptuAlreadyConfigured_(false), clientBlockListManager_(clientBlockListManager), mucBookmarkManager_(mucBookmarkManager) { assert(avatarManager_); parting_ = true; @@ -1277,7 +1278,7 @@ void MUCController::requestSecurityMarking() { // Now we know the marking is valid auto markingValue = marking->getTextSingleValue(); if (markingValue == "") { - chatWindow_->removeChatSecurityMarking(); + setMUCSecurityMarkingDefault(); return; } auto markingForegroundColor = roomInfoForm->getField("x-isode#roominfo_marking_fg_color"); @@ -1290,10 +1291,20 @@ void MUCController::requestSecurityMarking() { if (markingBackgroundColor) { markingBackgroundColorValue = markingBackgroundColor->getTextSingleValue(); } - chatWindow_->setChatSecurityMarking(markingValue, markingForegroundColorValue, markingBackgroundColorValue); + setMUCSecurityMarking(markingValue, markingForegroundColorValue, markingBackgroundColorValue); } ); discoInfoRequest->send(); } +void MUCController::setMUCSecurityMarking(const std::string& markingValue, const std::string& markingForegroundColorValue, const std::string& markingBackgroundColorValue) { + roomSecurityMarking_ = markingValue; + chatWindow_->setChatSecurityMarking(markingValue, markingForegroundColorValue, markingBackgroundColorValue); +} + +void MUCController::setMUCSecurityMarkingDefault() { + roomSecurityMarking_ = ""; + chatWindow_->removeChatSecurityMarking(); +} + } diff --git a/Swift/Controllers/Chat/MUCController.h b/Swift/Controllers/Chat/MUCController.h index 949f530..afc524f 100644 --- a/Swift/Controllers/Chat/MUCController.h +++ b/Swift/Controllers/Chat/MUCController.h @@ -53,7 +53,7 @@ namespace Swift { class MUCController : public ChatControllerBase { public: - MUCController(const JID& self, MUC::ref muc, const boost::optional<std::string>& password, const std::string &nick, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, UIEventStream* events, bool useDelayForLatency, TimerFactory* timerFactory, EventController* eventController, EntityCapsProvider* entityCapsProvider, XMPPRoster* xmppRoster, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, std::shared_ptr<ChatMessageParser> chatMessageParser, bool isImpromptu, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider, VCardManager* vcardManager, MUCBookmarkManager* mucBookmarkManager); + MUCController(const JID& self, MUC::ref muc, const boost::optional<std::string>& password, const std::string &nick, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, UIEventStream* events, bool useDelayForLatency, TimerFactory* timerFactory, EventController* eventController, EntityCapsProvider* entityCapsProvider, XMPPRoster* xmppRoster, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, std::shared_ptr<ChatMessageParser> chatMessageParser, bool isImpromptu, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider, VCardManager* vcardManager, MUCBookmarkManager* mucBookmarkManager, SettingsProvider* settings); virtual ~MUCController() override; boost::signals2::signal<void ()> onUserLeft; boost::signals2::signal<void ()> onUserJoined; @@ -149,6 +149,8 @@ namespace Swift { void addChatSystemMessage(); void requestSecurityMarking(); + void setMUCSecurityMarking(const std::string& markingValue, const std::string& markingForegroundColorValue, const std::string& markingBackgroundColorValue); + void setMUCSecurityMarkingDefault(); private: MUC::ref muc_; @@ -191,4 +193,3 @@ namespace Swift { std::string chatWindowTitle_; }; } - diff --git a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp index 06486d3..9b45794 100644 --- a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp +++ b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp @@ -36,6 +36,7 @@ #include <Swift/Controllers/Chat/UserSearchController.h> #include <Swift/Controllers/Roster/GroupRosterItem.h> #include <Swift/Controllers/Roster/Roster.h> +#include <Swift/Controllers/SettingConstants.h> #include <Swift/Controllers/Settings/DummySettingsProvider.h> #include <Swift/Controllers/UIEvents/UIEventStream.h> #include <Swift/Controllers/UIInterfaces/ChatWindow.h> @@ -76,6 +77,17 @@ class MUCControllerTest : public CppUnit::TestFixture { CPPUNIT_TEST(testSecurityMarkingRequestNoForm); CPPUNIT_TEST(testSecurityMarkingRequestError); + CPPUNIT_TEST(testSecurityMarkingAddedToMessage_Elision_NoRoomMarkingA); + CPPUNIT_TEST(testSecurityMarkingAddedToMessage_Elision_NoRoomMarkingB); + CPPUNIT_TEST(testSecurityMarkingAddedToMessage_Elision_WithRoomMarkingA); + CPPUNIT_TEST(testSecurityMarkingAddedToMessage_Elision_WithRoomMarkingB); + CPPUNIT_TEST(testSecurityMarkingAddedToMessage_Elision_WithRoomMarkingC); + + CPPUNIT_TEST(testSecurityMarkingAddedToMessage_NoElision_NoRoomMarkingA); + CPPUNIT_TEST(testSecurityMarkingAddedToMessage_NoElision_NoRoomMarkingB); + CPPUNIT_TEST(testSecurityMarkingAddedToMessage_NoElision_WithRoomMarkingA); + CPPUNIT_TEST(testSecurityMarkingAddedToMessage_NoElision_WithRoomMarkingB); + CPPUNIT_TEST_SUITE_END(); public: @@ -112,7 +124,7 @@ public: nickResolver_ = new NickResolver(self_, xmppRoster_, vcardManager_, mucRegistry_); clientBlockListManager_ = new ClientBlockListManager(iqRouter_); mucBookmarkManager_ = new MUCBookmarkManager(iqRouter_); - controller_ = new MUCController (self_, muc_, boost::optional<std::string>(), nick_, stanzaChannel_, iqRouter_, chatWindowFactory_, nickResolver_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory, eventController_, entityCapsProvider_, nullptr, nullptr, mucRegistry_, highlightManager_, clientBlockListManager_, chatMessageParser_, false, nullptr, vcardManager_, mucBookmarkManager_); + controller_ = new MUCController (self_, muc_, boost::optional<std::string>(), nick_, stanzaChannel_, iqRouter_, chatWindowFactory_, nickResolver_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory, eventController_, entityCapsProvider_, nullptr, nullptr, mucRegistry_, highlightManager_, clientBlockListManager_, chatMessageParser_, false, nullptr, vcardManager_, mucBookmarkManager_, settings_); } void tearDown() { @@ -171,6 +183,44 @@ public: } } + void setMUCSecurityMarking(const std::string& markingValue, const std::string & markingForegroundColorValue, const std::string& markingBackgroundColorValue, const bool includeFormTypeField = true) { + auto form = std::make_shared<Form>(Form::Type::ResultType); + + if (includeFormTypeField) { + std::shared_ptr<FormField> formTypeField = std::make_shared<FormField>(FormField::Type::HiddenType, "http://jabber.org/protocol/muc#roominfo"); + formTypeField->setName("FORM_TYPE"); + form->addField(formTypeField); + } + + auto markingField = std::make_shared<FormField>(FormField::Type::TextSingleType, markingValue); + auto markingForegroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, markingForegroundColorValue); + auto markingBackgroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, markingBackgroundColorValue); + + markingField->setName("x-isode#roominfo_marking"); + markingForegroundColorField->setName("x-isode#roominfo_marking_fg_color"); + markingBackgroundColorField->setName("x-isode#roominfo_marking_bg_color"); + + form->addField(markingField); + form->addField(markingForegroundColorField); + form->addField(markingBackgroundColorField); + + auto discoInfoRef = std::make_shared<DiscoInfo>(); + discoInfoRef->addExtension(form); + + auto infoResponse = IQ::createResult(self_, mucJID_, "test-id", discoInfoRef); + iqChannel_->onIQReceived(infoResponse); + } + + Message::ref createTestMessageWithoutSecurityLabel() { + auto message = std::make_shared<Message>(); + message->setType(Message::Type::Groupchat); + message->setID("test-id"); + message->setTo(self_); + message->setFrom(mucJID_.withResource("TestNickname")); + message->setBody("Do Not Read This Message"); + return message; + } + void testAddressedToSelf() { finishJoin(); Message::ref message(new Message()); @@ -602,34 +652,16 @@ public: } void testSecurityMarkingRequestCompleteMarking() { - auto formTypeField = std::make_shared<FormField>(FormField::Type::HiddenType, "http://jabber.org/protocol/muc#roominfo"); - auto markingField = std::make_shared<FormField>(FormField::Type::TextSingleType, "Test | Highest Possible Security"); - auto markingForegroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, "Black"); - auto markingBackgroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, "Red"); - formTypeField->setName("FORM_TYPE"); - markingField->setName("x-isode#roominfo_marking"); - markingForegroundColorField->setName("x-isode#roominfo_marking_fg_color"); - markingBackgroundColorField->setName("x-isode#roominfo_marking_bg_color"); - - auto form = std::make_shared<Form>(Form::Type::ResultType); - form->addField(formTypeField); - form->addField(markingField); - form->addField(markingForegroundColorField); - form->addField(markingBackgroundColorField); + setMUCSecurityMarking("Test|Highest Possible Security", "Black", "Red", true); - auto discoInfoRef = std::make_shared<DiscoInfo>(); - discoInfoRef->addExtension(form); - - auto infoResponse = IQ::createResult(self_, mucJID_, "test-id", discoInfoRef); - iqChannel_->onIQReceived(infoResponse); - CPPUNIT_ASSERT_EQUAL(std::string("Test | Highest Possible Security"), window_->markingValue_); + CPPUNIT_ASSERT_EQUAL(std::string("Test|Highest Possible Security"), window_->markingValue_); CPPUNIT_ASSERT_EQUAL(std::string("Black"), window_->markingForegroundColorValue_); CPPUNIT_ASSERT_EQUAL(std::string("Red"), window_->markingBackgroundColorValue_); } void testSecurityMarkingRequestCompleteMarkingWithExtraForm() { auto formTypeField = std::make_shared<FormField>(FormField::Type::HiddenType, "http://jabber.org/protocol/muc#roominfo"); - auto markingField = std::make_shared<FormField>(FormField::Type::TextSingleType, "Test | Highest Possible Security"); + auto markingField = std::make_shared<FormField>(FormField::Type::TextSingleType, "Test|Highest Possible Security"); auto markingForegroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, "Black"); auto markingBackgroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, "Red"); formTypeField->setName("FORM_TYPE"); @@ -650,14 +682,14 @@ public: auto infoResponse = IQ::createResult(self_, mucJID_, "test-id", discoInfoRef); iqChannel_->onIQReceived(infoResponse); - CPPUNIT_ASSERT_EQUAL(std::string("Test | Highest Possible Security"), window_->markingValue_); + CPPUNIT_ASSERT_EQUAL(std::string("Test|Highest Possible Security"), window_->markingValue_); CPPUNIT_ASSERT_EQUAL(std::string("Black"), window_->markingForegroundColorValue_); CPPUNIT_ASSERT_EQUAL(std::string("Red"), window_->markingBackgroundColorValue_); } void testSecurityMarkingRequestNoColorsInMarking() { auto formTypeField = std::make_shared<FormField>(FormField::Type::HiddenType, "http://jabber.org/protocol/muc#roominfo"); - auto markingField = std::make_shared<FormField>(FormField::Type::TextSingleType, "Test | Highest Possible Security"); + auto markingField = std::make_shared<FormField>(FormField::Type::TextSingleType, "Test|Highest Possible Security"); auto markingForegroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, ""); auto markingBackgroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, ""); formTypeField->setName("FORM_TYPE"); @@ -676,55 +708,22 @@ public: auto infoResponse = IQ::createResult(self_, mucJID_, "test-id", discoInfoRef); iqChannel_->onIQReceived(infoResponse); - CPPUNIT_ASSERT_EQUAL(std::string("Test | Highest Possible Security"), window_->markingValue_); + CPPUNIT_ASSERT_EQUAL(std::string("Test|Highest Possible Security"), window_->markingValue_); CPPUNIT_ASSERT_EQUAL(std::string("Black"), window_->markingForegroundColorValue_); CPPUNIT_ASSERT_EQUAL(std::string("White"), window_->markingBackgroundColorValue_); } void testSecurityMarkingRequestEmptyMarking() { - auto formTypeField = std::make_shared<FormField>(FormField::Type::HiddenType, "http://jabber.org/protocol/muc#roominfo"); - auto markingField = std::make_shared<FormField>(FormField::Type::TextSingleType, ""); - auto markingForegroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, ""); - auto markingBackgroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, ""); - formTypeField->setName("FORM_TYPE"); - markingField->setName("x-isode#roominfo_marking"); - markingForegroundColorField->setName("x-isode#roominfo_marking_fg_color"); - markingBackgroundColorField->setName("x-isode#roominfo_marking_bg_color"); + setMUCSecurityMarking("", "", "", true); - auto form = std::make_shared<Form>(Form::Type::ResultType); - form->addField(formTypeField); - form->addField(markingField); - form->addField(markingForegroundColorField); - form->addField(markingBackgroundColorField); - - auto discoInfoRef = std::make_shared<DiscoInfo>(); - discoInfoRef->addExtension(form); - - auto infoResponse = IQ::createResult(self_, mucJID_, "test-id", discoInfoRef); - iqChannel_->onIQReceived(infoResponse); CPPUNIT_ASSERT_EQUAL(std::string(""), window_->markingValue_); CPPUNIT_ASSERT_EQUAL(std::string(""), window_->markingForegroundColorValue_); CPPUNIT_ASSERT_EQUAL(std::string(""), window_->markingBackgroundColorValue_); } void testSecurityMarkingRequestWithMarkingNoFormType() { - auto markingField = std::make_shared<FormField>(FormField::Type::TextSingleType, "Test | Highest Possible Security"); - auto markingForegroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, "Black"); - auto markingBackgroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, "Red"); - markingField->setName("x-isode#roominfo_marking"); - markingForegroundColorField->setName("x-isode#roominfo_marking_fg_color"); - markingBackgroundColorField->setName("x-isode#roominfo_marking_bg_color"); + setMUCSecurityMarking("Test|Highest Possible Security", "Black", "Red", false); - auto form = std::make_shared<Form>(Form::Type::ResultType); - form->addField(markingField); - form->addField(markingForegroundColorField); - form->addField(markingBackgroundColorField); - - auto discoInfoRef = std::make_shared<DiscoInfo>(); - discoInfoRef->addExtension(form); - - auto infoResponse = IQ::createResult(self_, mucJID_, "test-id", discoInfoRef); - iqChannel_->onIQReceived(infoResponse); CPPUNIT_ASSERT_EQUAL(std::string(""), window_->markingValue_); CPPUNIT_ASSERT_EQUAL(std::string(""), window_->markingForegroundColorValue_); CPPUNIT_ASSERT_EQUAL(std::string(""), window_->markingBackgroundColorValue_); @@ -763,6 +762,212 @@ public: CPPUNIT_ASSERT_EQUAL(std::string(""), window_->markingBackgroundColorValue_); } + void testSecurityMarkingAddedToMessage_Elision_NoRoomMarkingA() { + settings_->storeSetting(SettingConstants::MUC_MARKING_ELISION, true); + setMUCSecurityMarking("", "Black", "Red"); + + auto messageLabel = std::make_shared<SecurityLabel>(); + messageLabel->setDisplayMarking("Test|Highest Possible Security"); + + auto sentMessage = createTestMessageWithoutSecurityLabel(); + sentMessage->addPayload(messageLabel); + + auto sentMessageEvent = std::make_shared<MessageEvent>(sentMessage); + controller_->handleIncomingMessage(sentMessageEvent); + + auto storedSecurityLabel = window_->lastAddedMessageSecurityLabel_; + + CPPUNIT_ASSERT_EQUAL(false, storedSecurityLabel == nullptr); + // This is the potentially altered security label that is displayed on the screen + CPPUNIT_ASSERT_EQUAL(std::string("Test|Highest Possible Security"), storedSecurityLabel->getDisplayMarking()); + } + + void testSecurityMarkingAddedToMessage_Elision_NoRoomMarkingB() { + settings_->storeSetting(SettingConstants::MUC_MARKING_ELISION, true); + setMUCSecurityMarking("", "Black", "Red"); + + auto messageLabel = std::make_shared<SecurityLabel>(); + messageLabel->setDisplayMarking(""); + + auto sentMessage = createTestMessageWithoutSecurityLabel(); + sentMessage->addPayload(messageLabel); + + auto sentMessageEvent = std::make_shared<MessageEvent>(sentMessage); + controller_->handleIncomingMessage(sentMessageEvent); + + auto storedSecurityLabel = window_->lastAddedMessageSecurityLabel_; + + CPPUNIT_ASSERT_EQUAL(false, storedSecurityLabel == nullptr); + // This is the potentially altered security label that is displayed on the screen + CPPUNIT_ASSERT_EQUAL(std::string(""), storedSecurityLabel->getDisplayMarking()); + } + + void testSecurityMarkingAddedToMessage_Elision_WithRoomMarkingA() { + settings_->storeSetting(SettingConstants::MUC_MARKING_ELISION, true); + setMUCSecurityMarking("Test|Highest Possible Security", "Black", "Red"); + + auto messageLabel = std::make_shared<SecurityLabel>(); + messageLabel->setDisplayMarking("Test|Highest Possible Security"); + + auto sentMessage = createTestMessageWithoutSecurityLabel(); + sentMessage->addPayload(messageLabel); + + // Test the first message matching MUC marking. This message SHOULD have a marking + + auto sentMessageEvent1 = std::make_shared<MessageEvent>(sentMessage); + controller_->handleIncomingMessage(sentMessageEvent1); + + auto storedSecurityLabel1 = window_->lastAddedMessageSecurityLabel_; + + CPPUNIT_ASSERT_EQUAL(false, storedSecurityLabel1 == nullptr); + // This is the potentially altered security label that is displayed on the screen + CPPUNIT_ASSERT_EQUAL(std::string("Test|Highest Possible Security"), storedSecurityLabel1->getDisplayMarking()); + + // Test a consecutive message matching MUC marking. This message SHOULD NOT have a marking + + auto sentMessageEvent2 = std::make_shared<MessageEvent>(sentMessage); + controller_->handleIncomingMessage(sentMessageEvent2); + + auto storedSecurityLabel2 = window_->lastAddedMessageSecurityLabel_; + + CPPUNIT_ASSERT_EQUAL(false, storedSecurityLabel2 == nullptr); + // This is the potentially altered security label that is displayed on the screen + CPPUNIT_ASSERT_EQUAL(std::string(""), storedSecurityLabel2->getDisplayMarking()); + } + + void testSecurityMarkingAddedToMessage_Elision_WithRoomMarkingB() { + settings_->storeSetting(SettingConstants::MUC_MARKING_ELISION, true); + setMUCSecurityMarking("Test|Lower Security Marking", "Black", "Red"); + + auto messageLabel = std::make_shared<SecurityLabel>(); + messageLabel->setDisplayMarking("Test|Highest Possible Security"); + + auto sentMessage = createTestMessageWithoutSecurityLabel(); + sentMessage->addPayload(messageLabel); + + auto sentMessageEvent = std::make_shared<MessageEvent>(sentMessage); + controller_->handleIncomingMessage(sentMessageEvent); + + auto storedSecurityLabel = window_->lastAddedMessageSecurityLabel_; + + CPPUNIT_ASSERT_EQUAL(false, storedSecurityLabel == nullptr); + // This is the potentially altered security label that is displayed on the screen + CPPUNIT_ASSERT_EQUAL(std::string("Test|Highest Possible Security"), storedSecurityLabel->getDisplayMarking()); + } + + void testSecurityMarkingAddedToMessage_Elision_WithRoomMarkingC() { + settings_->storeSetting(SettingConstants::MUC_MARKING_ELISION, true); + setMUCSecurityMarking("Test|Highest Possible Security", "Black", "Red"); + + auto messageLabel = std::make_shared<SecurityLabel>(); + messageLabel->setDisplayMarking(""); + + auto sentMessage = createTestMessageWithoutSecurityLabel(); + sentMessage->addPayload(messageLabel); + + auto sentMessageEvent = std::make_shared<MessageEvent>(sentMessage); + controller_->handleIncomingMessage(sentMessageEvent); + + auto storedSecurityLabel = window_->lastAddedMessageSecurityLabel_; + + CPPUNIT_ASSERT_EQUAL(false, storedSecurityLabel == nullptr); + // This is the potentially altered security label that is displayed on the screen + CPPUNIT_ASSERT_EQUAL(std::string("Unmarked"), storedSecurityLabel->getDisplayMarking()); + } + + void testSecurityMarkingAddedToMessage_NoElision_NoRoomMarkingA() { + settings_->storeSetting(SettingConstants::MUC_MARKING_ELISION, false); + setMUCSecurityMarking("", "Black", "Red"); + + auto messageLabel = std::make_shared<SecurityLabel>(); + messageLabel->setDisplayMarking("Test|Highest Possible Security"); + + auto sentMessage = createTestMessageWithoutSecurityLabel(); + sentMessage->addPayload(messageLabel); + + auto sentMessageEvent = std::make_shared<MessageEvent>(sentMessage); + controller_->handleIncomingMessage(sentMessageEvent); + + auto storedSecurityLabel = window_->lastAddedMessageSecurityLabel_; + + CPPUNIT_ASSERT_EQUAL(false, storedSecurityLabel == nullptr); + // This is the potentially altered security label that is displayed on the screen + CPPUNIT_ASSERT_EQUAL(std::string("Test|Highest Possible Security"), storedSecurityLabel->getDisplayMarking()); + } + + void testSecurityMarkingAddedToMessage_NoElision_NoRoomMarkingB() { + settings_->storeSetting(SettingConstants::MUC_MARKING_ELISION, false); + setMUCSecurityMarking("", "Black", "Red"); + + auto messageLabel = std::make_shared<SecurityLabel>(); + messageLabel->setDisplayMarking(""); + + auto sentMessage = createTestMessageWithoutSecurityLabel(); + sentMessage->addPayload(messageLabel); + + auto sentMessageEvent = std::make_shared<MessageEvent>(sentMessage); + controller_->handleIncomingMessage(sentMessageEvent); + + auto storedSecurityLabel = window_->lastAddedMessageSecurityLabel_; + + CPPUNIT_ASSERT_EQUAL(false, storedSecurityLabel == nullptr); + // This is the potentially altered security label that is displayed on the screen + CPPUNIT_ASSERT_EQUAL(std::string(""), storedSecurityLabel->getDisplayMarking()); + } + + void testSecurityMarkingAddedToMessage_NoElision_WithRoomMarkingA() { + settings_->storeSetting(SettingConstants::MUC_MARKING_ELISION, false); + setMUCSecurityMarking("Test|Highest Possible Security", "Black", "Red"); + + auto messageLabel = std::make_shared<SecurityLabel>(); + messageLabel->setDisplayMarking("Test|Highest Possible Security"); + + auto sentMessage = createTestMessageWithoutSecurityLabel(); + sentMessage->addPayload(messageLabel); + + // Test the first message matching MUC marking. This message SHOULD have a marking + + auto sentMessageEvent1 = std::make_shared<MessageEvent>(sentMessage); + controller_->handleIncomingMessage(sentMessageEvent1); + + auto storedSecurityLabel1 = window_->lastAddedMessageSecurityLabel_; + + CPPUNIT_ASSERT_EQUAL(false, storedSecurityLabel1 == nullptr); + // This is the potentially altered security label that is displayed on the screen + CPPUNIT_ASSERT_EQUAL(std::string("Test|Highest Possible Security"), storedSecurityLabel1->getDisplayMarking()); + + // Test a consecutive message matching MUC marking. This message SHOULD ALSO have a marking + + auto sentMessageEvent2 = std::make_shared<MessageEvent>(sentMessage); + controller_->handleIncomingMessage(sentMessageEvent2); + + auto storedSecurityLabel2 = window_->lastAddedMessageSecurityLabel_; + + CPPUNIT_ASSERT_EQUAL(false, storedSecurityLabel2 == nullptr); + // This is the potentially altered security label that is displayed on the screen + CPPUNIT_ASSERT_EQUAL(std::string("Test|Highest Possible Security"), storedSecurityLabel2->getDisplayMarking()); + } + + void testSecurityMarkingAddedToMessage_NoElision_WithRoomMarkingB() { + settings_->storeSetting(SettingConstants::MUC_MARKING_ELISION, false); + setMUCSecurityMarking("", "Black", "Red"); + + auto messageLabel = std::make_shared<SecurityLabel>(); + messageLabel->setDisplayMarking(""); + + auto sentMessage = createTestMessageWithoutSecurityLabel(); + sentMessage->addPayload(messageLabel); + + auto sentMessageEvent = std::make_shared<MessageEvent>(sentMessage); + controller_->handleIncomingMessage(sentMessageEvent); + + auto storedSecurityLabel = window_->lastAddedMessageSecurityLabel_; + + CPPUNIT_ASSERT_EQUAL(false, storedSecurityLabel == nullptr); + // This is the potentially altered security label that is displayed on the screen + CPPUNIT_ASSERT_EQUAL(std::string(""), storedSecurityLabel->getDisplayMarking()); + } + private: JID self_; JID mucJID_; diff --git a/Swift/Controllers/SettingConstants.cpp b/Swift/Controllers/SettingConstants.cpp index f0064ba..5347d4e 100644 --- a/Swift/Controllers/SettingConstants.cpp +++ b/Swift/Controllers/SettingConstants.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2017 Isode Limited. + * Copyright (c) 2012-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -24,5 +24,6 @@ const SettingsProvider::Setting<std::string> SettingConstants::HIGHLIGHT_RULES_V const SettingsProvider::Setting<std::string> SettingConstants::INVITE_AUTO_ACCEPT_MODE("inviteAutoAcceptMode", "presence"); const SettingsProvider::Setting<bool> SettingConstants::DISCONNECT_ON_CARD_REMOVAL("disconnectOnCardRemoval", true); const SettingsProvider::Setting<bool> SettingConstants::SINGLE_SIGN_ON("singleSignOn", false); +const SettingsProvider::Setting<bool> SettingConstants::MUC_MARKING_ELISION("mucMarkingElision", true); } diff --git a/Swift/Controllers/SettingConstants.h b/Swift/Controllers/SettingConstants.h index fec2d27..61781e0 100644 --- a/Swift/Controllers/SettingConstants.h +++ b/Swift/Controllers/SettingConstants.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2017 Isode Limited. + * Copyright (c) 2012-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -93,5 +93,16 @@ namespace Swift { * log in the user; else not. */ static const SettingsProvider::Setting<bool> SINGLE_SIGN_ON; + /** + * The #MUC_MARKING_ELISION setting + * specifies whether or not messages with the default muc + * marking display their marking, and whether unmarked messages + * are marked as such. + * + * If set true, unmarked messages will be marked with the marking + * "unmarked", and messages with the room default marking will + * have their markings stripped. + */ + static const SettingsProvider::Setting<bool> MUC_MARKING_ELISION; }; } diff --git a/Swift/Controllers/UnitTest/MockChatWindow.h b/Swift/Controllers/UnitTest/MockChatWindow.h index 56f118d..389d787 100644 --- a/Swift/Controllers/UnitTest/MockChatWindow.h +++ b/Swift/Controllers/UnitTest/MockChatWindow.h @@ -17,10 +17,11 @@ namespace Swift { MockChatWindow() {} virtual ~MockChatWindow(); - virtual std::string addMessage(const ChatMessage& message, const std::string& senderName, bool senderIsSelf, std::shared_ptr<SecurityLabel> /*label*/, const std::string& /*avatarPath*/, const boost::posix_time::ptime& /*time*/) { + virtual std::string addMessage(const ChatMessage& message, const std::string& senderName, bool senderIsSelf, std::shared_ptr<SecurityLabel> label, const std::string& /*avatarPath*/, const boost::posix_time::ptime& /*time*/) { lastAddedMessage_ = message; lastAddedMessageSenderName_ = senderName; lastAddedMessageSenderIsSelf_ = senderIsSelf; + lastAddedMessageSecurityLabel_ = label; return "id"; } @@ -145,6 +146,7 @@ namespace Swift { ChatMessage lastAddedMessage_; std::string lastAddedMessageSenderName_; bool lastAddedMessageSenderIsSelf_ = false; + std::shared_ptr<SecurityLabel> lastAddedMessageSecurityLabel_ = nullptr; ChatMessage lastAddedAction_; std::string lastAddedActionSenderName_; bool lastAddedActionSenderIsSelf_ = false; diff --git a/Swift/QtUI/QtChatWindow.cpp b/Swift/QtUI/QtChatWindow.cpp index 17e3328..96162ba 100644 --- a/Swift/QtUI/QtChatWindow.cpp +++ b/Swift/QtUI/QtChatWindow.cpp @@ -111,7 +111,7 @@ QtChatWindow::QtChatWindow(const QString& contact, QtChatTheme* theme, UIEventSt messageLog_ = new QtPlainChatView(this, eventStream_); } else { - messageLog_ = new QtWebKitChatView(this, eventStream_, theme, this); // I accept that passing the ChatWindow in so that the view can call the signals is somewhat inelegant, but it saves a lot of boilerplate. This patch is unpleasant enough already. So let's fix this soon (it at least needs fixing by the time history is sorted), but not now. + messageLog_ = new QtWebKitChatView(this, eventStream_, theme, this, settings); // I accept that passing the ChatWindow in so that the view can call the signals is somewhat inelegant, but it saves a lot of boilerplate. This patch is unpleasant enough already. So let's fix this soon (it at least needs fixing by the time history is sorted), but not now. } logRosterSplitter_->addWidget(messageLog_); diff --git a/Swift/QtUI/QtHistoryWindow.cpp b/Swift/QtUI/QtHistoryWindow.cpp index 77a7f12..983d0e9 100644 --- a/Swift/QtUI/QtHistoryWindow.cpp +++ b/Swift/QtUI/QtHistoryWindow.cpp @@ -49,7 +49,7 @@ QtHistoryWindow::QtHistoryWindow(SettingsProvider* settings, UIEventStream* even idCounter_ = 0; delete ui_.conversation_; - conversation_ = new QtWebKitChatView(nullptr, nullptr, theme_, this, true); // Horrible unsafe. Do not do this. FIXME + conversation_ = new QtWebKitChatView(nullptr, nullptr, theme_, this, settings, true); // Horrible unsafe. Do not do this. FIXME QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); sizePolicy.setHorizontalStretch(80); sizePolicy.setVerticalStretch(0); diff --git a/Swift/QtUI/QtWebKitChatView.cpp b/Swift/QtUI/QtWebKitChatView.cpp index ea9a9c6..f3d23e7 100644 --- a/Swift/QtUI/QtWebKitChatView.cpp +++ b/Swift/QtUI/QtWebKitChatView.cpp @@ -28,6 +28,8 @@ #include <Swiften/Base/Log.h> #include <Swiften/StringCodecs/Base64.h> +#include <Swift/Controllers/SettingConstants.h> +#include <Swift/Controllers/Settings/SettingsProvider.h> #include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h> #include <Swift/Controllers/UIEvents/UIEventStream.h> @@ -56,7 +58,7 @@ namespace { const double minimalFontScaling = 0.7; } -QtWebKitChatView::QtWebKitChatView(QtChatWindow* window, UIEventStream* eventStream, QtChatTheme* theme, QWidget* parent, bool disableAutoScroll) : QtChatView(parent), window_(window), eventStream_(eventStream), fontSizeSteps_(0), disableAutoScroll_(disableAutoScroll), previousMessageKind_(PreviosuMessageWasNone), previousMessageWasSelf_(false), showEmoticons_(false), insertingLastLine_(false), idCounter_(0) { +QtWebKitChatView::QtWebKitChatView(QtChatWindow* window, UIEventStream* eventStream, QtChatTheme* theme, QWidget* parent, SettingsProvider* settings, bool disableAutoScroll /*= false*/) : QtChatView(parent), window_(window), eventStream_(eventStream), fontSizeSteps_(0), disableAutoScroll_(disableAutoScroll), previousMessageKind_(PreviosuMessageWasNone), previousMessageWasSelf_(false), showEmoticons_(false), insertingLastLine_(false), idCounter_(0), settings_(settings) { theme_ = theme; QVBoxLayout* mainLayout = new QVBoxLayout(this); @@ -555,10 +557,13 @@ std::string QtWebKitChatView::addMessage( QString scaledAvatarPath = QtScaledAvatarCache(32).getScaledAvatarPath(avatarPath.c_str()); + std::string messageMarkingValue = ""; + QString htmlString; if (label) { + messageMarkingValue = label->getDisplayMarking(); htmlString = QString("<span style=\"border: thin dashed grey; padding-left: .5em; padding-right: .5em; color: %1; background-color: %2; font-size: 90%; margin-right: .5em; \" class='swift_label'>").arg(QtUtilities::htmlEscape(P2QSTRING(label->getForegroundColor()))).arg(QtUtilities::htmlEscape(P2QSTRING(label->getBackgroundColor()))); - htmlString += QString("%1</span> ").arg(QtUtilities::htmlEscape(P2QSTRING(label->getDisplayMarking()))); + htmlString += QString("%1</span> ").arg(QtUtilities::htmlEscape(P2QSTRING(messageMarkingValue))); } QString styleSpanStart = style == "" ? "" : "<span style=\"" + style + "\">"; @@ -569,7 +574,7 @@ std::string QtWebKitChatView::addMessage( QString highlightSpanEnd = highlightWholeMessage ? "</span>" : ""; htmlString += "<span class='swift_inner_message'>" + styleSpanStart + highlightSpanStart + message + highlightSpanEnd + styleSpanEnd + "</span>" ; - bool appendToPrevious = appendToPreviousCheck(PreviousMessageWasMessage, senderName, senderIsSelf); + bool appendToPrevious = appendToPreviousCheck(PreviousMessageWasMessage, senderName, senderIsSelf, label); QString qAvatarPath = scaledAvatarPath.isEmpty() ? "qrc:/icons/avatar.svg" : QUrl::fromLocalFile(scaledAvatarPath).toEncoded(); std::string id = "id" + boost::lexical_cast<std::string>(idCounter_++); @@ -578,6 +583,7 @@ std::string QtWebKitChatView::addMessage( previousMessageWasSelf_ = senderIsSelf; previousSenderName_ = P2QSTRING(senderName); previousMessageKind_ = PreviousMessageWasMessage; + previousMessageDisplayMarking_ = messageMarkingValue; return id; } @@ -978,12 +984,19 @@ void QtWebKitChatView::setMessageReceiptState(const std::string& id, ChatWindow: setReceiptXML(P2QSTRING(id), xml); } -bool QtWebKitChatView::appendToPreviousCheck(PreviousMessageKind messageKind, const std::string& senderName, bool senderIsSelf) { +bool QtWebKitChatView::appendToPreviousCheck(PreviousMessageKind messageKind, const std::string& senderName, bool senderIsSelf, const std::shared_ptr<SecurityLabel>& label /*=nullptr*/) { bool result = previousMessageKind_ == messageKind && ((senderIsSelf && previousMessageWasSelf_) || (!senderIsSelf && !previousMessageWasSelf_&& previousSenderName_ == P2QSTRING(senderName))); if (insertingLastLine_) { insertingLastLine_ = false; return false; } + if (settings_->getSetting(SettingConstants::MUC_MARKING_ELISION)) { + if (label && label->getDisplayMarking() != previousMessageDisplayMarking_) { + if (label->getDisplayMarking() != "") { + return false; + } + } + } return result; } diff --git a/Swift/QtUI/QtWebKitChatView.h b/Swift/QtUI/QtWebKitChatView.h index f816942..a2eafe6 100644 --- a/Swift/QtUI/QtWebKitChatView.h +++ b/Swift/QtUI/QtWebKitChatView.h @@ -28,6 +28,7 @@ namespace Swift { class QtChatWindowJSBridge; class UIEventStream; class QtChatWindow; + class SettingsProvider; class QtWebKitChatView : public QtChatView { Q_OBJECT @@ -42,7 +43,7 @@ namespace Swift { static const QString ButtonFileTransferOpenFile; static const QString ButtonMUCInvite; public: - QtWebKitChatView(QtChatWindow* window, UIEventStream* eventStream, QtChatTheme* theme, QWidget* parent, bool disableAutoScroll = false); + QtWebKitChatView(QtChatWindow* window, UIEventStream* eventStream, QtChatTheme* theme, QWidget* parent, SettingsProvider* settings, bool disableAutoScroll = false); ~QtWebKitChatView() override; /** Add message to window. @@ -150,7 +151,7 @@ namespace Swift { const boost::posix_time::ptime& time, const QString& style, const HighlightAction& highlight); - bool appendToPreviousCheck(PreviousMessageKind messageKind, const std::string& senderName, bool senderIsSelf); + bool appendToPreviousCheck(PreviousMessageKind messageKind, const std::string& senderName, bool senderIsSelf, const std::shared_ptr<SecurityLabel>& label = nullptr); static ChatSnippet::Direction getActualDirection(const ChatWindow::ChatMessage& message, ChatWindow::Direction direction); QString getHighlightSpanStart(const std::string& text, const std::string& background); QString getHighlightSpanStart(const HighlightAction& highlight); @@ -189,5 +190,7 @@ namespace Swift { QString previousSenderName_; std::map<QString, QString> descriptions_; std::map<QString, QString> filePaths_; + std::string previousMessageDisplayMarking_; + SettingsProvider* settings_ = nullptr; }; } diff --git a/Swiften/Elements/SecurityLabel.h b/Swiften/Elements/SecurityLabel.h index 0f0311e..fcaa610 100644 --- a/Swiften/Elements/SecurityLabel.h +++ b/Swiften/Elements/SecurityLabel.h @@ -15,6 +15,7 @@ namespace Swift { class SWIFTEN_API SecurityLabel : public Payload { public: + using ref = std::shared_ptr<SecurityLabel>; SecurityLabel(); |