summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swift/Controllers')
-rw-r--r--Swift/Controllers/BlockListController.cpp159
-rw-r--r--Swift/Controllers/BlockListController.h48
-rw-r--r--Swift/Controllers/Chat/AutoAcceptMUCInviteDecider.h42
-rw-r--r--Swift/Controllers/Chat/ChatController.cpp141
-rw-r--r--Swift/Controllers/Chat/ChatController.h29
-rw-r--r--Swift/Controllers/Chat/ChatControllerBase.cpp93
-rw-r--r--Swift/Controllers/Chat/ChatControllerBase.h68
-rw-r--r--Swift/Controllers/Chat/ChatMessageParser.cpp112
-rw-r--r--Swift/Controllers/Chat/ChatMessageParser.h23
-rw-r--r--Swift/Controllers/Chat/ChatsManager.cpp397
-rw-r--r--Swift/Controllers/Chat/ChatsManager.h60
-rw-r--r--Swift/Controllers/Chat/MUCController.cpp282
-rw-r--r--Swift/Controllers/Chat/MUCController.h40
-rw-r--r--Swift/Controllers/Chat/UnitTest/ChatMessageParserTest.cpp74
-rw-r--r--Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp86
-rw-r--r--Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp49
-rw-r--r--Swift/Controllers/Chat/UnitTest/MockChatListWindow.h8
-rw-r--r--Swift/Controllers/Chat/UserSearchController.cpp149
-rw-r--r--Swift/Controllers/Chat/UserSearchController.h21
-rw-r--r--Swift/Controllers/ChatMessageSummarizer.cpp4
-rw-r--r--Swift/Controllers/Contact.cpp17
-rw-r--r--Swift/Controllers/Contact.h28
-rw-r--r--Swift/Controllers/ContactProvider.cpp15
-rw-r--r--Swift/Controllers/ContactProvider.h21
-rw-r--r--Swift/Controllers/ContactSuggester.cpp80
-rw-r--r--Swift/Controllers/ContactSuggester.h36
-rw-r--r--Swift/Controllers/ContactsFromXMPPRoster.cpp36
-rw-r--r--Swift/Controllers/ContactsFromXMPPRoster.h29
-rw-r--r--Swift/Controllers/DummySoundPlayer.h2
-rw-r--r--Swift/Controllers/DummySystemTray.h4
-rw-r--r--Swift/Controllers/FileTransfer/FileTransferController.cpp22
-rw-r--r--Swift/Controllers/FileTransfer/FileTransferProgressInfo.cpp4
-rw-r--r--Swift/Controllers/HighlightAction.cpp28
-rw-r--r--Swift/Controllers/HighlightAction.h45
-rw-r--r--Swift/Controllers/HighlightEditorController.cpp40
-rw-r--r--Swift/Controllers/HighlightEditorController.h38
-rw-r--r--Swift/Controllers/HighlightManager.cpp139
-rw-r--r--Swift/Controllers/HighlightManager.h49
-rw-r--r--Swift/Controllers/HighlightRule.cpp192
-rw-r--r--Swift/Controllers/HighlightRule.h77
-rw-r--r--Swift/Controllers/Highlighter.cpp41
-rw-r--r--Swift/Controllers/Highlighter.h37
-rw-r--r--Swift/Controllers/HistoryViewController.cpp16
-rw-r--r--Swift/Controllers/MainController.cpp193
-rw-r--r--Swift/Controllers/MainController.h54
-rw-r--r--Swift/Controllers/ProfileController.cpp8
-rw-r--r--Swift/Controllers/ProfileController.h1
-rw-r--r--Swift/Controllers/Roster/ContactRosterItem.cpp39
-rw-r--r--Swift/Controllers/Roster/ContactRosterItem.h25
-rw-r--r--Swift/Controllers/Roster/LeastCommonSubsequence.h25
-rw-r--r--Swift/Controllers/Roster/Roster.cpp35
-rw-r--r--Swift/Controllers/Roster/Roster.h10
-rw-r--r--Swift/Controllers/Roster/RosterController.cpp46
-rw-r--r--Swift/Controllers/Roster/RosterController.h17
-rw-r--r--Swift/Controllers/Roster/RosterItemOperation.h8
-rw-r--r--Swift/Controllers/Roster/SetAvatar.h7
-rw-r--r--Swift/Controllers/Roster/TableRoster.cpp7
-rw-r--r--Swift/Controllers/Roster/TableRoster.h5
-rw-r--r--Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp26
-rw-r--r--Swift/Controllers/Roster/UnitTest/TableRosterTest.cpp2
-rw-r--r--Swift/Controllers/SConscript17
-rw-r--r--Swift/Controllers/SettingConstants.cpp6
-rw-r--r--Swift/Controllers/SettingConstants.h6
-rw-r--r--Swift/Controllers/Settings/DummySettingsProvider.h12
-rw-r--r--Swift/Controllers/Settings/UnitTest/SettingsProviderHierachyTest.cpp2
-rw-r--r--Swift/Controllers/ShowProfileController.cpp74
-rw-r--r--Swift/Controllers/ShowProfileController.h36
-rw-r--r--Swift/Controllers/SoundEventController.cpp19
-rw-r--r--Swift/Controllers/SoundEventController.h8
-rw-r--r--Swift/Controllers/SoundPlayer.h6
-rw-r--r--Swift/Controllers/StatusCache.cpp107
-rw-r--r--Swift/Controllers/StatusCache.h40
-rw-r--r--Swift/Controllers/StatusTracker.cpp6
-rw-r--r--Swift/Controllers/StatusTracker.h5
-rw-r--r--Swift/Controllers/StatusUtil.cpp2
-rw-r--r--Swift/Controllers/Storages/AvatarFileStorage.cpp10
-rw-r--r--Swift/Controllers/Storages/AvatarFileStorage.h7
-rw-r--r--Swift/Controllers/Storages/CertificateFileStorage.cpp13
-rw-r--r--Swift/Controllers/Storages/CertificateFileStorage.h6
-rw-r--r--Swift/Controllers/Storages/CertificateFileStorageFactory.h8
-rw-r--r--Swift/Controllers/Storages/FileStorages.cpp13
-rw-r--r--Swift/Controllers/Storages/FileStorages.h7
-rw-r--r--Swift/Controllers/Storages/FileStoragesFactory.h9
-rw-r--r--Swift/Controllers/Storages/VCardFileStorage.cpp9
-rw-r--r--Swift/Controllers/Storages/VCardFileStorage.h7
-rw-r--r--Swift/Controllers/SystemTray.h2
-rw-r--r--Swift/Controllers/Translator.cpp2
-rw-r--r--Swift/Controllers/UIEvents/AddContactUIEvent.h6
-rw-r--r--Swift/Controllers/UIEvents/AddMUCBookmarkUIEvent.h2
-rw-r--r--Swift/Controllers/UIEvents/CreateImpromptuMUCUIEvent.h26
-rw-r--r--Swift/Controllers/UIEvents/EditMUCBookmarkUIEvent.h6
-rw-r--r--Swift/Controllers/UIEvents/InviteToMUCUIEvent.h40
-rw-r--r--Swift/Controllers/UIEvents/JoinMUCUIEvent.h7
-rw-r--r--Swift/Controllers/UIEvents/RemoveMUCBookmarkUIEvent.h2
-rw-r--r--Swift/Controllers/UIEvents/RemoveRosterItemUIEvent.h6
-rw-r--r--Swift/Controllers/UIEvents/RequestAdHocUIEvent.h2
-rw-r--r--Swift/Controllers/UIEvents/RequestAddUserDialogUIEvent.h8
-rw-r--r--Swift/Controllers/UIEvents/RequestBlockListDialogUIEvent.h16
-rw-r--r--Swift/Controllers/UIEvents/RequestChangeBlockStateUIEvent.h37
-rw-r--r--Swift/Controllers/UIEvents/RequestChatUIEvent.h2
-rw-r--r--Swift/Controllers/UIEvents/RequestHighlightEditorUIEvent.h16
-rw-r--r--Swift/Controllers/UIEvents/RequestInviteToMUCUIEvent.h35
-rw-r--r--Swift/Controllers/UIEvents/RequestWhiteboardUIEvent.h2
-rw-r--r--Swift/Controllers/UIEvents/ShowProfileForRosterItemUIEvent.h25
-rw-r--r--Swift/Controllers/UIEvents/ShowWhiteboardUIEvent.h2
-rw-r--r--Swift/Controllers/UIEvents/UIEventStream.h2
-rw-r--r--Swift/Controllers/UIInterfaces/AdHocCommandWindow.h2
-rw-r--r--Swift/Controllers/UIInterfaces/BlockListEditorWidget.h32
-rw-r--r--Swift/Controllers/UIInterfaces/BlockListEditorWidgetFactory.h20
-rw-r--r--Swift/Controllers/UIInterfaces/ChatListWindow.h20
-rw-r--r--Swift/Controllers/UIInterfaces/ChatWindow.h99
-rw-r--r--Swift/Controllers/UIInterfaces/ChatWindowFactory.h2
-rw-r--r--Swift/Controllers/UIInterfaces/ContactEditWindowFactory.h2
-rw-r--r--Swift/Controllers/UIInterfaces/EventWindow.h2
-rw-r--r--Swift/Controllers/UIInterfaces/EventWindowFactory.h2
-rw-r--r--Swift/Controllers/UIInterfaces/HighlightEditorWidget.h22
-rw-r--r--Swift/Controllers/UIInterfaces/HighlightEditorWidgetFactory.h20
-rw-r--r--Swift/Controllers/UIInterfaces/HistoryWindow.h2
-rw-r--r--Swift/Controllers/UIInterfaces/HistoryWindowFactory.h2
-rw-r--r--Swift/Controllers/UIInterfaces/InviteToChatWindow.h30
-rw-r--r--Swift/Controllers/UIInterfaces/JoinMUCWindow.h2
-rw-r--r--Swift/Controllers/UIInterfaces/JoinMUCWindowFactory.h2
-rw-r--r--Swift/Controllers/UIInterfaces/LoginWindow.h2
-rw-r--r--Swift/Controllers/UIInterfaces/LoginWindowFactory.h2
-rw-r--r--Swift/Controllers/UIInterfaces/MUCSearchWindow.h2
-rw-r--r--Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h2
-rw-r--r--Swift/Controllers/UIInterfaces/MainWindow.h3
-rw-r--r--Swift/Controllers/UIInterfaces/MainWindowFactory.h2
-rw-r--r--Swift/Controllers/UIInterfaces/ProfileWindow.h7
-rw-r--r--Swift/Controllers/UIInterfaces/ProfileWindowFactory.h2
-rw-r--r--Swift/Controllers/UIInterfaces/UIFactory.h6
-rw-r--r--Swift/Controllers/UIInterfaces/UserSearchWindow.h19
-rw-r--r--Swift/Controllers/UIInterfaces/UserSearchWindowFactory.h2
-rw-r--r--Swift/Controllers/UIInterfaces/WhiteboardWindowFactory.h2
-rw-r--r--Swift/Controllers/UIInterfaces/XMLConsoleWidgetFactory.h2
-rw-r--r--Swift/Controllers/UnitTest/ChatMessageSummarizerTest.cpp6
-rw-r--r--Swift/Controllers/UnitTest/HighlightRuleTest.cpp318
-rw-r--r--Swift/Controllers/UnitTest/MockChatWindow.h89
-rw-r--r--Swift/Controllers/UnitTest/MockMainWindow.h21
-rw-r--r--Swift/Controllers/UnitTest/MockMainWindowFactory.h6
-rw-r--r--Swift/Controllers/XMPPEvents/ErrorEvent.h8
-rw-r--r--Swift/Controllers/XMPPEvents/EventController.cpp5
-rw-r--r--Swift/Controllers/XMPPEvents/MUCInviteEvent.h4
-rw-r--r--Swift/Controllers/XMPPEvents/MessageEvent.h2
-rw-r--r--Swift/Controllers/XMPPEvents/StanzaEvent.h8
-rw-r--r--Swift/Controllers/XMPPEvents/SubscriptionRequestEvent.h12
146 files changed, 4144 insertions, 719 deletions
diff --git a/Swift/Controllers/BlockListController.cpp b/Swift/Controllers/BlockListController.cpp
new file mode 100644
index 0000000..e7bc45d
--- /dev/null
+++ b/Swift/Controllers/BlockListController.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <Swift/Controllers/BlockListController.h>
+
+#include <boost/bind.hpp>
+
+#include <Swiften/Client/ClientBlockListManager.h>
+
+#include <Swiften/Base/foreach.h>
+#include <Swiften/Base/format.h>
+#include <Swift/Controllers/Intl.h>
+#include <Swift/Controllers/UIEvents/RequestChangeBlockStateUIEvent.h>
+#include <Swift/Controllers/UIEvents/RequestBlockListDialogUIEvent.h>
+#include <Swift/Controllers/XMPPEvents/ErrorEvent.h>
+#include <Swift/Controllers/UIInterfaces/BlockListEditorWidget.h>
+#include <Swift/Controllers/XMPPEvents/EventController.h>
+
+namespace Swift {
+
+BlockListController::BlockListController(ClientBlockListManager* blockListManager, UIEventStream* uiEventStream, BlockListEditorWidgetFactory* blockListEditorWidgetFactory, EventController* eventController) : blockListManager_(blockListManager), blockListEditorWidgetFactory_(blockListEditorWidgetFactory), blockListEditorWidget_(0), eventController_(eventController), remainingRequests_(0) {
+ uiEventStream->onUIEvent.connect(boost::bind(&BlockListController::handleUIEvent, this, _1));
+ blockListManager_->getBlockList()->onItemAdded.connect(boost::bind(&BlockListController::handleBlockListChanged, this));
+ blockListManager_->getBlockList()->onItemRemoved.connect(boost::bind(&BlockListController::handleBlockListChanged, this));
+}
+
+BlockListController::~BlockListController() {
+ blockListManager_->getBlockList()->onItemAdded.disconnect(boost::bind(&BlockListController::handleBlockListChanged, this));
+ blockListManager_->getBlockList()->onItemRemoved.disconnect(boost::bind(&BlockListController::handleBlockListChanged, this));
+}
+
+void BlockListController::blockListDifferences(const std::vector<JID> &newBlockList, std::vector<JID> &jidsToUnblock, std::vector<JID> &jidsToBlock) const {
+ foreach (const JID& jid, blockListBeforeEdit) {
+ if (std::find(newBlockList.begin(), newBlockList.end(), jid) == newBlockList.end()) {
+ jidsToUnblock.push_back(jid);
+ }
+ }
+
+ foreach (const JID& jid, newBlockList) {
+ if (std::find(blockListBeforeEdit.begin(), blockListBeforeEdit.end(), jid) == blockListBeforeEdit.end()) {
+ jidsToBlock.push_back(jid);
+ }
+ }
+}
+
+void BlockListController::handleUIEvent(boost::shared_ptr<UIEvent> rawEvent) {
+ // handle UI dialog
+ boost::shared_ptr<RequestBlockListDialogUIEvent> requestDialogEvent = boost::dynamic_pointer_cast<RequestBlockListDialogUIEvent>(rawEvent);
+ if (requestDialogEvent != NULL) {
+ if (blockListEditorWidget_ == NULL) {
+ blockListEditorWidget_ = blockListEditorWidgetFactory_->createBlockListEditorWidget();
+ blockListEditorWidget_->onSetNewBlockList.connect(boost::bind(&BlockListController::handleSetNewBlockList, this, _1));
+ }
+ blockListBeforeEdit = blockListManager_->getBlockList()->getItems();
+ blockListEditorWidget_->setCurrentBlockList(blockListBeforeEdit);
+ blockListEditorWidget_->show();
+ return;
+ }
+
+ // handle block state change
+ boost::shared_ptr<RequestChangeBlockStateUIEvent> changeStateEvent = boost::dynamic_pointer_cast<RequestChangeBlockStateUIEvent>(rawEvent);
+ if (changeStateEvent != NULL) {
+ if (changeStateEvent->getBlockState() == RequestChangeBlockStateUIEvent::Blocked) {
+ GenericRequest<BlockPayload>::ref blockRequest = blockListManager_->createBlockJIDRequest(changeStateEvent->getContact());
+ blockRequest->onResponse.connect(boost::bind(&BlockListController::handleBlockResponse, this, blockRequest, _1, _2, std::vector<JID>(1, changeStateEvent->getContact()), false));
+ blockRequest->send();
+ } else if (changeStateEvent->getBlockState() == RequestChangeBlockStateUIEvent::Unblocked) {
+ GenericRequest<UnblockPayload>::ref unblockRequest = blockListManager_->createUnblockJIDRequest(changeStateEvent->getContact());
+ unblockRequest->onResponse.connect(boost::bind(&BlockListController::handleUnblockResponse, this, unblockRequest, _1, _2, std::vector<JID>(1, changeStateEvent->getContact()), false));
+ unblockRequest->send();
+ }
+ return;
+ }
+}
+
+void BlockListController::handleBlockResponse(GenericRequest<BlockPayload>::ref request, boost::shared_ptr<BlockPayload>, ErrorPayload::ref error, const std::vector<JID>& jids, bool originEditor) {
+ if (error) {
+ std::string errorMessage;
+ // FIXME: Handle reporting of list of JIDs in a translatable way.
+ errorMessage = str(format(QT_TRANSLATE_NOOP("", "Failed to block %1%.")) % jids.at(0).toString());
+ if (!error->getText().empty()) {
+ errorMessage = str(format(QT_TRANSLATE_NOOP("", "%1%: %2%.")) % errorMessage % error->getText());
+ }
+ eventController_->handleIncomingEvent(boost::make_shared<ErrorEvent>(request->getReceiver(), errorMessage));
+ }
+ if (originEditor) {
+ remainingRequests_--;
+ if (blockListEditorWidget_ && (remainingRequests_ == 0)) {
+ blockListEditorWidget_->setBusy(false);
+ }
+ }
+}
+
+void BlockListController::handleUnblockResponse(GenericRequest<UnblockPayload>::ref request, boost::shared_ptr<UnblockPayload>, ErrorPayload::ref error, const std::vector<JID>& jids, bool originEditor) {
+ if (error) {
+ std::string errorMessage;
+ // FIXME: Handle reporting of list of JIDs in a translatable way.
+ errorMessage = str(format(QT_TRANSLATE_NOOP("", "Failed to unblock %1%.")) % jids.at(0).toString());
+ if (!error->getText().empty()) {
+ errorMessage = str(format(QT_TRANSLATE_NOOP("", "%1%: %2%.")) % errorMessage % error->getText());
+ }
+ eventController_->handleIncomingEvent(boost::make_shared<ErrorEvent>(request->getReceiver(), errorMessage));
+ }
+ if (originEditor) {
+ remainingRequests_--;
+ if (blockListEditorWidget_ && (remainingRequests_ == 0)) {
+ blockListEditorWidget_->setBusy(false);
+ }
+ }
+}
+
+void BlockListController::handleSetNewBlockList(const std::vector<JID> &newBlockList) {
+ std::vector<JID> jidsToBlock;
+ std::vector<JID> jidsToUnblock;
+
+ blockListDifferences(newBlockList, jidsToUnblock, jidsToBlock);
+
+ if (!jidsToBlock.empty()) {
+ remainingRequests_++;
+ GenericRequest<BlockPayload>::ref blockRequest = blockListManager_->createBlockJIDsRequest(jidsToBlock);
+ blockRequest->onResponse.connect(boost::bind(&BlockListController::handleBlockResponse, this, blockRequest, _1, _2, jidsToBlock, true));
+ blockRequest->send();
+ }
+ if (!jidsToUnblock.empty()) {
+ remainingRequests_++;
+ GenericRequest<UnblockPayload>::ref unblockRequest = blockListManager_->createUnblockJIDsRequest(jidsToUnblock);
+ unblockRequest->onResponse.connect(boost::bind(&BlockListController::handleUnblockResponse, this, unblockRequest, _1, _2, jidsToUnblock, true));
+ unblockRequest->send();
+ }
+ if (!jidsToBlock.empty() || jidsToUnblock.empty()) {
+ assert(blockListEditorWidget_);
+ blockListEditorWidget_->setBusy(true);
+ }
+}
+
+void BlockListController::handleBlockListChanged() {
+ if (blockListEditorWidget_) {
+ std::vector<JID> jidsToBlock;
+ std::vector<JID> jidsToUnblock;
+
+ blockListDifferences(blockListEditorWidget_->getCurrentBlockList(), jidsToUnblock, jidsToBlock);
+ blockListBeforeEdit = blockListManager_->getBlockList()->getItems();
+
+ foreach (const JID& jid, jidsToBlock) {
+ blockListBeforeEdit.push_back(jid);
+ }
+
+ foreach (const JID& jid, jidsToUnblock) {
+ blockListBeforeEdit.erase(std::remove(blockListBeforeEdit.begin(), blockListBeforeEdit.end(), jid), blockListBeforeEdit.end());;
+ }
+
+ blockListEditorWidget_->setCurrentBlockList(blockListBeforeEdit);
+ }
+}
+
+}
diff --git a/Swift/Controllers/BlockListController.h b/Swift/Controllers/BlockListController.h
new file mode 100644
index 0000000..4c9caad
--- /dev/null
+++ b/Swift/Controllers/BlockListController.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Queries/GenericRequest.h>
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
+#include <Swift/Controllers/UIInterfaces/BlockListEditorWidgetFactory.h>
+
+namespace Swift {
+
+class BlockPayload;
+class UnblockPayload;
+class ClientBlockListManager;
+class EventController;
+
+class BlockListController {
+public:
+ BlockListController(ClientBlockListManager* blockListManager, UIEventStream* uiEventStream, BlockListEditorWidgetFactory* blockListEditorWidgetFactory, EventController* eventController);
+ ~BlockListController();
+
+private:
+ void blockListDifferences(const std::vector<JID> &newBlockList, std::vector<JID>& jidsToUnblock, std::vector<JID>& jidsToBlock) const;
+
+ void handleUIEvent(boost::shared_ptr<UIEvent> event);
+
+ void handleBlockResponse(GenericRequest<BlockPayload>::ref, boost::shared_ptr<BlockPayload>, ErrorPayload::ref error, const std::vector<JID>& jids, bool originEditor);
+ void handleUnblockResponse(GenericRequest<UnblockPayload>::ref, boost::shared_ptr<UnblockPayload>, ErrorPayload::ref error, const std::vector<JID>& jids, bool originEditor);
+
+ void handleSetNewBlockList(const std::vector<JID>& newBlockList);
+
+ void handleBlockListChanged();
+
+private:
+ ClientBlockListManager* blockListManager_;
+ BlockListEditorWidgetFactory* blockListEditorWidgetFactory_;
+ BlockListEditorWidget* blockListEditorWidget_;
+ EventController* eventController_;
+ std::vector<JID> blockListBeforeEdit;
+ int remainingRequests_;
+};
+
+}
diff --git a/Swift/Controllers/Chat/AutoAcceptMUCInviteDecider.h b/Swift/Controllers/Chat/AutoAcceptMUCInviteDecider.h
new file mode 100644
index 0000000..0f85a8a
--- /dev/null
+++ b/Swift/Controllers/Chat/AutoAcceptMUCInviteDecider.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Roster/XMPPRoster.h>
+#include <Swiften/Elements/MUCInvitationPayload.h>
+#include <Swift/Controllers/Settings/SettingsProvider.h>
+#include <Swift/Controllers/SettingConstants.h>
+
+namespace Swift {
+ class AutoAcceptMUCInviteDecider {
+ public:
+ AutoAcceptMUCInviteDecider(const JID& domain, XMPPRoster* roster, SettingsProvider* settings) : domain_(domain), roster_(roster), settings_(settings) {
+ }
+
+ bool isAutoAcceptedInvite(const JID& from, MUCInvitationPayload::ref invite) {
+ if (!invite->getIsImpromptu() && !invite->getIsContinuation()) {
+ return false;
+ }
+
+ std::string auto_accept_mode = settings_->getSetting(SettingConstants::INVITE_AUTO_ACCEPT_MODE);
+ if (auto_accept_mode == "no") {
+ return false;
+ } else if (auto_accept_mode == "presence") {
+ return roster_->getSubscriptionStateForJID(from) == RosterItemPayload::From || roster_->getSubscriptionStateForJID(from) == RosterItemPayload::Both;
+ } else if (auto_accept_mode == "domain") {
+ return roster_->getSubscriptionStateForJID(from) == RosterItemPayload::From || roster_->getSubscriptionStateForJID(from) == RosterItemPayload::Both || from.getDomain() == domain_;
+ } else {
+ assert(false);
+ }
+ }
+
+ private:
+ JID domain_;
+ XMPPRoster* roster_;
+ SettingsProvider* settings_;
+ };
+}
diff --git a/Swift/Controllers/Chat/ChatController.cpp b/Swift/Controllers/Chat/ChatController.cpp
index 16b22fe..13fd22b 100644
--- a/Swift/Controllers/Chat/ChatController.cpp
+++ b/Swift/Controllers/Chat/ChatController.cpp
@@ -1,47 +1,55 @@
/*
- * Copyright (c) 2010-2012 Kevin Smith
+ * Copyright (c) 2010-2013 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#include "Swift/Controllers/Chat/ChatController.h"
+#include <Swift/Controllers/Chat/ChatController.h>
#include <boost/bind.hpp>
#include <boost/smart_ptr/make_shared.hpp>
#include <stdio.h>
-#include <Swift/Controllers/Intl.h>
#include <Swiften/Base/format.h>
#include <Swiften/Base/Algorithm.h>
#include <Swiften/Avatars/AvatarManager.h>
#include <Swiften/Chat/ChatStateNotifier.h>
#include <Swiften/Chat/ChatStateTracker.h>
#include <Swiften/Client/StanzaChannel.h>
-#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h>
#include <Swiften/Client/NickResolver.h>
+#include <Swiften/Disco/EntityCapsProvider.h>
+#include <Swiften/Base/foreach.h>
+#include <Swiften/Base/DateTime.h>
+#include <Swiften/Elements/DeliveryReceipt.h>
+#include <Swiften/Elements/DeliveryReceiptRequest.h>
+#include <Swiften/Elements/Idle.h>
+#include <Swiften/Base/Log.h>
+#include <Swiften/Client/ClientBlockListManager.h>
+
+#include <Swift/Controllers/Intl.h>
+#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h>
#include <Swift/Controllers/XMPPEvents/EventController.h>
#include <Swift/Controllers/FileTransfer/FileTransferController.h>
#include <Swift/Controllers/StatusUtil.h>
-#include <Swiften/Disco/EntityCapsProvider.h>
-#include <Swiften/Base/foreach.h>
#include <Swift/Controllers/UIEvents/UIEventStream.h>
#include <Swift/Controllers/UIEvents/SendFileUIEvent.h>
#include <Swift/Controllers/UIEvents/AcceptWhiteboardSessionUIEvent.h>
#include <Swift/Controllers/UIEvents/CancelWhiteboardSessionUIEvent.h>
#include <Swift/Controllers/UIEvents/ShowWhiteboardUIEvent.h>
-#include <Swiften/Elements/DeliveryReceipt.h>
-#include <Swiften/Elements/DeliveryReceiptRequest.h>
+#include <Swift/Controllers/UIEvents/RequestChangeBlockStateUIEvent.h>
+#include <Swift/Controllers/UIEvents/InviteToMUCUIEvent.h>
+#include <Swift/Controllers/UIEvents/RequestInviteToMUCUIEvent.h>
#include <Swift/Controllers/SettingConstants.h>
-
-#include <Swiften/Base/Log.h>
+#include <Swift/Controllers/Highlighter.h>
+#include <Swift/Controllers/Chat/ChatMessageParser.h>
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, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, bool userWantsReceipts, SettingsProvider* settings, HistoryController* historyController, MUCRegistry* mucRegistry)
- : ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, contact, presenceOracle, avatarManager, useDelayForLatency, eventStream, eventController, timerFactory, entityCapsProvider, historyController, mucRegistry), eventStream_(eventStream), userWantsReceipts_(userWantsReceipts), settings_(settings) {
+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, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, bool userWantsReceipts, SettingsProvider* settings, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, ChatMessageParser* chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider)
+ : ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, contact, presenceOracle, avatarManager, useDelayForLatency, eventStream, eventController, timerFactory, entityCapsProvider, historyController, mucRegistry, highlightManager, chatMessageParser, autoAcceptMUCInviteDecider), eventStream_(eventStream), userWantsReceipts_(userWantsReceipts), settings_(settings), clientBlockListManager_(clientBlockListManager) {
isInMUC_ = isInMUC;
lastWasPresence_ = false;
chatStateNotifier_ = new ChatStateNotifier(stanzaChannel, contact, entityCapsProvider);
@@ -62,6 +70,10 @@ ChatController::ChatController(const JID& self, StanzaChannel* stanzaChannel, IQ
startMessage = str(format(QT_TRANSLATE_NOOP("", "Starting chat with %1% - %2%")) % nick % contact.toBare().toString());
theirPresence = contact.isBare() ? presenceOracle->getHighestPriorityPresence(contact.toBare()) : presenceOracle->getLastPresence(contact);
}
+ Idle::ref idle;
+ if (theirPresence && (idle = theirPresence->getPayload<Idle>())) {
+ startMessage += str(format(QT_TRANSLATE_NOOP("", ", who has been idle since %1%")) % dateTimeToLocalString(idle->getSince()));
+ }
startMessage += ": " + statusShowTypeToFriendlyName(theirPresence ? theirPresence->getShow() : StatusShow::None);
if (theirPresence && !theirPresence->getStatus().empty()) {
startMessage += " (" + theirPresence->getStatus() + ")";
@@ -69,7 +81,7 @@ ChatController::ChatController(const JID& self, StanzaChannel* stanzaChannel, IQ
lastShownStatus_ = theirPresence ? theirPresence->getShow() : StatusShow::None;
chatStateNotifier_->setContactIsOnline(theirPresence && theirPresence->getType() == Presence::Available);
startMessage += ".";
- chatWindow_->addSystemMessage(startMessage);
+ chatWindow_->addSystemMessage(chatMessageParser_->parseMessageBody(startMessage), ChatWindow::DefaultDirection);
chatWindow_->onUserTyping.connect(boost::bind(&ChatStateNotifier::setUserIsTyping, chatStateNotifier_));
chatWindow_->onUserCancelsTyping.connect(boost::bind(&ChatStateNotifier::userCancelledNewMessage, chatStateNotifier_));
chatWindow_->onFileTransferStart.connect(boost::bind(&ChatController::handleFileTransferStart, this, _1, _2));
@@ -79,9 +91,13 @@ ChatController::ChatController(const JID& self, StanzaChannel* stanzaChannel, IQ
chatWindow_->onWhiteboardSessionAccept.connect(boost::bind(&ChatController::handleWhiteboardSessionAccept, this));
chatWindow_->onWhiteboardSessionCancel.connect(boost::bind(&ChatController::handleWhiteboardSessionCancel, this));
chatWindow_->onWhiteboardWindowShow.connect(boost::bind(&ChatController::handleWhiteboardWindowShow, this));
+ chatWindow_->onBlockUserRequest.connect(boost::bind(&ChatController::handleBlockUserRequest, this));
+ chatWindow_->onUnblockUserRequest.connect(boost::bind(&ChatController::handleUnblockUserRequest, this));
+ chatWindow_->onInviteToChat.connect(boost::bind(&ChatController::handleInviteToChat, this, _1));
handleBareJIDCapsChanged(toJID_);
settings_->onSettingChanged.connect(boost::bind(&ChatController::handleSettingChanged, this, _1));
+ eventStream_->onUIEvent.connect(boost::bind(&ChatController::handleUIEvent, this, _1));
}
void ChatController::handleContactNickChanged(const JID& jid, const std::string& /*oldNick*/) {
@@ -91,6 +107,7 @@ void ChatController::handleContactNickChanged(const JID& jid, const std::string&
}
ChatController::~ChatController() {
+ eventStream_->onUIEvent.disconnect(boost::bind(&ChatController::handleUIEvent, this, _1));
settings_->onSettingChanged.disconnect(boost::bind(&ChatController::handleSettingChanged, this, _1));
nickResolver_->onNickChanged.disconnect(boost::bind(&ChatController::handleContactNickChanged, this, _1, _2));
delete chatStateNotifier_;
@@ -139,6 +156,19 @@ void ChatController::setToJID(const JID& jid) {
handleBareJIDCapsChanged(toJID_);
}
+void ChatController::setAvailableServerFeatures(boost::shared_ptr<DiscoInfo> info) {
+ ChatControllerBase::setAvailableServerFeatures(info);
+ if (iqRouter_->isAvailable() && info->hasFeature(DiscoInfo::BlockingCommandFeature)) {
+ boost::shared_ptr<BlockList> blockList = clientBlockListManager_->getBlockList();
+
+ blockingOnStateChangedConnection_ = blockList->onStateChanged.connect(boost::bind(&ChatController::handleBlockingStateChanged, this));
+ blockingOnItemAddedConnection_ = blockList->onItemAdded.connect(boost::bind(&ChatController::handleBlockingItemAdded, this, _1));
+ blockingOnItemRemovedConnection_ = blockList->onItemRemoved.connect(boost::bind(&ChatController::handleBlockingItemRemoved, this, _1));
+
+ handleBlockingStateChanged();
+ }
+}
+
bool ChatController::isIncomingMessageFromMe(boost::shared_ptr<Message>) {
return false;
}
@@ -174,8 +204,11 @@ void ChatController::preHandleIncomingMessage(boost::shared_ptr<MessageEvent> me
}
}
-void ChatController::postHandleIncomingMessage(boost::shared_ptr<MessageEvent> messageEvent) {
+void ChatController::postHandleIncomingMessage(boost::shared_ptr<MessageEvent> messageEvent, const HighlightAction& highlight) {
eventController_->handleIncomingEvent(messageEvent);
+ if (!messageEvent->getConcluded()) {
+ highlighter_->handleHighlightAction(highlight);
+ }
}
@@ -207,13 +240,72 @@ void ChatController::checkForDisplayingDisplayReceiptsAlert() {
}
}
+void ChatController::handleBlockingStateChanged() {
+ boost::shared_ptr<BlockList> blockList = clientBlockListManager_->getBlockList();
+ if (blockList->getState() == BlockList::Available) {
+ if (isInMUC_ ? blockList->isBlocked(toJID_) : blockList->isBlocked(toJID_.toBare())) {
+ chatWindow_->setAlert(QT_TRANSLATE_NOOP("", "You've currently blocked this contact. To continue your conversation you have to unblock the contact first."));
+ chatWindow_->setInputEnabled(false);
+ chatWindow_->setBlockingState(ChatWindow::IsBlocked);
+ } else {
+ chatWindow_->setBlockingState(ChatWindow::IsUnblocked);
+ }
+ }
+}
+
+void ChatController::handleBlockingItemAdded(const JID& jid) {
+ if (toJID_ == (isInMUC_ ? jid: jid.toBare())) {
+ chatWindow_->setAlert(QT_TRANSLATE_NOOP("", "You've currently blocked this contact. To continue your conversation you have to unblock the contact first."));
+ chatWindow_->setInputEnabled(false);
+ chatWindow_->setBlockingState(ChatWindow::IsBlocked);
+ }
+}
+
+void ChatController::handleBlockingItemRemoved(const JID& jid) {
+ if (toJID_ == (isInMUC_ ? jid: jid.toBare())) {
+ // FIXME: Support for different types of alerts.
+ chatWindow_->cancelAlert();
+ chatWindow_->setInputEnabled(true);
+ chatWindow_->setBlockingState(ChatWindow::IsUnblocked);
+ }
+}
+
+void ChatController::handleBlockUserRequest() {
+ if (isInMUC_) {
+ eventStream_->send(boost::make_shared<RequestChangeBlockStateUIEvent>(RequestChangeBlockStateUIEvent::Blocked, toJID_));
+ } else {
+ eventStream_->send(boost::make_shared<RequestChangeBlockStateUIEvent>(RequestChangeBlockStateUIEvent::Blocked, toJID_.toBare()));
+ }
+}
+
+void ChatController::handleUnblockUserRequest() {
+ if (isInMUC_) {
+ eventStream_->send(boost::make_shared<RequestChangeBlockStateUIEvent>(RequestChangeBlockStateUIEvent::Unblocked, toJID_));
+ } else {
+ eventStream_->send(boost::make_shared<RequestChangeBlockStateUIEvent>(RequestChangeBlockStateUIEvent::Unblocked, toJID_.toBare()));
+ }
+}
+
+void ChatController::handleInviteToChat(const std::vector<JID>& droppedJIDs) {
+ boost::shared_ptr<UIEvent> event(new RequestInviteToMUCUIEvent(toJID_.toBare(), droppedJIDs));
+ eventStream_->send(event);
+}
+
+void ChatController::handleUIEvent(boost::shared_ptr<UIEvent> event) {
+ boost::shared_ptr<InviteToMUCUIEvent> inviteEvent = boost::dynamic_pointer_cast<InviteToMUCUIEvent>(event);
+ if (inviteEvent && inviteEvent->getRoom() == toJID_.toBare()) {
+ onConvertToMUC(detachChatWindow(), inviteEvent->getInvites(), inviteEvent->getReason());
+ }
+}
+
+
void ChatController::postSendMessage(const std::string& body, boost::shared_ptr<Stanza> sentStanza) {
boost::shared_ptr<Replace> replace = sentStanza->getPayload<Replace>();
if (replace) {
eraseIf(unackedStanzas_, PairSecondEquals<boost::shared_ptr<Stanza>, std::string>(myLastMessageUIID_));
- replaceMessage(body, myLastMessageUIID_, boost::posix_time::microsec_clock::universal_time());
+ replaceMessage(body, myLastMessageUIID_, boost::posix_time::microsec_clock::universal_time(), HighlightAction());
} else {
- myLastMessageUIID_ = addMessage(body, QT_TRANSLATE_NOOP("", "me"), true, labelsEnabled_ ? chatWindow_->getSelectedSecurityLabel().getLabel() : boost::shared_ptr<SecurityLabel>(), std::string(avatarManager_->getAvatarPath(selfJID_).string()), boost::posix_time::microsec_clock::universal_time());
+ myLastMessageUIID_ = addMessage(body, QT_TRANSLATE_NOOP("", "me"), true, labelsEnabled_ ? chatWindow_->getSelectedSecurityLabel().getLabel() : boost::shared_ptr<SecurityLabel>(), avatarManager_->getAvatarPath(selfJID_), boost::posix_time::microsec_clock::universal_time(), HighlightAction());
}
if (stanzaChannel_->getStreamManagementEnabled() && !myLastMessageUIID_.empty() ) {
@@ -288,7 +380,7 @@ void ChatController::handleFileTransferStart(std::string id, std::string descrip
}
void ChatController::handleFileTransferAccept(std::string id, std::string filename) {
- SWIFT_LOG(debug) "handleFileTransferAccept(" << id << ", " << filename << ")" << std::endl;
+ SWIFT_LOG(debug) << "handleFileTransferAccept(" << id << ", " << filename << ")" << std::endl;
if (ftControllers.find(id) != ftControllers.end()) {
ftControllers[id]->accept(filename);
} else {
@@ -332,6 +424,11 @@ std::string ChatController::getStatusChangeString(boost::shared_ptr<Presence> pr
response = QT_TRANSLATE_NOOP("", "%1% is now busy");
}
}
+ Idle::ref idle;
+ if ((idle = presence->getPayload<Idle>())) {
+ response += str(format(QT_TRANSLATE_NOOP("", " and has been idle since %1%")) % dateTimeToLocalString(idle->getSince()));
+ }
+
if (!response.empty()) {
response = str(format(response) % nick);
}
@@ -366,9 +463,9 @@ void ChatController::handlePresenceChange(boost::shared_ptr<Presence> newPresenc
std::string newStatusChangeString = getStatusChangeString(newPresence);
if (newStatusChangeString != lastStatusChangeString_) {
if (lastWasPresence_) {
- chatWindow_->replaceLastMessage(newStatusChangeString);
+ chatWindow_->replaceLastMessage(chatMessageParser_->parseMessageBody(newStatusChangeString));
} else {
- chatWindow_->addPresenceMessage(newStatusChangeString);
+ chatWindow_->addPresenceMessage(chatMessageParser_->parseMessageBody(newStatusChangeString), ChatWindow::DefaultDirection);
}
lastStatusChangeString_ = newStatusChangeString;
lastWasPresence_ = true;
@@ -393,4 +490,10 @@ void ChatController::logMessage(const std::string& message, const JID& fromJID,
}
}
+ChatWindow* ChatController::detachChatWindow() {
+ chatWindow_->onUserTyping.disconnect(boost::bind(&ChatStateNotifier::setUserIsTyping, chatStateNotifier_));
+ chatWindow_->onUserCancelsTyping.disconnect(boost::bind(&ChatStateNotifier::userCancelledNewMessage, chatStateNotifier_));
+ return ChatControllerBase::detachChatWindow();
+}
+
}
diff --git a/Swift/Controllers/Chat/ChatController.h b/Swift/Controllers/Chat/ChatController.h
index 66ec37d..f8b6d8b 100644
--- a/Swift/Controllers/Chat/ChatController.h
+++ b/Swift/Controllers/Chat/ChatController.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2012 Kevin Smith
+ * Copyright (c) 2010-2013 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -22,17 +22,22 @@ namespace Swift {
class FileTransferController;
class SettingsProvider;
class HistoryController;
+ class HighlightManager;
+ class ClientBlockListManager;
+ class UIEvent;
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, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, bool userWantsReceipts, SettingsProvider* settings, HistoryController* historyController, MUCRegistry* mucRegistry);
+ 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, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, bool userWantsReceipts, SettingsProvider* settings, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, ChatMessageParser* chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider);
virtual ~ChatController();
virtual void setToJID(const JID& jid);
+ virtual void setAvailableServerFeatures(boost::shared_ptr<DiscoInfo> info);
virtual void setOnline(bool online);
virtual void handleNewFileTransferController(FileTransferController* ftc);
virtual void handleWhiteboardSessionRequest(bool senderIsSelf);
virtual void handleWhiteboardStateChange(const ChatWindow::WhiteboardSessionState state);
virtual void setContactIsReceivingPresence(bool /*isReceivingPresence*/);
+ virtual ChatWindow* detachChatWindow();
protected:
void cancelReplaces();
@@ -45,7 +50,7 @@ namespace Swift {
bool isIncomingMessageFromMe(boost::shared_ptr<Message> message);
void postSendMessage(const std::string &body, boost::shared_ptr<Stanza> sentStanza);
void preHandleIncomingMessage(boost::shared_ptr<MessageEvent> messageEvent);
- void postHandleIncomingMessage(boost::shared_ptr<MessageEvent> messageEvent);
+ void postHandleIncomingMessage(boost::shared_ptr<MessageEvent> messageEvent, const HighlightAction&);
void preSendMessageRequest(boost::shared_ptr<Message>);
std::string senderDisplayNameFromMessage(const JID& from);
virtual boost::optional<boost::posix_time::ptime> getMessageTimestamp(boost::shared_ptr<Message>) const;
@@ -66,6 +71,19 @@ namespace Swift {
void handleSettingChanged(const std::string& settingPath);
void checkForDisplayingDisplayReceiptsAlert();
+ void handleBlockingStateChanged();
+ void handleBlockingItemAdded(const JID&);
+ void handleBlockingItemRemoved(const JID&);
+
+ void handleBlockUserRequest();
+ void handleUnblockUserRequest();
+
+ void handleInviteToChat(const std::vector<JID>& droppedJIDs);
+ void handleInviteToMUCWindowDismissed();
+ void handleInviteToMUCWindowCompleted();
+
+ void handleUIEvent(boost::shared_ptr<UIEvent> event);
+
private:
NickResolver* nickResolver_;
ChatStateNotifier* chatStateNotifier_;
@@ -85,6 +103,11 @@ namespace Swift {
std::map<std::string, FileTransferController*> ftControllers;
SettingsProvider* settings_;
std::string lastWbID_;
+
+ ClientBlockListManager* clientBlockListManager_;
+ boost::bsignals::scoped_connection blockingOnStateChangedConnection_;
+ boost::bsignals::scoped_connection blockingOnItemAddedConnection_;
+ boost::bsignals::scoped_connection blockingOnItemRemovedConnection_;
};
}
diff --git a/Swift/Controllers/Chat/ChatControllerBase.cpp b/Swift/Controllers/Chat/ChatControllerBase.cpp
index 50709f7..23137dc 100644
--- a/Swift/Controllers/Chat/ChatControllerBase.cpp
+++ b/Swift/Controllers/Chat/ChatControllerBase.cpp
@@ -1,10 +1,10 @@
/*
- * Copyright (c) 2010-2012 Kevin Smith
+ * Copyright (c) 2010-2013 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#include "Swift/Controllers/Chat/ChatControllerBase.h"
+#include <Swift/Controllers/Chat/ChatControllerBase.h>
#include <sstream>
#include <map>
@@ -13,32 +13,42 @@
#include <boost/shared_ptr.hpp>
#include <boost/smart_ptr/make_shared.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/numeric/conversion/cast.hpp>
#include <boost/algorithm/string.hpp>
-#include <Swift/Controllers/Intl.h>
#include <Swiften/Base/format.h>
+#include <Swiften/Base/Path.h>
#include <Swiften/Base/String.h>
#include <Swiften/Client/StanzaChannel.h>
#include <Swiften/Elements/Delay.h>
#include <Swiften/Elements/MUCInvitationPayload.h>
#include <Swiften/Elements/MUCUserPayload.h>
#include <Swiften/Base/foreach.h>
-#include <Swift/Controllers/XMPPEvents/EventController.h>
#include <Swiften/Disco/EntityCapsProvider.h>
-#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
-#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h>
#include <Swiften/Queries/Requests/GetSecurityLabelsCatalogRequest.h>
#include <Swiften/Avatars/AvatarManager.h>
+
+#include <Swift/Controllers/Intl.h>
+#include <Swift/Controllers/XMPPEvents/EventController.h>
+#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h>
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
+#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
+#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h>
#include <Swift/Controllers/XMPPEvents/MUCInviteEvent.h>
+#include <Swift/Controllers/HighlightManager.h>
+#include <Swift/Controllers/Highlighter.h>
+#include <Swift/Controllers/Chat/AutoAcceptMUCInviteDecider.h>
+#include <Swift/Controllers/Chat/ChatMessageParser.h>
namespace Swift {
-ChatControllerBase::ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, HistoryController* historyController, MUCRegistry* mucRegistry) : selfJID_(self), stanzaChannel_(stanzaChannel), iqRouter_(iqRouter), chatWindowFactory_(chatWindowFactory), toJID_(toJID), labelsEnabled_(false), presenceOracle_(presenceOracle), avatarManager_(avatarManager), useDelayForLatency_(useDelayForLatency), eventController_(eventController), timerFactory_(timerFactory), entityCapsProvider_(entityCapsProvider), historyController_(historyController), mucRegistry_(mucRegistry) {
+ChatControllerBase::ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ChatMessageParser* chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider) : selfJID_(self), stanzaChannel_(stanzaChannel), iqRouter_(iqRouter), chatWindowFactory_(chatWindowFactory), toJID_(toJID), labelsEnabled_(false), presenceOracle_(presenceOracle), avatarManager_(avatarManager), useDelayForLatency_(useDelayForLatency), eventController_(eventController), timerFactory_(timerFactory), entityCapsProvider_(entityCapsProvider), historyController_(historyController), mucRegistry_(mucRegistry), chatMessageParser_(chatMessageParser), autoAcceptMUCInviteDecider_(autoAcceptMUCInviteDecider), eventStream_(eventStream) {
chatWindow_ = chatWindowFactory_->createChatWindow(toJID, eventStream);
chatWindow_->onAllMessagesRead.connect(boost::bind(&ChatControllerBase::handleAllMessagesRead, this));
chatWindow_->onSendMessageRequest.connect(boost::bind(&ChatControllerBase::handleSendMessageRequest, this, _1, _2));
chatWindow_->onLogCleared.connect(boost::bind(&ChatControllerBase::handleLogCleared, this));
entityCapsProvider_->onCapsChanged.connect(boost::bind(&ChatControllerBase::handleCapsChanged, this, _1));
+ highlighter_ = highlightManager->createHighlighter();
setOnline(stanzaChannel->isAvailable() && iqRouter->isAvailable());
createDayChangeTimer();
}
@@ -51,17 +61,29 @@ void ChatControllerBase::handleLogCleared() {
cancelReplaces();
}
+ChatWindow* ChatControllerBase::detachChatWindow() {
+ ChatWindow* chatWindow = chatWindow_;
+ chatWindow_ = NULL;
+ return chatWindow;
+}
+
void ChatControllerBase::handleCapsChanged(const JID& jid) {
if (jid.compare(toJID_, JID::WithoutResource) == 0) {
handleBareJIDCapsChanged(jid);
}
}
+void ChatControllerBase::setCanStartImpromptuChats(bool supportsImpromptu) {
+ if (chatWindow_) {
+ chatWindow_->setCanInitiateImpromptuChats(supportsImpromptu);
+ }
+}
+
void ChatControllerBase::createDayChangeTimer() {
if (timerFactory_) {
boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
boost::posix_time::ptime midnight(now.date() + boost::gregorian::days(1));
- long millisecondsUntilMidnight = (midnight - now).total_milliseconds();
+ int millisecondsUntilMidnight = boost::numeric_cast<int>((midnight - now).total_milliseconds());
dateChangeTimer_ = boost::shared_ptr<Timer>(timerFactory_->createTimer(millisecondsUntilMidnight));
dateChangeTimer_->onTick.connect(boost::bind(&ChatControllerBase::handleDayChangeTick, this));
dateChangeTimer_->start();
@@ -71,7 +93,7 @@ void ChatControllerBase::createDayChangeTimer() {
void ChatControllerBase::handleDayChangeTick() {
dateChangeTimer_->stop();
boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
- chatWindow_->addSystemMessage(str(format(QT_TRANSLATE_NOOP("", "The day is now %1%")) % std::string(boost::posix_time::to_iso_extended_string(now)).substr(0,10)));
+ chatWindow_->addSystemMessage(chatMessageParser_->parseMessageBody(str(format(QT_TRANSLATE_NOOP("", "The day is now %1%")) % std::string(boost::posix_time::to_iso_extended_string(now)).substr(0,10))), ChatWindow::DefaultDirection);
dayTicked();
createDayChangeTimer();
}
@@ -112,7 +134,7 @@ void ChatControllerBase::handleAllMessagesRead() {
}
int ChatControllerBase::getUnreadCount() {
- return targetedUnreadMessages_.size();
+ return boost::numeric_cast<int>(targetedUnreadMessages_.size());
}
void ChatControllerBase::handleSendMessageRequest(const std::string &body, bool isCorrectionMessage) {
@@ -175,19 +197,19 @@ void ChatControllerBase::activateChatWindow() {
chatWindow_->activate();
}
-std::string ChatControllerBase::addMessage(const std::string& message, const std::string& senderName, bool senderIsSelf, const boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time) {
+std::string ChatControllerBase::addMessage(const std::string& message, const std::string& senderName, bool senderIsSelf, const boost::shared_ptr<SecurityLabel> label, const boost::filesystem::path& avatarPath, const boost::posix_time::ptime& time, const HighlightAction& highlight) {
if (boost::starts_with(message, "/me ")) {
- return chatWindow_->addAction(String::getSplittedAtFirst(message, ' ').second, senderName, senderIsSelf, label, avatarPath, time);
+ return chatWindow_->addAction(chatMessageParser_->parseMessageBody(String::getSplittedAtFirst(message, ' ').second), senderName, senderIsSelf, label, pathToString(avatarPath), time, highlight);
} else {
- return chatWindow_->addMessage(message, senderName, senderIsSelf, label, avatarPath, time);
+ return chatWindow_->addMessage(chatMessageParser_->parseMessageBody(message), senderName, senderIsSelf, label, pathToString(avatarPath), time, highlight);
}
}
-void ChatControllerBase::replaceMessage(const std::string& message, const std::string& id, const boost::posix_time::ptime& time) {
+void ChatControllerBase::replaceMessage(const std::string& message, const std::string& id, const boost::posix_time::ptime& time, const HighlightAction& highlight) {
if (boost::starts_with(message, "/me ")) {
- chatWindow_->replaceWithAction(String::getSplittedAtFirst(message, ' ').second, id, time);
+ chatWindow_->replaceWithAction(chatMessageParser_->parseMessageBody(String::getSplittedAtFirst(message, ' ').second), id, time, highlight);
} else {
- chatWindow_->replaceMessage(message, id, time);
+ chatWindow_->replaceMessage(chatMessageParser_->parseMessageBody(message), id, time, highlight);
}
}
@@ -205,9 +227,12 @@ void ChatControllerBase::handleIncomingMessage(boost::shared_ptr<MessageEvent> m
}
boost::shared_ptr<Message> message = messageEvent->getStanza();
std::string body = message->getBody();
+ HighlightAction highlight;
if (message->isError()) {
- std::string errorMessage = str(format(QT_TRANSLATE_NOOP("", "Couldn't send message: %1%")) % getErrorMessage(message->getPayload<ErrorPayload>()));
- chatWindow_->addErrorMessage(errorMessage);
+ if (!message->getTo().getResource().empty()) {
+ std::string 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());
@@ -231,7 +256,7 @@ void ChatControllerBase::handleIncomingMessage(boost::shared_ptr<MessageEvent> m
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(std::string(s.str()));
+ chatWindow_->addSystemMessage(chatMessageParser_->parseMessageBody(std::string(s.str())), ChatWindow::DefaultDirection);
}
boost::shared_ptr<SecurityLabel> label = message->getPayload<SecurityLabel>();
@@ -243,6 +268,11 @@ void ChatControllerBase::handleIncomingMessage(boost::shared_ptr<MessageEvent> m
}
onActivity(body);
+ // Highlight
+ if (!isIncomingMessageFromMe(message)) {
+ highlight = highlighter_->findAction(body, senderDisplayNameFromMessage(from));
+ }
+
boost::shared_ptr<Replace> replace = message->getPayload<Replace>();
if (replace) {
std::string body = message->getBody();
@@ -250,19 +280,19 @@ void ChatControllerBase::handleIncomingMessage(boost::shared_ptr<MessageEvent> m
std::map<JID, std::string>::iterator lastMessage;
lastMessage = lastMessagesUIID_.find(from);
if (lastMessage != lastMessagesUIID_.end()) {
- replaceMessage(body, lastMessagesUIID_[from], timeStamp);
+ replaceMessage(body, lastMessagesUIID_[from], timeStamp, highlight);
}
}
else {
- lastMessagesUIID_[from] = addMessage(body, senderDisplayNameFromMessage(from), isIncomingMessageFromMe(message), label, std::string(avatarManager_->getAvatarPath(from).string()), timeStamp);
+ lastMessagesUIID_[from] = addMessage(body, senderDisplayNameFromMessage(from), isIncomingMessageFromMe(message), label, avatarManager_->getAvatarPath(from), timeStamp, highlight);
}
logMessage(body, from, selfJID_, timeStamp, true);
}
chatWindow_->show();
- chatWindow_->setUnreadMessageCount(unreadMessages_.size());
+ chatWindow_->setUnreadMessageCount(boost::numeric_cast<int>(unreadMessages_.size()));
onUnreadCountChanged();
- postHandleIncomingMessage(messageEvent);
+ postHandleIncomingMessage(messageEvent, highlight);
}
std::string ChatControllerBase::getErrorMessage(boost::shared_ptr<ErrorPayload> error) {
@@ -296,23 +326,28 @@ std::string ChatControllerBase::getErrorMessage(boost::shared_ptr<ErrorPayload>
case ErrorPayload::UnexpectedRequest: return QT_TRANSLATE_NOOP("", "Unexpected request");
}
}
+ assert(false);
return defaultMessage;
}
void ChatControllerBase::handleGeneralMUCInvitation(MUCInviteEvent::ref event) {
unreadMessages_.push_back(event);
chatWindow_->show();
- chatWindow_->setUnreadMessageCount(unreadMessages_.size());
+ chatWindow_->setUnreadMessageCount(boost::numeric_cast<int>(unreadMessages_.size()));
onUnreadCountChanged();
- chatWindow_->addMUCInvitation(senderDisplayNameFromMessage(event->getInviter()), event->getRoomJID(), event->getReason(), event->getPassword(), event->getDirect());
+ chatWindow_->addMUCInvitation(senderDisplayNameFromMessage(event->getInviter()), event->getRoomJID(), event->getReason(), event->getPassword(), event->getDirect(), event->getImpromptu());
eventController_->handleIncomingEvent(event);
}
void ChatControllerBase::handleMUCInvitation(Message::ref message) {
MUCInvitationPayload::ref invite = message->getPayload<MUCInvitationPayload>();
- MUCInviteEvent::ref inviteEvent = boost::make_shared<MUCInviteEvent>(toJID_, invite->getJID(), invite->getReason(), invite->getPassword(), true);
- handleGeneralMUCInvitation(inviteEvent);
+ if (autoAcceptMUCInviteDecider_->isAutoAcceptedInvite(message->getFrom(), invite)) {
+ eventStream_->send(boost::make_shared<JoinMUCUIEvent>(invite->getJID(), boost::optional<std::string>(), boost::optional<std::string>(), false, false, true));
+ } else {
+ MUCInviteEvent::ref inviteEvent = boost::make_shared<MUCInviteEvent>(toJID_, invite->getJID(), invite->getReason(), invite->getPassword(), true, invite->getIsImpromptu());
+ handleGeneralMUCInvitation(inviteEvent);
+ }
}
void ChatControllerBase::handleMediatedMUCInvitation(Message::ref message) {
@@ -327,10 +362,8 @@ void ChatControllerBase::handleMediatedMUCInvitation(Message::ref message) {
password = *message->getPayload<MUCUserPayload>()->getPassword();
}
- MUCInviteEvent::ref inviteEvent = boost::make_shared<MUCInviteEvent>(invite.from, from, reason, password, false);
+ MUCInviteEvent::ref inviteEvent = boost::make_shared<MUCInviteEvent>(invite.from, from, reason, password, false, false);
handleGeneralMUCInvitation(inviteEvent);
}
-
-
}
diff --git a/Swift/Controllers/Chat/ChatControllerBase.h b/Swift/Controllers/Chat/ChatControllerBase.h
index b26af02..7db94a4 100644
--- a/Swift/Controllers/Chat/ChatControllerBase.h
+++ b/Swift/Controllers/Chat/ChatControllerBase.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2012 Kevin Smith
+ * Copyright (c) 2010-2013 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -8,72 +8,82 @@
#include <map>
#include <vector>
+#include <string>
+
#include <boost/shared_ptr.hpp>
-#include "Swiften/Base/boost_bsignals.h"
-#include <boost/filesystem.hpp>
+#include <boost/filesystem/path.hpp>
#include <boost/optional.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
-#include "Swiften/Network/Timer.h"
-#include "Swiften/Network/TimerFactory.h"
-#include "Swiften/Elements/Stanza.h"
-#include <string>
-#include "Swiften/Elements/DiscoInfo.h"
-#include "Swift/Controllers/XMPPEvents/MessageEvent.h"
+#include <Swiften/Network/Timer.h>
+#include <Swiften/Network/TimerFactory.h>
+#include <Swiften/Elements/Stanza.h>
+#include <Swiften/Base/boost_bsignals.h>
+#include <Swiften/Elements/DiscoInfo.h>
+#include <Swiften/JID/JID.h>
+#include <Swiften/Elements/SecurityLabelsCatalog.h>
+#include <Swiften/Elements/ErrorPayload.h>
+#include <Swiften/Presence/PresenceOracle.h>
+#include <Swiften/Queries/IQRouter.h>
+#include <Swiften/Base/IDGenerator.h>
+#include <Swiften/MUC/MUCRegistry.h>
+
+#include <Swift/Controllers/XMPPEvents/MessageEvent.h>
#include <Swift/Controllers/XMPPEvents/MUCInviteEvent.h>
-#include "Swiften/JID/JID.h"
-#include "Swiften/Elements/SecurityLabelsCatalog.h"
-#include "Swiften/Elements/ErrorPayload.h"
-#include "Swiften/Presence/PresenceOracle.h"
-#include "Swiften/Queries/IQRouter.h"
-#include "Swiften/Base/IDGenerator.h"
#include <Swift/Controllers/HistoryController.h>
-#include <Swiften/MUC/MUCRegistry.h>
+#include <Swift/Controllers/HighlightManager.h>
+#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
namespace Swift {
class IQRouter;
class StanzaChannel;
- class ChatWindow;
class ChatWindowFactory;
class AvatarManager;
class UIEventStream;
class EventController;
class EntityCapsProvider;
+ class HighlightManager;
+ class Highlighter;
+ class ChatMessageParser;
+ class AutoAcceptMUCInviteDecider;
class ChatControllerBase : public boost::bsignals::trackable {
public:
virtual ~ChatControllerBase();
void showChatWindow();
void activateChatWindow();
- void setAvailableServerFeatures(boost::shared_ptr<DiscoInfo> info);
+ virtual void setAvailableServerFeatures(boost::shared_ptr<DiscoInfo> info);
void handleIncomingMessage(boost::shared_ptr<MessageEvent> message);
- std::string addMessage(const std::string& message, const std::string& senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time);
- void replaceMessage(const std::string& message, const std::string& id, const boost::posix_time::ptime& time);
+ std::string addMessage(const std::string& message, const std::string& senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const boost::filesystem::path& avatarPath, const boost::posix_time::ptime& time, const HighlightAction& highlight);
+ void replaceMessage(const std::string& message, const std::string& id, const boost::posix_time::ptime& time, const HighlightAction& highlight);
virtual void setOnline(bool online);
virtual void setEnabled(bool enabled);
- virtual void setToJID(const JID& jid) {toJID_ = jid;};
+ virtual void setToJID(const JID& jid) {toJID_ = jid;}
/** Used for determining when something is recent.*/
boost::signal<void (const std::string& /*activity*/)> onActivity;
boost::signal<void ()> onUnreadCountChanged;
int getUnreadCount();
const JID& getToJID() {return toJID_;}
void handleCapsChanged(const JID& jid);
+ void setCanStartImpromptuChats(bool supportsImpromptu);
+ virtual ChatWindow* detachChatWindow();
+ boost::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, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, HistoryController* historyController, MUCRegistry* mucRegistry);
+ ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ChatMessageParser* chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider);
/**
* Pass the Message appended, and the stanza used to send it.
*/
- virtual void postSendMessage(const std::string&, boost::shared_ptr<Stanza>) {};
+ virtual void postSendMessage(const std::string&, boost::shared_ptr<Stanza>) {}
virtual std::string senderDisplayNameFromMessage(const JID& from) = 0;
virtual bool isIncomingMessageFromMe(boost::shared_ptr<Message>) = 0;
- virtual void preHandleIncomingMessage(boost::shared_ptr<MessageEvent>) {};
- virtual void postHandleIncomingMessage(boost::shared_ptr<MessageEvent>) {};
- virtual void preSendMessageRequest(boost::shared_ptr<Message>) {};
+ virtual void preHandleIncomingMessage(boost::shared_ptr<MessageEvent>) {}
+ virtual void postHandleIncomingMessage(boost::shared_ptr<MessageEvent>, const HighlightAction&) {}
+ virtual void preSendMessageRequest(boost::shared_ptr<Message>) {}
virtual bool isFromContact(const JID& from);
virtual boost::optional<boost::posix_time::ptime> getMessageTimestamp(boost::shared_ptr<Message>) const = 0;
- virtual void dayTicked() {};
+ virtual void dayTicked() {}
virtual void handleBareJIDCapsChanged(const JID& jid) = 0;
std::string getErrorMessage(boost::shared_ptr<ErrorPayload>);
virtual void setContactIsReceivingPresence(bool /* isReceivingPresence */) {}
@@ -116,5 +126,9 @@ namespace Swift {
SecurityLabelsCatalog::Item lastLabel_;
HistoryController* historyController_;
MUCRegistry* mucRegistry_;
+ Highlighter* highlighter_;
+ ChatMessageParser* chatMessageParser_;
+ AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider_;
+ UIEventStream* eventStream_;
};
}
diff --git a/Swift/Controllers/Chat/ChatMessageParser.cpp b/Swift/Controllers/Chat/ChatMessageParser.cpp
new file mode 100644
index 0000000..ce184ea
--- /dev/null
+++ b/Swift/Controllers/Chat/ChatMessageParser.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2013 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swift/Controllers/Chat/ChatMessageParser.h>
+
+#include <vector>
+#include <utility>
+
+#include <boost/smart_ptr/make_shared.hpp>
+#include <boost/algorithm/string.hpp>
+
+#include <Swiften/Base/Regex.h>
+#include <Swiften/Base/foreach.h>
+
+#include <SwifTools/Linkify.h>
+
+
+namespace Swift {
+
+ ChatMessageParser::ChatMessageParser(const std::map<std::string, std::string>& emoticons) : emoticons_(emoticons) {
+
+ }
+
+ typedef std::pair<std::string, std::string> StringPair;
+
+ ChatWindow::ChatMessage ChatMessageParser::parseMessageBody(const std::string& body) {
+ ChatWindow::ChatMessage parsedMessage;
+ std::string remaining = body;
+ /* Parse one, URLs */
+ while (!remaining.empty()) {
+ bool found = false;
+ std::pair<std::vector<std::string>, size_t> links = Linkify::splitLink(remaining);
+ remaining = "";
+ for (size_t i = 0; i < links.first.size(); i++) {
+ const std::string& part = links.first[i];
+ if (found) {
+ // Must be on the last part, then
+ remaining = part;
+ }
+ else {
+ if (i == links.second) {
+ found = true;
+ parsedMessage.append(boost::make_shared<ChatWindow::ChatURIMessagePart>(part));
+ }
+ else {
+ parsedMessage.append(boost::make_shared<ChatWindow::ChatTextMessagePart>(part));
+ }
+ }
+ }
+ }
+
+
+
+ std::string regexString;
+ /* Parse two, emoticons */
+ foreach (StringPair emoticon, emoticons_) {
+ /* Construct a regexp that finds an instance of any of the emoticons inside a group */
+ regexString += regexString.empty() ? "(" : "|";
+ regexString += Regex::escape(emoticon.first);
+ }
+ if (!regexString.empty()) {
+ regexString += ")";
+ boost::regex emoticonRegex(regexString);
+
+ ChatWindow::ChatMessage newMessage;
+ foreach (boost::shared_ptr<ChatWindow::ChatMessagePart> part, parsedMessage.getParts()) {
+ boost::shared_ptr<ChatWindow::ChatTextMessagePart> textPart;
+ if ((textPart = boost::dynamic_pointer_cast<ChatWindow::ChatTextMessagePart>(part))) {
+ try {
+ boost::match_results<std::string::const_iterator> match;
+ const std::string& text = textPart->text;
+ std::string::const_iterator start = text.begin();
+ while (regex_search(start, text.end(), match, emoticonRegex)) {
+ std::string::const_iterator matchStart = match[0].first;
+ std::string::const_iterator matchEnd = match[0].second;
+ if (start != matchStart) {
+ /* If we're skipping over plain text since the previous emoticon, record it as plain text */
+ newMessage.append(boost::make_shared<ChatWindow::ChatTextMessagePart>(std::string(start, matchStart)));
+ }
+ boost::shared_ptr<ChatWindow::ChatEmoticonMessagePart> emoticonPart = boost::make_shared<ChatWindow::ChatEmoticonMessagePart>();
+ std::map<std::string, std::string>::const_iterator emoticonIterator = emoticons_.find(match.str());
+ assert (emoticonIterator != emoticons_.end());
+ const StringPair& emoticon = *emoticonIterator;
+ emoticonPart->imagePath = emoticon.second;
+ emoticonPart->alternativeText = emoticon.first;
+ newMessage.append(emoticonPart);
+ start = matchEnd;
+ }
+ if (start != text.end()) {
+ /* If there's plain text after the last emoticon, record it */
+ newMessage.append(boost::make_shared<ChatWindow::ChatTextMessagePart>(std::string(start, text.end())));
+ }
+
+ }
+ catch (std::runtime_error) {
+ /* Basically too expensive to compute the regex results and it gave up, so pass through as text */
+ newMessage.append(part);
+ }
+ }
+ else {
+ newMessage.append(part);
+ }
+ }
+ parsedMessage = newMessage;
+
+ }
+ return parsedMessage;
+ }
+}
diff --git a/Swift/Controllers/Chat/ChatMessageParser.h b/Swift/Controllers/Chat/ChatMessageParser.h
new file mode 100644
index 0000000..c9b9456
--- /dev/null
+++ b/Swift/Controllers/Chat/ChatMessageParser.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2013 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
+
+namespace Swift {
+
+ class ChatMessageParser {
+ public:
+ ChatMessageParser(const std::map<std::string, std::string>& emoticons);
+ ChatWindow::ChatMessage parseMessageBody(const std::string& body);
+ private:
+ std::map<std::string, std::string> emoticons_;
+
+ };
+}
diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp
index 1e0e9c2..5d69019 100644
--- a/Swift/Controllers/Chat/ChatsManager.cpp
+++ b/Swift/Controllers/Chat/ChatsManager.cpp
@@ -1,48 +1,93 @@
/*
- * Copyright (c) 2010-2011 Kevin Smith
+ * Copyright (c) 2010-2013 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#include "Swift/Controllers/Chat/ChatsManager.h"
+#include <Swift/Controllers/Chat/ChatsManager.h>
#include <boost/bind.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/smart_ptr/make_shared.hpp>
+#include <boost/archive/text_oarchive.hpp>
+#include <boost/archive/text_iarchive.hpp>
+#include <boost/serialization/vector.hpp>
+#include <boost/serialization/map.hpp>
+#include <boost/serialization/string.hpp>
+#include <boost/serialization/split_free.hpp>
#include <Swiften/Base/foreach.h>
+#include <Swiften/Presence/PresenceSender.h>
+#include <Swiften/Client/NickResolver.h>
+#include <Swiften/MUC/MUCManager.h>
+#include <Swiften/Elements/ChatState.h>
+#include <Swiften/Elements/MUCUserPayload.h>
+#include <Swiften/Elements/DeliveryReceipt.h>
+#include <Swiften/Elements/DeliveryReceiptRequest.h>
+#include <Swiften/MUC/MUCBookmarkManager.h>
+#include <Swiften/Avatars/AvatarManager.h>
+#include <Swiften/Elements/MUCInvitationPayload.h>
+#include <Swiften/Roster/XMPPRoster.h>
+#include <Swiften/Client/ClientBlockListManager.h>
+#include <Swiften/Client/StanzaChannel.h>
+
#include <Swift/Controllers/Chat/ChatController.h>
#include <Swift/Controllers/Chat/ChatControllerBase.h>
#include <Swift/Controllers/Chat/MUCSearchController.h>
+#include <Swift/Controllers/Chat/AutoAcceptMUCInviteDecider.h>
#include <Swift/Controllers/XMPPEvents/EventController.h>
#include <Swift/Controllers/Chat/MUCController.h>
#include <Swift/Controllers/UIEvents/RequestChatUIEvent.h>
+#include <Swift/Controllers/UIEvents/CreateImpromptuMUCUIEvent.h>
#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h>
#include <Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h>
#include <Swift/Controllers/UIEvents/AddMUCBookmarkUIEvent.h>
#include <Swift/Controllers/UIEvents/RemoveMUCBookmarkUIEvent.h>
#include <Swift/Controllers/UIEvents/EditMUCBookmarkUIEvent.h>
+#include <Swift/Controllers/UIEvents/InviteToMUCUIEvent.h>
#include <Swift/Controllers/UIInterfaces/ChatListWindowFactory.h>
#include <Swift/Controllers/UIInterfaces/JoinMUCWindow.h>
#include <Swift/Controllers/UIInterfaces/JoinMUCWindowFactory.h>
-#include <Swiften/Presence/PresenceSender.h>
-#include <Swiften/Client/NickResolver.h>
-#include <Swiften/MUC/MUCManager.h>
-#include <Swiften/Elements/ChatState.h>
-#include <Swiften/Elements/MUCUserPayload.h>
-#include <Swiften/Elements/DeliveryReceipt.h>
-#include <Swiften/Elements/DeliveryReceiptRequest.h>
-#include <Swiften/MUC/MUCBookmarkManager.h>
#include <Swift/Controllers/FileTransfer/FileTransferController.h>
#include <Swift/Controllers/FileTransfer/FileTransferOverview.h>
#include <Swift/Controllers/ProfileSettingsProvider.h>
-#include <Swiften/Avatars/AvatarManager.h>
-#include <Swiften/Elements/MUCInvitationPayload.h>
-#include <Swiften/Roster/XMPPRoster.h>
#include <Swift/Controllers/Settings/SettingsProvider.h>
#include <Swift/Controllers/SettingConstants.h>
-#include <Swiften/Client/StanzaChannel.h>
#include <Swift/Controllers/WhiteboardManager.h>
+#include <Swift/Controllers/Chat/ChatMessageParser.h>
+#include <Swift/Controllers/Chat/UserSearchController.h>
+#include <Swiften/Disco/DiscoServiceWalker.h>
+#include <Swiften/Client/ClientBlockListManager.h>
+#include <Swiften/StringCodecs/Base64.h>
+#include <Swiften/Base/Log.h>
+
+namespace boost {
+namespace serialization {
+ template<class Archive> void save(Archive& ar, const Swift::JID& jid, const unsigned int /*version*/) {
+ std::string jidStr = jid.toString();
+ ar << jidStr;
+ }
+
+ template<class Archive> void load(Archive& ar, Swift::JID& jid, const unsigned int /*version*/) {
+ std::string stringJID;
+ ar >> stringJID;
+ jid = Swift::JID(stringJID);
+ }
+
+ template<class Archive> inline void serialize(Archive& ar, Swift::JID& t, const unsigned int file_version){
+ split_free(ar, t, file_version);
+ }
+
+ template<class Archive> void serialize(Archive& ar, Swift::ChatListWindow::Chat& chat, const unsigned int /*version*/) {
+ ar & chat.jid;
+ ar & chat.chatName;
+ ar & chat.activity;
+ ar & chat.isMUC;
+ ar & chat.nick;
+ ar & chat.impromptuJIDs;
+ }
+}
+}
namespace Swift {
@@ -74,7 +119,11 @@ ChatsManager::ChatsManager(
bool eagleMode,
SettingsProvider* settings,
HistoryController* historyController,
- WhiteboardManager* whiteboardManager) :
+ WhiteboardManager* whiteboardManager,
+ HighlightManager* highlightManager,
+ ClientBlockListManager* clientBlockListManager,
+ const std::map<std::string, std::string>& emoticons,
+ UserSearchController* inviteUserSearchController) :
jid_(jid),
joinMUCWindowFactory_(joinMUCWindowFactory),
useDelayForLatency_(useDelayForLatency),
@@ -86,7 +135,10 @@ ChatsManager::ChatsManager(
eagleMode_(eagleMode),
settings_(settings),
historyController_(historyController),
- whiteboardManager_(whiteboardManager) {
+ whiteboardManager_(whiteboardManager),
+ highlightManager_(highlightManager),
+ clientBlockListManager_(clientBlockListManager),
+ inviteUserSearchController_(inviteUserSearchController) {
timerFactory_ = timerFactory;
eventController_ = eventController;
stanzaChannel_ = stanzaChannel;
@@ -100,6 +152,7 @@ ChatsManager::ChatsManager(
uiEventStream_ = uiEventStream;
mucBookmarkManager_ = NULL;
profileSettings_ = profileSettings;
+ chatMessageParser_ = new ChatMessageParser(emoticons);
presenceOracle_->onPresenceChange.connect(boost::bind(&ChatsManager::handlePresenceChange, this, _1));
uiEventConnection_ = uiEventStream_->onUIEvent.connect(boost::bind(&ChatsManager::handleUIEvent, this, _1));
@@ -127,6 +180,8 @@ ChatsManager::ChatsManager(
setupBookmarks();
loadRecents();
+
+ autoAcceptMUCInviteDecider_ = new AutoAcceptMUCInviteDecider(jid.getDomain(), roster_, settings_);
}
ChatsManager::~ChatsManager() {
@@ -144,25 +199,26 @@ ChatsManager::~ChatsManager() {
}
delete mucBookmarkManager_;
delete mucSearchController_;
+ delete chatMessageParser_;
+ delete autoAcceptMUCInviteDecider_;
}
void ChatsManager::saveRecents() {
- std::string recents;
- int i = 1;
- foreach (ChatListWindow::Chat chat, recentChats_) {
- std::vector<std::string> activity;
- boost::split(activity, chat.activity, boost::is_any_of("\t\n"));
- if (activity.empty()) {
- /* Work around Boost bug https://svn.boost.org/trac/boost/ticket/4751 */
- activity.push_back("");
- }
- std::string recent = chat.jid.toString() + "\t" + (eagleMode_ ? "" : activity[0]) + "\t" + (chat.isMUC ? "true" : "false") + "\t" + chat.nick;
- recents += recent + "\n";
- if (i++ > 25) {
- break;
+ std::stringstream serializeStream;
+ boost::archive::text_oarchive oa(serializeStream);
+ std::vector<ChatListWindow::Chat> recentsLimited = std::vector<ChatListWindow::Chat>(recentChats_.begin(), recentChats_.end());
+ if (recentsLimited.size() > 25) {
+ recentsLimited.erase(recentsLimited.begin() + 25, recentsLimited.end());
+ }
+ if (eagleMode_) {
+ foreach(ChatListWindow::Chat& chat, recentsLimited) {
+ chat.activity = "";
}
}
- profileSettings_->storeString(RECENT_CHATS, recents);
+
+ oa << recentsLimited;
+ std::string serializedStr = Base64::encode(createByteArray(serializeStream.str()));
+ profileSettings_->storeString(RECENT_CHATS, serializedStr);
}
void ChatsManager::handleClearRecentsRequested() {
@@ -204,43 +260,70 @@ void ChatsManager::updatePresenceReceivingStateOnChatController(const JID &jid)
}
}
-void ChatsManager::loadRecents() {
- std::string recentsString(profileSettings_->getStringSetting(RECENT_CHATS));
- std::vector<std::string> recents;
- boost::split(recents, recentsString, boost::is_any_of("\n"));
- int i = 0;
- foreach (std::string recentString, recents) {
- if (i++ > 30) {
- break;
- }
- std::vector<std::string> recent;
- boost::split(recent, recentString, boost::is_any_of("\t"));
- if (recent.size() < 4) {
- continue;
+ChatListWindow::Chat ChatsManager::updateChatStatusAndAvatarHelper(const ChatListWindow::Chat& chat) const {
+ ChatListWindow::Chat fixedChat = chat;
+ if (fixedChat.isMUC) {
+ if (mucControllers_.find(fixedChat.jid.toBare()) != mucControllers_.end()) {
+ fixedChat.statusType = StatusShow::Online;
}
- JID jid(recent[0]);
- if (!jid.isValid()) {
- continue;
+ } else {
+ if (avatarManager_) {
+ fixedChat.avatarPath = avatarManager_->getAvatarPath(fixedChat.jid);
}
- std::string activity(recent[1]);
- bool isMUC = recent[2] == "true";
- std::string nick(recent[3]);
- StatusShow::Type type = StatusShow::None;
- boost::filesystem::path path;
- if (isMUC) {
- if (mucControllers_.find(jid.toBare()) != mucControllers_.end()) {
- type = StatusShow::Online;
+ Presence::ref presence = presenceOracle_->getHighestPriorityPresence(fixedChat.jid.toBare());
+ fixedChat.statusType = presence ? presence->getShow() : StatusShow::None;
+ }
+ return fixedChat;
+}
+
+void ChatsManager::loadRecents() {
+ std::string recentsString(profileSettings_->getStringSetting(RECENT_CHATS));
+ if (recentsString.find("\t") != std::string::npos) {
+ // old format
+ std::vector<std::string> recents;
+ boost::split(recents, recentsString, boost::is_any_of("\n"));
+ int i = 0;
+ foreach (std::string recentString, recents) {
+ if (i++ > 30) {
+ break;
}
- } else {
- if (avatarManager_) {
- path = avatarManager_->getAvatarPath(jid);
+ std::vector<std::string> recent;
+ boost::split(recent, recentString, boost::is_any_of("\t"));
+ if (recent.size() < 4) {
+ continue;
}
- Presence::ref presence = presenceOracle_->getHighestPriorityPresence(jid.toBare());
- type = presence ? presence->getShow() : StatusShow::None;
+ JID jid(recent[0]);
+ if (!jid.isValid()) {
+ continue;
+ }
+ std::string activity(recent[1]);
+ bool isMUC = recent[2] == "true";
+ std::string nick(recent[3]);
+ StatusShow::Type type = StatusShow::None;
+ boost::filesystem::path path;
+
+ ChatListWindow::Chat chat(jid, nickResolver_->jidToNick(jid), activity, 0, type, path, isMUC, nick);
+ chat = updateChatStatusAndAvatarHelper(chat);
+ prependRecent(chat);
+ }
+ } else if (!recentsString.empty()){
+ // boost searilaize based format
+ ByteArray debase64 = Base64::decode(recentsString);
+ std::vector<ChatListWindow::Chat> recentChats;
+ std::stringstream deserializeStream(std::string((const char*)debase64.data(), debase64.size()));
+ try {
+ boost::archive::text_iarchive ia(deserializeStream);
+ ia >> recentChats;
+ } catch (const boost::archive::archive_exception& e) {
+ SWIFT_LOG(debug) << "Failed to load recents: " << e.what() << std::endl;
+ return;
}
- ChatListWindow::Chat chat(jid, nickResolver_->jidToNick(jid), activity, 0, type, path, isMUC, nick);
- prependRecent(chat);
+ foreach(ChatListWindow::Chat chat, recentChats) {
+ chat.statusType = StatusShow::None;
+ chat = updateChatStatusAndAvatarHelper(chat);
+ prependRecent(chat);
+ }
}
handleUnreadCountChanged(NULL);
}
@@ -268,7 +351,7 @@ void ChatsManager::handleBookmarksReady() {
void ChatsManager::handleMUCBookmarkAdded(const MUCBookmark& bookmark) {
std::map<JID, MUCController*>::iterator it = mucControllers_.find(bookmark.getRoom());
if (it == mucControllers_.end() && bookmark.getAutojoin()) {
- handleJoinMUCRequest(bookmark.getRoom(), bookmark.getPassword(), bookmark.getNick(), false, false);
+ handleJoinMUCRequest(bookmark.getRoom(), bookmark.getPassword(), bookmark.getNick(), false, false, false );
}
chatListWindow_->addMUCBookmark(bookmark);
}
@@ -289,9 +372,16 @@ ChatListWindow::Chat ChatsManager::createChatListChatItem(const JID& jid, const
type = StatusShow::Online;
}
nick = controller->getNick();
+
+ if (controller->isImpromptu()) {
+ ChatListWindow::Chat chat = ChatListWindow::Chat(jid, jid.toString(), activity, unreadCount, type, boost::filesystem::path(), true, nick);
+ typedef std::pair<std::string, JID> StringJIDPair;
+ std::map<std::string, JID> participants = controller->getParticipantJIDs();
+ chat.impromptuJIDs = participants;
+ return chat;
+ }
}
return ChatListWindow::Chat(jid, jid.toString(), activity, unreadCount, type, boost::filesystem::path(), true, nick);
-
} else {
ChatController* controller = getChatControllerIfExists(jid, false);
if (controller) {
@@ -340,14 +430,33 @@ void ChatsManager::handleUnreadCountChanged(ChatControllerBase* controller) {
chatListWindow_->setUnreadCount(unreadTotal);
}
+boost::optional<ChatListWindow::Chat> ChatsManager::removeExistingChat(const ChatListWindow::Chat& chat) {
+ std::list<ChatListWindow::Chat>::iterator result = std::find(recentChats_.begin(), recentChats_.end(), chat);
+ if (result != recentChats_.end()) {
+ ChatListWindow::Chat existingChat = *result;
+ recentChats_.erase(std::remove(recentChats_.begin(), recentChats_.end(), chat), recentChats_.end());
+ return boost::optional<ChatListWindow::Chat>(existingChat);
+ } else {
+ return boost::optional<ChatListWindow::Chat>();
+ }
+}
+
void ChatsManager::appendRecent(const ChatListWindow::Chat& chat) {
- recentChats_.erase(std::remove(recentChats_.begin(), recentChats_.end(), chat), recentChats_.end());
- recentChats_.push_front(chat);
+ boost::optional<ChatListWindow::Chat> oldChat = removeExistingChat(chat);
+ ChatListWindow::Chat mergedChat = chat;
+ if (oldChat && !oldChat->impromptuJIDs.empty()) {
+ mergedChat.impromptuJIDs.insert(oldChat->impromptuJIDs.begin(), oldChat->impromptuJIDs.end());
+ }
+ recentChats_.push_front(mergedChat);
}
void ChatsManager::prependRecent(const ChatListWindow::Chat& chat) {
- recentChats_.erase(std::remove(recentChats_.begin(), recentChats_.end(), chat), recentChats_.end());
- recentChats_.push_back(chat);
+ boost::optional<ChatListWindow::Chat> oldChat = removeExistingChat(chat);
+ ChatListWindow::Chat mergedChat = chat;
+ if (oldChat && !oldChat->impromptuJIDs.empty()) {
+ mergedChat.impromptuJIDs.insert(oldChat->impromptuJIDs.begin(), oldChat->impromptuJIDs.end());
+ }
+ recentChats_.push_back(mergedChat);
}
void ChatsManager::handleUserLeftMUC(MUCController* mucController) {
@@ -375,6 +484,27 @@ void ChatsManager::handleSettingChanged(const std::string& settingPath) {
}
}
+void ChatsManager::finalizeImpromptuJoin(MUC::ref muc, const std::vector<JID>& jidsToInvite, const std::string& reason, const boost::optional<JID>& reuseChatJID) {
+ // send impromptu invites for the new MUC
+ std::vector<JID> missingJIDsToInvite = jidsToInvite;
+
+ typedef std::pair<std::string, MUCOccupant> StringMUCOccupantPair;
+ std::map<std::string, MUCOccupant> occupants = muc->getOccupants();
+ foreach(StringMUCOccupantPair occupant, occupants) {
+ boost::optional<JID> realJID = occupant.second.getRealJID();
+ if (realJID) {
+ missingJIDsToInvite.erase(std::remove(missingJIDsToInvite.begin(), missingJIDsToInvite.end(), realJID->toBare()), missingJIDsToInvite.end());
+ }
+ }
+
+ if (reuseChatJID) {
+ muc->invitePerson(reuseChatJID.get(), reason, true, true);
+ }
+ foreach(const JID& jid, missingJIDsToInvite) {
+ muc->invitePerson(jid, reason, true);
+ }
+}
+
void ChatsManager::handleUIEvent(boost::shared_ptr<UIEvent> event) {
boost::shared_ptr<RequestChatUIEvent> chatEvent = boost::dynamic_pointer_cast<RequestChatUIEvent>(event);
if (chatEvent) {
@@ -392,13 +522,24 @@ void ChatsManager::handleUIEvent(boost::shared_ptr<UIEvent> event) {
return;
}
+ boost::shared_ptr<CreateImpromptuMUCUIEvent> createImpromptuMUCEvent = boost::dynamic_pointer_cast<CreateImpromptuMUCUIEvent>(event);
+ if (createImpromptuMUCEvent) {
+ assert(!localMUCServiceJID_.toString().empty());
+ // create new muc
+ JID roomJID = createImpromptuMUCEvent->getRoomJID().toString().empty() ? JID(idGenerator_.generateID(), localMUCServiceJID_) : createImpromptuMUCEvent->getRoomJID();
+
+ // join muc
+ MUC::ref muc = handleJoinMUCRequest(roomJID, boost::optional<std::string>(), nickResolver_->jidToNick(jid_), false, true, true);
+ mucControllers_[roomJID]->onImpromptuConfigCompleted.connect(boost::bind(&ChatsManager::finalizeImpromptuJoin, this, muc, createImpromptuMUCEvent->getJIDs(), createImpromptuMUCEvent->getReason(), boost::optional<JID>()));
+ mucControllers_[roomJID]->activateChatWindow();
+ }
boost::shared_ptr<EditMUCBookmarkUIEvent> editMUCBookmarkEvent = boost::dynamic_pointer_cast<EditMUCBookmarkUIEvent>(event);
if (editMUCBookmarkEvent) {
mucBookmarkManager_->replaceBookmark(editMUCBookmarkEvent->getOldBookmark(), editMUCBookmarkEvent->getNewBookmark());
}
else if (JoinMUCUIEvent::ref joinEvent = boost::dynamic_pointer_cast<JoinMUCUIEvent>(event)) {
- handleJoinMUCRequest(joinEvent->getJID(), joinEvent->getPassword(), joinEvent->getNick(), joinEvent->getShouldJoinAutomatically(), joinEvent->getCreateAsReservedRoomIfNew());
+ handleJoinMUCRequest(joinEvent->getJID(), joinEvent->getPassword(), joinEvent->getNick(), joinEvent->getShouldJoinAutomatically(), joinEvent->getCreateAsReservedRoomIfNew(), joinEvent->isImpromptu());
mucControllers_[joinEvent->getJID()]->activateChatWindow();
}
else if (boost::shared_ptr<RequestJoinMUCUIEvent> joinEvent = boost::dynamic_pointer_cast<RequestJoinMUCUIEvent>(event)) {
@@ -420,6 +561,22 @@ void ChatsManager::markAllRecentsOffline() {
chatListWindow_->setRecents(recentChats_);
}
+void ChatsManager::handleTransformChatToMUC(ChatController* chatController, ChatWindow* chatWindow, const std::vector<JID>& jidsToInvite, const std::string& reason) {
+ JID reuseChatInvite = chatController->getToJID();
+ chatControllers_.erase(chatController->getToJID());
+ delete chatController;
+
+ // join new impromptu muc
+ assert(!localMUCServiceJID_.toString().empty());
+
+ // create new muc
+ JID roomJID = JID(idGenerator_.generateID(), localMUCServiceJID_);
+
+ // join muc
+ MUC::ref muc = handleJoinMUCRequest(roomJID, boost::optional<std::string>(), nickResolver_->jidToNick(jid_), false, true, true, chatWindow);
+ mucControllers_[roomJID]->onImpromptuConfigCompleted.connect(boost::bind(&ChatsManager::finalizeImpromptuJoin, this, muc, jidsToInvite, reason, boost::optional<JID>(reuseChatInvite)));
+}
+
/**
* If a resource goes offline, release bound chatdialog to that resource.
*/
@@ -497,6 +654,11 @@ void ChatsManager::setOnline(bool enabled) {
markAllRecentsOffline();
} else {
setupBookmarks();
+ localMUCServiceFinderWalker_ = boost::make_shared<DiscoServiceWalker>(jid_.getDomain(), iqRouter_);
+ localMUCServiceFinderWalker_->onServiceFound.connect(boost::bind(&ChatsManager::handleLocalServiceFound, this, _1, _2));
+ localMUCServiceFinderWalker_->onWalkAborted.connect(boost::bind(&ChatsManager::handleLocalServiceWalkFinished, this));
+ localMUCServiceFinderWalker_->onWalkComplete.connect(boost::bind(&ChatsManager::handleLocalServiceWalkFinished, this));
+ localMUCServiceFinderWalker_->beginWalk();
}
}
@@ -521,12 +683,14 @@ ChatController* ChatsManager::getChatControllerOrFindAnother(const JID &contact)
ChatController* ChatsManager::createNewChatController(const JID& contact) {
assert(chatControllers_.find(contact) == chatControllers_.end());
- ChatController* controller = new ChatController(jid_, stanzaChannel_, iqRouter_, chatWindowFactory_, contact, nickResolver_, presenceOracle_, avatarManager_, mucRegistry_->isMUC(contact.toBare()), useDelayForLatency_, uiEventStream_, eventController_, timerFactory_, entityCapsProvider_, userWantsReceipts_, settings_, historyController_, mucRegistry_);
+ ChatController* controller = new ChatController(jid_, stanzaChannel_, iqRouter_, chatWindowFactory_, contact, nickResolver_, presenceOracle_, avatarManager_, mucRegistry_->isMUC(contact.toBare()), useDelayForLatency_, uiEventStream_, eventController_, timerFactory_, entityCapsProvider_, userWantsReceipts_, settings_, historyController_, mucRegistry_, highlightManager_, clientBlockListManager_, chatMessageParser_, autoAcceptMUCInviteDecider_);
chatControllers_[contact] = controller;
controller->setAvailableServerFeatures(serverDiscoInfo_);
controller->onActivity.connect(boost::bind(&ChatsManager::handleChatActivity, this, contact, _1, false));
controller->onUnreadCountChanged.connect(boost::bind(&ChatsManager::handleUnreadCountChanged, this, controller));
+ controller->onConvertToMUC.connect(boost::bind(&ChatsManager::handleTransformChatToMUC, this, controller, _1, _2, _3));
updatePresenceReceivingStateOnChatController(contact);
+ controller->setCanStartImpromptuChats(!localMUCServiceJID_.toString().empty());
return controller;
}
@@ -553,7 +717,6 @@ ChatController* ChatsManager::getChatControllerIfExists(const JID &contact, bool
} else {
return pair.second;
}
-
}
}
return NULL;
@@ -568,10 +731,11 @@ void ChatsManager::rebindControllerJID(const JID& from, const JID& to) {
chatControllers_[to]->setToJID(to);
}
-void ChatsManager::handleJoinMUCRequest(const JID &mucJID, const boost::optional<std::string>& password, const boost::optional<std::string>& nickMaybe, bool addAutoJoin, bool createAsReservedIfNew) {
+MUC::ref ChatsManager::handleJoinMUCRequest(const JID &mucJID, const boost::optional<std::string>& password, const boost::optional<std::string>& nickMaybe, bool addAutoJoin, bool createAsReservedIfNew, bool isImpromptu, ChatWindow* reuseChatwindow) {
+ MUC::ref muc;
if (!stanzaChannel_->isAvailable()) {
/* This is potentially not the optimal solution, but it will avoid consistency issues.*/
- return;
+ return muc;
}
if (addAutoJoin) {
MUCBookmark bookmark(mucJID, mucJID.getNode());
@@ -590,11 +754,27 @@ void ChatsManager::handleJoinMUCRequest(const JID &mucJID, const boost::optional
it->second->rejoin();
} else {
std::string nick = (nickMaybe && !(*nickMaybe).empty()) ? nickMaybe.get() : nickResolver_->jidToNick(jid_);
- MUC::ref muc = mucManager->createMUC(mucJID);
+ muc = mucManager->createMUC(mucJID);
if (createAsReservedIfNew) {
muc->setCreateAsReservedIfNew();
}
- MUCController* controller = new MUCController(jid_, muc, password, nick, stanzaChannel_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory_, eventController_, entityCapsProvider_, roster_, historyController_, mucRegistry_);
+ if (isImpromptu) {
+ muc->setCreateAsReservedIfNew();
+ }
+
+ MUCController* controller = NULL;
+ SingleChatWindowFactoryAdapter* chatWindowFactoryAdapter = NULL;
+ if (reuseChatwindow) {
+ chatWindowFactoryAdapter = new SingleChatWindowFactoryAdapter(reuseChatwindow);
+ }
+ controller = new MUCController(jid_, muc, password, nick, stanzaChannel_, iqRouter_, reuseChatwindow ? chatWindowFactoryAdapter : chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory_, eventController_, entityCapsProvider_, roster_, historyController_, mucRegistry_, highlightManager_, chatMessageParser_, isImpromptu, autoAcceptMUCInviteDecider_);
+ 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
+ * are also deleted there.*/
+ chatWindowFactoryAdapters_[controller] = chatWindowFactoryAdapter;
+ }
+
mucControllers_[mucJID] = controller;
controller->setAvailableServerFeatures(serverDiscoInfo_);
controller->onUserLeft.connect(boost::bind(&ChatsManager::handleUserLeftMUC, this, controller));
@@ -605,6 +785,7 @@ void ChatsManager::handleJoinMUCRequest(const JID &mucJID, const boost::optional
}
mucControllers_[mucJID]->showChatWindow();
+ return muc;
}
void ChatsManager::handleSearchMUCRequest() {
@@ -635,7 +816,25 @@ void ChatsManager::handleIncomingMessage(boost::shared_ptr<Message> message) {
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(jid);
+ if (controller) {
+ ChatWindow* window = controller->detachChatWindow();
+ chatControllers_.erase(jid);
+ delete controller;
+ handleJoinMUCRequest(invite->getJID(), boost::optional<std::string>(), boost::optional<std::string>(), false, false, true, window);
+ }
+ } else {
+ handleJoinMUCRequest(invite->getJID(), boost::optional<std::string>(), boost::optional<std::string>(), false, false, true);
+ return;
+ }
+ }
+
//if not a mucroom
if (!event->isReadable() && !isInvite && !isMediatedInvite) {
/* Only route such messages if a window exists, don't open new windows for them.*/
@@ -688,7 +887,15 @@ void ChatsManager::handleWhiteboardStateChange(const JID& contact, const ChatWin
}
void ChatsManager::handleRecentActivated(const ChatListWindow::Chat& chat) {
- if (chat.isMUC) {
+ if (chat.isMUC && !chat.impromptuJIDs.empty()) {
+ typedef std::pair<std::string, JID> StringJIDPair;
+ std::vector<JID> inviteJIDs;
+ foreach(StringJIDPair pair, chat.impromptuJIDs) {
+ inviteJIDs.push_back(pair.second);
+ }
+ uiEventStream_->send(boost::make_shared<CreateImpromptuMUCUIEvent>(inviteJIDs, chat.jid, ""));
+ }
+ else if (chat.isMUC) {
/* FIXME: This means that recents requiring passwords will just flat-out not work */
uiEventStream_->send(boost::make_shared<JoinMUCUIEvent>(chat.jid, boost::optional<std::string>(), chat.nick));
}
@@ -697,4 +904,42 @@ void ChatsManager::handleRecentActivated(const ChatListWindow::Chat& chat) {
}
}
+void ChatsManager::handleLocalServiceFound(const JID& service, boost::shared_ptr<DiscoInfo> info) {
+ foreach (DiscoInfo::Identity identity, info->getIdentities()) {
+ if ((identity.getCategory() == "directory"
+ && identity.getType() == "chatroom")
+ || (identity.getCategory() == "conference"
+ && identity.getType() == "text")) {
+ localMUCServiceJID_ = service;
+ localMUCServiceFinderWalker_->endWalk();
+ SWIFT_LOG(debug) << "Use following MUC service for impromptu chats: " << localMUCServiceJID_ << std::endl;
+ break;
+ }
+ }
+}
+
+void ChatsManager::handleLocalServiceWalkFinished() {
+ onImpromptuMUCServiceDiscovered(!localMUCServiceJID_.toString().empty());
+}
+
+std::vector<ChatListWindow::Chat> ChatsManager::getRecentChats() const {
+ return std::vector<ChatListWindow::Chat>(recentChats_.begin(), recentChats_.end());
+}
+
+std::vector<Contact> Swift::ChatsManager::getContacts() {
+ std::vector<Contact> result;
+ foreach (ChatListWindow::Chat chat, recentChats_) {
+ if (!chat.isMUC) {
+ result.push_back(Contact(chat.chatName.empty() ? chat.jid.toString() : chat.chatName, chat.jid, chat.statusType, chat.avatarPath));
+ }
+ }
+ return result;
+}
+
+ChatsManager::SingleChatWindowFactoryAdapter::SingleChatWindowFactoryAdapter(ChatWindow* chatWindow) : chatWindow_(chatWindow) {}
+ChatsManager::SingleChatWindowFactoryAdapter::~SingleChatWindowFactoryAdapter() {}
+ChatWindow* ChatsManager::SingleChatWindowFactoryAdapter::createChatWindow(const JID &, UIEventStream*) {
+ return chatWindow_;
+}
+
}
diff --git a/Swift/Controllers/Chat/ChatsManager.h b/Swift/Controllers/Chat/ChatsManager.h
index 5b8b785..c9dd856 100644
--- a/Swift/Controllers/Chat/ChatsManager.h
+++ b/Swift/Controllers/Chat/ChatsManager.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2011 Kevin Smith
+ * Copyright (c) 2010-2013 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -7,19 +7,26 @@
#pragma once
#include <map>
+#include <string>
#include <boost/shared_ptr.hpp>
-#include <string>
+#include <Swiften/Base/IDGenerator.h>
#include <Swiften/Elements/DiscoInfo.h>
#include <Swiften/Elements/Message.h>
#include <Swiften/Elements/Presence.h>
#include <Swiften/JID/JID.h>
#include <Swiften/MUC/MUCRegistry.h>
+#include <Swiften/MUC/MUCBookmark.h>
+#include <Swiften/MUC/MUC.h>
+
+
+#include <Swift/Controllers/ContactProvider.h>
#include <Swift/Controllers/UIEvents/UIEventStream.h>
#include <Swift/Controllers/UIInterfaces/ChatListWindow.h>
#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
-#include <Swiften/MUC/MUCBookmark.h>
+#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h>
+
namespace Swift {
class EventController;
@@ -27,7 +34,6 @@ namespace Swift {
class ChatControllerBase;
class MUCController;
class MUCManager;
- class ChatWindowFactory;
class JoinMUCWindow;
class JoinMUCWindowFactory;
class NickResolver;
@@ -50,20 +56,42 @@ namespace Swift {
class SettingsProvider;
class WhiteboardManager;
class HistoryController;
-
- class ChatsManager {
+ class HighlightManager;
+ class ClientBlockListManager;
+ class ChatMessageParser;
+ class DiscoServiceWalker;
+ class AutoAcceptMUCInviteDecider;
+ class UserSearchController;
+
+ class ChatsManager : public ContactProvider {
public:
- ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, JoinMUCWindowFactory* joinMUCWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, PresenceSender* presenceSender, UIEventStream* uiEventStream, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency, TimerFactory* timerFactory, MUCRegistry* mucRegistry, EntityCapsProvider* entityCapsProvider, MUCManager* mucManager, MUCSearchWindowFactory* mucSearchWindowFactory, ProfileSettingsProvider* profileSettings, FileTransferOverview* ftOverview, XMPPRoster* roster, bool eagleMode, SettingsProvider* settings, HistoryController* historyController_, WhiteboardManager* whiteboardManager);
+ ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, JoinMUCWindowFactory* joinMUCWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, PresenceSender* presenceSender, UIEventStream* uiEventStream, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency, TimerFactory* timerFactory, MUCRegistry* mucRegistry, EntityCapsProvider* entityCapsProvider, MUCManager* mucManager, MUCSearchWindowFactory* mucSearchWindowFactory, ProfileSettingsProvider* profileSettings, FileTransferOverview* ftOverview, XMPPRoster* roster, bool eagleMode, SettingsProvider* settings, HistoryController* historyController_, WhiteboardManager* whiteboardManager, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, const std::map<std::string, std::string>& emoticons, UserSearchController* inviteUserSearchController);
virtual ~ChatsManager();
void setAvatarManager(AvatarManager* avatarManager);
void setOnline(bool enabled);
void setServerDiscoInfo(boost::shared_ptr<DiscoInfo> info);
void handleIncomingMessage(boost::shared_ptr<Message> message);
+ std::vector<ChatListWindow::Chat> getRecentChats() const;
+ virtual std::vector<Contact> getContacts();
+
+ boost::signal<void (bool supportsImpromptu)> onImpromptuMUCServiceDiscovered;
+
+ private:
+ class SingleChatWindowFactoryAdapter : public ChatWindowFactory {
+ public:
+ SingleChatWindowFactoryAdapter(ChatWindow* chatWindow);
+ virtual ~SingleChatWindowFactoryAdapter();
+ virtual ChatWindow* createChatWindow(const JID &, UIEventStream*);
+
+ private:
+ ChatWindow* chatWindow_;
+ };
private:
ChatListWindow::Chat createChatListChatItem(const JID& jid, const std::string& activity);
void handleChatRequest(const std::string& contact);
- void handleJoinMUCRequest(const JID& muc, const boost::optional<std::string>& password, const boost::optional<std::string>& nick, bool addAutoJoin, bool createAsReservedIfNew);
+ void finalizeImpromptuJoin(MUC::ref muc, const std::vector<JID>& jidsToInvite, const std::string& reason, const boost::optional<JID>& reuseChatJID = boost::optional<JID>());
+ MUC::ref handleJoinMUCRequest(const JID& muc, const boost::optional<std::string>& password, const boost::optional<std::string>& nick, bool addAutoJoin, bool createAsReservedIfNew, bool isImpromptu, ChatWindow* reuseChatwindow = 0);
void handleSearchMUCRequest();
void handleMUCSelectedAfterSearch(const JID&);
void rebindControllerJID(const JID& from, const JID& to);
@@ -77,6 +105,7 @@ namespace Swift {
void handleNewFileTransferController(FileTransferController*);
void handleWhiteboardSessionRequest(const JID& contact, bool senderIsSelf);
void handleWhiteboardStateChange(const JID& contact, const ChatWindow::WhiteboardSessionState state);
+ boost::optional<ChatListWindow::Chat> removeExistingChat(const ChatListWindow::Chat& chat);
void appendRecent(const ChatListWindow::Chat& chat);
void prependRecent(const ChatListWindow::Chat& chat);
void setupBookmarks();
@@ -94,8 +123,14 @@ namespace Swift {
void handleRosterCleared();
void handleSettingChanged(const std::string& settingPath);
void markAllRecentsOffline();
+ void handleTransformChatToMUC(ChatController* chatController, ChatWindow* chatWindow, const std::vector<JID>& jidsToInvite, const std::string& reason);
+
+ void handleLocalServiceFound(const JID& service, boost::shared_ptr<DiscoInfo> info);
+ void handleLocalServiceWalkFinished();
void updatePresenceReceivingStateOnChatController(const JID&);
+ ChatListWindow::Chat updateChatStatusAndAvatarHelper(const ChatListWindow::Chat& chat) const;
+
ChatController* getChatControllerOrFindAnother(const JID &contact);
ChatController* createNewChatController(const JID &contact);
@@ -105,6 +140,7 @@ namespace Swift {
private:
std::map<JID, MUCController*> mucControllers_;
std::map<JID, ChatController*> chatControllers_;
+ std::map<ChatControllerBase*, SingleChatWindowFactoryAdapter*> chatWindowFactoryAdapters_;
EventController* eventController_;
JID jid_;
StanzaChannel* stanzaChannel_;
@@ -136,5 +172,13 @@ namespace Swift {
SettingsProvider* settings_;
HistoryController* historyController_;
WhiteboardManager* whiteboardManager_;
+ HighlightManager* highlightManager_;
+ ClientBlockListManager* clientBlockListManager_;
+ ChatMessageParser* chatMessageParser_;
+ JID localMUCServiceJID_;
+ boost::shared_ptr<DiscoServiceWalker> localMUCServiceFinderWalker_;
+ AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider_;
+ UserSearchController* inviteUserSearchController_;
+ IDGenerator idGenerator_;
};
}
diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp
index 50eee68..37631a5 100644
--- a/Swift/Controllers/Chat/MUCController.cpp
+++ b/Swift/Controllers/Chat/MUCController.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2013 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -19,11 +19,13 @@
#include <Swiften/Base/foreach.h>
#include <Swift/Controllers/XMPPEvents/EventController.h>
#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
-#include <Swift/Controllers/UIInterfaces/InviteToChatWindow.h>
#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h>
#include <Swift/Controllers/UIEvents/UIEventStream.h>
#include <Swift/Controllers/UIEvents/RequestChatUIEvent.h>
#include <Swift/Controllers/UIEvents/RequestAddUserDialogUIEvent.h>
+#include <Swift/Controllers/UIEvents/ShowProfileForRosterItemUIEvent.h>
+#include <Swift/Controllers/UIEvents/RequestInviteToMUCUIEvent.h>
+#include <Swift/Controllers/UIEvents/InviteToMUCUIEvent.h>
#include <Swift/Controllers/Roster/GroupRosterItem.h>
#include <Swift/Controllers/Roster/ContactRosterItem.h>
#include <Swiften/Avatars/AvatarManager.h>
@@ -35,7 +37,10 @@
#include <Swift/Controllers/Roster/SetPresence.h>
#include <Swiften/Disco/EntityCapsProvider.h>
#include <Swiften/Roster/XMPPRoster.h>
+#include <Swift/Controllers/Highlighter.h>
+#include <Swift/Controllers/Chat/ChatMessageParser.h>
+#include <Swiften/Base/Log.h>
#define MUC_JOIN_WARNING_TIMEOUT_MILLISECONDS 60000
@@ -61,22 +66,24 @@ MUCController::MUCController (
EntityCapsProvider* entityCapsProvider,
XMPPRoster* roster,
HistoryController* historyController,
- MUCRegistry* mucRegistry) :
- ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, muc->getJID(), presenceOracle, avatarManager, useDelayForLatency, uiEventStream, eventController, timerFactory, entityCapsProvider, historyController, mucRegistry), muc_(muc), nick_(nick), desiredNick_(nick), password_(password) {
+ MUCRegistry* mucRegistry,
+ HighlightManager* highlightManager,
+ ChatMessageParser* chatMessageParser,
+ bool isImpromptu,
+ AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider) :
+ ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, muc->getJID(), presenceOracle, avatarManager, useDelayForLatency, uiEventStream, eventController, timerFactory, entityCapsProvider, historyController, mucRegistry, highlightManager, chatMessageParser, autoAcceptMUCInviteDecider), muc_(muc), nick_(nick), desiredNick_(nick), password_(password), renameCounter_(0), isImpromptu_(isImpromptu), isImpromptuAlreadyConfigured_(false) {
parting_ = true;
joined_ = false;
lastWasPresence_ = false;
shouldJoinOnReconnect_ = true;
doneGettingHistory_ = false;
events_ = uiEventStream;
- inviteWindow_ = NULL;
xmppRoster_ = roster;
roster_ = new Roster(false, true);
completer_ = new TabComplete();
chatWindow_->setRosterModel(roster_);
chatWindow_->setTabComplete(completer_);
- chatWindow_->setName(muc->getJID().getNode());
chatWindow_->onClosed.connect(boost::bind(&MUCController::handleWindowClosed, this));
chatWindow_->onOccupantSelectionChanged.connect(boost::bind(&MUCController::handleWindowOccupantSelectionChanged, this, _1));
chatWindow_->onOccupantActionSelected.connect(boost::bind(&MUCController::handleActionRequestedOnOccupant, this, _1, _2));
@@ -84,7 +91,7 @@ MUCController::MUCController (
chatWindow_->onConfigureRequest.connect(boost::bind(&MUCController::handleConfigureRequest, this, _1));
chatWindow_->onConfigurationFormCancelled.connect(boost::bind(&MUCController::handleConfigurationCancelled, this));
chatWindow_->onDestroyRequest.connect(boost::bind(&MUCController::handleDestroyRoomRequest, this));
- chatWindow_->onInvitePersonToThisMUCRequest.connect(boost::bind(&MUCController::handleInvitePersonToThisMUCRequest, this));
+ chatWindow_->onInviteToChat.connect(boost::bind(&MUCController::handleInvitePersonToThisMUCRequest, this, _1));
chatWindow_->onGetAffiliationsRequest.connect(boost::bind(&MUCController::handleGetAffiliationsRequest, this));
chatWindow_->onChangeAffiliationsRequest.connect(boost::bind(&MUCController::handleChangeAffiliationsRequest, this, _1));
muc_->onJoinComplete.connect(boost::bind(&MUCController::handleJoinComplete, this, _1));
@@ -94,24 +101,34 @@ MUCController::MUCController (
muc_->onOccupantLeft.connect(boost::bind(&MUCController::handleOccupantLeft, this, _1, _2, _3));
muc_->onOccupantRoleChanged.connect(boost::bind(&MUCController::handleOccupantRoleChanged, this, _1, _2, _3));
muc_->onOccupantAffiliationChanged.connect(boost::bind(&MUCController::handleOccupantAffiliationChanged, this, _1, _2, _3));
- muc_->onConfigurationFailed.connect(boost::bind(&MUCController::handleConfigurationFailed, this, _1));
- muc_->onConfigurationFormReceived.connect(boost::bind(&MUCController::handleConfigurationFormReceived, this, _1));
muc_->onRoleChangeFailed.connect(boost::bind(&MUCController::handleOccupantRoleChangeFailed, this, _1, _2, _3));
muc_->onAffiliationListReceived.connect(boost::bind(&MUCController::handleAffiliationListReceived, this, _1, _2));
+ muc_->onConfigurationFailed.connect(boost::bind(&MUCController::handleConfigurationFailed, this, _1));
+ muc_->onConfigurationFormReceived.connect(boost::bind(&MUCController::handleConfigurationFormReceived, this, _1));
+ highlighter_->setMode(Highlighter::MUCMode);
+ highlighter_->setNick(nick_);
if (timerFactory) {
loginCheckTimer_ = boost::shared_ptr<Timer>(timerFactory->createTimer(MUC_JOIN_WARNING_TIMEOUT_MILLISECONDS));
loginCheckTimer_->onTick.connect(boost::bind(&MUCController::handleJoinTimeoutTick, this));
loginCheckTimer_->start();
}
- chatWindow_->convertToMUC();
+ if (isImpromptu) {
+ muc_->onUnlocked.connect(boost::bind(&MUCController::handleRoomUnlocked, this));
+ chatWindow_->convertToMUC(true);
+ } else {
+ chatWindow_->convertToMUC();
+ chatWindow_->setName(muc->getJID().getNode());
+ }
setOnline(true);
if (avatarManager_ != NULL) {
avatarChangedConnection_ = (avatarManager_->onAvatarChanged.connect(boost::bind(&MUCController::handleAvatarChanged, this, _1)));
}
handleBareJIDCapsChanged(muc->getJID());
+ eventStream_->onUIEvent.connect(boost::bind(&MUCController::handleUIEvent, this, _1));
}
MUCController::~MUCController() {
+ eventStream_->onUIEvent.disconnect(boost::bind(&MUCController::handleUIEvent, this, _1));
chatWindow_->setRosterModel(NULL);
delete roster_;
if (loginCheckTimer_) {
@@ -146,6 +163,7 @@ void MUCController::handleWindowOccupantSelectionChanged(ContactRosterItem* item
if (muc_->getOccupant(item->getJID().getResource()).getRealJID()) {
actions.push_back(ChatWindow::AddContact);
}
+ actions.push_back(ChatWindow::ShowProfile);
}
chatWindow_->setAvailableOccupantActions(actions);
}
@@ -164,6 +182,7 @@ void MUCController::handleActionRequestedOnOccupant(ChatWindow::OccupantAction a
case ChatWindow::MakeParticipant: muc_->changeOccupantRole(mucJID, MUCOccupant::Participant);break;
case ChatWindow::MakeVisitor: muc_->changeOccupantRole(mucJID, MUCOccupant::Visitor);break;
case ChatWindow::AddContact: if (occupant.getRealJID()) events_->send(boost::make_shared<RequestAddUserDialogUIEvent>(realJID, occupant.getNick()));break;
+ case ChatWindow::ShowProfile: events_->send(boost::make_shared<ShowProfileForRosterItemUIEvent>(mucJID));break;
}
}
@@ -217,9 +236,31 @@ const std::string& MUCController::getNick() {
return nick_;
}
+bool MUCController::isImpromptu() const {
+ return isImpromptu_;
+}
+
+std::map<std::string, JID> MUCController::getParticipantJIDs() const {
+ std::map<std::string, JID> participants;
+ typedef std::pair<std::string, MUCOccupant> MUCOccupantPair;
+ std::map<std::string, MUCOccupant> occupants = muc_->getOccupants();
+ foreach(const MUCOccupantPair& occupant, occupants) {
+ if (occupant.first != nick_) {
+ participants[occupant.first] = occupant.second.getRealJID().is_initialized() ? occupant.second.getRealJID().get().toBare() : JID();
+ }
+ }
+ return participants;
+}
+
+void MUCController::sendInvites(const std::vector<JID>& jids, const std::string& reason) const {
+ foreach (const JID& jid, jids) {
+ muc_->invitePerson(jid, reason, isImpromptu_);
+ }
+}
+
void MUCController::handleJoinTimeoutTick() {
receivedActivity();
- chatWindow_->addSystemMessage(str(format(QT_TRANSLATE_NOOP("", "Room %1% is not responding. This operation may never complete.")) % toJID_.toString()));
+ chatWindow_->addSystemMessage(chatMessageParser_->parseMessageBody(str(format(QT_TRANSLATE_NOOP("", "Room %1% is not responding. This operation may never complete.")) % toJID_.toString())), ChatWindow::DefaultDirection);
}
void MUCController::receivedActivity() {
@@ -228,6 +269,9 @@ void MUCController::receivedActivity() {
}
}
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wswitch-enum"
+
void MUCController::handleJoinFailed(boost::shared_ptr<ErrorPayload> error) {
receivedActivity();
std::string errorMessage = QT_TRANSLATE_NOOP("", "Unable to enter this room");
@@ -267,20 +311,29 @@ void MUCController::handleJoinFailed(boost::shared_ptr<ErrorPayload> error) {
}
}
errorMessage = str(format(QT_TRANSLATE_NOOP("", "Couldn't join room: %1%.")) % errorMessage);
- chatWindow_->addErrorMessage(errorMessage);
+ chatWindow_->addErrorMessage(chatMessageParser_->parseMessageBody(errorMessage));
parting_ = true;
- if (!rejoinNick.empty()) {
- nick_ = rejoinNick;
+ if (!rejoinNick.empty() && renameCounter_ < 10) {
+ renameCounter_++;
+ setNick(rejoinNick);
rejoin();
}
}
+#pragma clang diagnostic pop
+
void MUCController::handleJoinComplete(const std::string& nick) {
receivedActivity();
+ renameCounter_ = 0;
joined_ = true;
- std::string joinMessage = str(format(QT_TRANSLATE_NOOP("", "You have entered room %1% as %2%.")) % toJID_.toString() % nick);
- nick_ = nick;
- chatWindow_->addSystemMessage(joinMessage);
+ std::string joinMessage;
+ if (isImpromptu_) {
+ joinMessage = str(format(QT_TRANSLATE_NOOP("", "You have entered chat as %1%.")) % nick);
+ } else {
+ joinMessage = str(format(QT_TRANSLATE_NOOP("", "You have entered room %1% as %2%.")) % toJID_.toString() % nick);
+ }
+ setNick(nick);
+ chatWindow_->addSystemMessage(chatMessageParser_->parseMessageBody(joinMessage), ChatWindow::DefaultDirection);
#ifdef SWIFT_EXPERIMENTAL_HISTORY
addRecentLogs();
@@ -292,14 +345,17 @@ void MUCController::handleJoinComplete(const std::string& nick) {
MUCOccupant occupant = muc_->getOccupant(nick);
setAvailableRoomActions(occupant.getAffiliation(), occupant.getRole());
onUserJoined();
+
+ if (isImpromptu_) {
+ setImpromptuWindowTitle();
+ }
}
void MUCController::handleAvatarChanged(const JID& jid) {
if (parting_ || !jid.equals(toJID_, JID::WithoutResource)) {
return;
}
- std::string path = avatarManager_->getAvatarPath(jid).string();
- roster_->applyOnItems(SetAvatar(jid, path, JID::WithResource));
+ roster_->applyOnItems(SetAvatar(jid, avatarManager_->getAvatarPath(jid), JID::WithResource));
}
void MUCController::handleWindowClosed() {
@@ -323,22 +379,26 @@ void MUCController::handleOccupantJoined(const MUCOccupant& occupant) {
NickJoinPart event(occupant.getNick(), Join);
appendToJoinParts(joinParts_, event);
std::string groupName(roleToGroupName(occupant.getRole()));
- roster_->addContact(jid, realJID, occupant.getNick(), groupName, avatarManager_->getAvatarPath(jid).string());
+ roster_->addContact(jid, realJID, occupant.getNick(), groupName, avatarManager_->getAvatarPath(jid));
roster_->getGroup(groupName)->setManualSort(roleToSortName(occupant.getRole()));
if (joined_) {
std::string joinString;
MUCOccupant::Role role = occupant.getRole();
if (role != MUCOccupant::NoRole && role != MUCOccupant::Participant) {
- joinString = str(format(QT_TRANSLATE_NOOP("", "%1% has entered the room as a %2%.")) % occupant.getNick() % roleToFriendlyName(role));
+ joinString = str(format(QT_TRANSLATE_NOOP("", "%1% has entered the %3% as a %2%.")) % occupant.getNick() % roleToFriendlyName(role) % (isImpromptu_ ? QT_TRANSLATE_NOOP("", "chat") : QT_TRANSLATE_NOOP("", "room")));
}
else {
- joinString = str(format(QT_TRANSLATE_NOOP("", "%1% has entered the room.")) % occupant.getNick());
+ joinString = str(format(QT_TRANSLATE_NOOP("", "%1% has entered the %2%.")) % occupant.getNick() % (isImpromptu_ ? QT_TRANSLATE_NOOP("", "chat") : QT_TRANSLATE_NOOP("", "room")));
}
if (shouldUpdateJoinParts()) {
updateJoinParts();
} else {
addPresenceMessage(joinString);
+ }
+ if (isImpromptu_) {
+ setImpromptuWindowTitle();
+ onActivity("");
}
}
if (avatarManager_ != NULL) {
@@ -348,7 +408,7 @@ void MUCController::handleOccupantJoined(const MUCOccupant& occupant) {
void MUCController::addPresenceMessage(const std::string& message) {
lastWasPresence_ = true;
- chatWindow_->addPresenceMessage(message);
+ chatWindow_->addPresenceMessage(chatMessageParser_->parseMessageBody(message), ChatWindow::DefaultDirection);
}
@@ -386,6 +446,7 @@ std::string MUCController::roleToFriendlyName(MUCOccupant::Role role) {
case MUCOccupant::Visitor: return QT_TRANSLATE_NOOP("", "visitor");
case MUCOccupant::NoRole: return "";
}
+ assert(false);
return "";
}
@@ -396,6 +457,7 @@ std::string MUCController::roleToSortName(MUCOccupant::Role role) {
case MUCOccupant::Visitor: return "3";
case MUCOccupant::NoRole: return "4";
}
+ assert(false);
return "5";
}
@@ -433,7 +495,7 @@ void MUCController::preHandleIncomingMessage(boost::shared_ptr<MessageEvent> mes
joined_ = true;
if (message->hasSubject() && message->getBody().empty()) {
- chatWindow_->addSystemMessage(str(format(QT_TRANSLATE_NOOP("", "The room subject is now: %1%")) % message->getSubject()));;
+ chatWindow_->addSystemMessage(chatMessageParser_->parseMessageBody(str(format(QT_TRANSLATE_NOOP("", "The room subject is now: %1%")) % message->getSubject())), ChatWindow::DefaultDirection);;
chatWindow_->setSubject(message->getSubject());
doneGettingHistory_ = true;
}
@@ -448,10 +510,13 @@ void MUCController::preHandleIncomingMessage(boost::shared_ptr<MessageEvent> mes
}
}
-void MUCController::postHandleIncomingMessage(boost::shared_ptr<MessageEvent> messageEvent) {
+void MUCController::postHandleIncomingMessage(boost::shared_ptr<MessageEvent> messageEvent, const HighlightAction& highlight) {
boost::shared_ptr<Message> message = messageEvent->getStanza();
if (joined_ && messageEvent->getStanza()->getFrom().getResource() != nick_ && messageTargetsMe(message) && !message->getPayload<Delay>()) {
eventController_->handleIncomingEvent(messageEvent);
+ if (!messageEvent->getConcluded()) {
+ highlighter_->handleHighlightAction(highlight);
+ }
}
}
@@ -465,9 +530,9 @@ void MUCController::handleOccupantRoleChanged(const std::string& nick, const MUC
realJID = occupant.getRealJID().get();
}
std::string group(roleToGroupName(occupant.getRole()));
- roster_->addContact(jid, realJID, nick, group, avatarManager_->getAvatarPath(jid).string());
+ roster_->addContact(jid, realJID, nick, group, avatarManager_->getAvatarPath(jid));
roster_->getGroup(group)->setManualSort(roleToSortName(occupant.getRole()));
- chatWindow_->addSystemMessage(str(format(QT_TRANSLATE_NOOP("", "%1% is now a %2%")) % nick % roleToFriendlyName(occupant.getRole())));
+ chatWindow_->addSystemMessage(chatMessageParser_->parseMessageBody(str(format(QT_TRANSLATE_NOOP("", "%1% is now a %2%")) % nick % roleToFriendlyName(occupant.getRole()))), ChatWindow::DefaultDirection);
if (nick == nick_) {
setAvailableRoomActions(occupant.getAffiliation(), occupant.getRole());
}
@@ -487,7 +552,6 @@ std::string MUCController::roleToGroupName(MUCOccupant::Role role) {
case MUCOccupant::Participant: result = QT_TRANSLATE_NOOP("", "Participants"); break;
case MUCOccupant::Visitor: result = QT_TRANSLATE_NOOP("", "Visitors"); break;
case MUCOccupant::NoRole: result = QT_TRANSLATE_NOOP("", "Occupants"); break;
- default: assert(false);
}
return result;
}
@@ -500,11 +564,16 @@ void MUCController::setOnline(bool online) {
processUserPart();
} else {
if (shouldJoinOnReconnect_) {
- chatWindow_->addSystemMessage(str(format(QT_TRANSLATE_NOOP("", "Trying to enter room %1%")) % toJID_.toString()));
+ renameCounter_ = 0;
+ if (isImpromptu_) {
+ chatWindow_->addSystemMessage(chatMessageParser_->parseMessageBody(QT_TRANSLATE_NOOP("", "Trying to enter chat")), ChatWindow::DefaultDirection);
+ } else {
+ chatWindow_->addSystemMessage(chatMessageParser_->parseMessageBody(str(format(QT_TRANSLATE_NOOP("", "Trying to enter room %1%")) % toJID_.toString())), ChatWindow::DefaultDirection);
+ }
if (loginCheckTimer_) {
loginCheckTimer_->start();
}
- nick_ = desiredNick_;
+ setNick(desiredNick_);
rejoin();
}
}
@@ -573,6 +642,10 @@ void MUCController::handleOccupantLeft(const MUCOccupant& occupant, MUC::Leaving
if (clearAfter) {
clearPresenceQueue();
}
+
+ if (isImpromptu_) {
+ setImpromptuWindowTitle();
+ }
}
void MUCController::handleOccupantPresenceChange(boost::shared_ptr<Presence> presence) {
@@ -598,7 +671,7 @@ boost::optional<boost::posix_time::ptime> MUCController::getMessageTimestamp(boo
}
void MUCController::updateJoinParts() {
- chatWindow_->replaceLastMessage(generateJoinPartString(joinParts_));
+ chatWindow_->replaceLastMessage(chatMessageParser_->parseMessageBody(generateJoinPartString(joinParts_, isImpromptu())));
}
void MUCController::appendToJoinParts(std::vector<NickJoinPart>& joinParts, const NickJoinPart& newEvent) {
@@ -611,7 +684,8 @@ void MUCController::appendToJoinParts(std::vector<NickJoinPart>& joinParts, cons
switch (newEvent.type) {
case Join: type = (type == Part) ? PartThenJoin : Join; break;
case Part: type = (type == Join) ? JoinThenPart : Part; break;
- default: /*Nothing to see here */;break;
+ case PartThenJoin: break;
+ case JoinThenPart: break;
}
(*it).type = type;
break;
@@ -638,7 +712,7 @@ std::string MUCController::concatenateListOfNames(const std::vector<NickJoinPart
return result;
}
-std::string MUCController::generateJoinPartString(const std::vector<NickJoinPart>& joinParts) {
+std::string MUCController::generateJoinPartString(const std::vector<NickJoinPart>& joinParts, bool isImpromptu) {
std::vector<NickJoinPart> sorted[4];
std::string eventStrings[4];
foreach (NickJoinPart event, joinParts) {
@@ -653,34 +727,34 @@ std::string MUCController::generateJoinPartString(const std::vector<NickJoinPart
switch (i) {
case Join:
if (sorted[i].size() > 1) {
- eventString = QT_TRANSLATE_NOOP("", "%1% have entered the room");
+ eventString = (isImpromptu ? QT_TRANSLATE_NOOP("", "%1% have joined the chat") : QT_TRANSLATE_NOOP("", "%1% have entered the room"));
}
else {
- eventString = QT_TRANSLATE_NOOP("", "%1% has entered the room");
+ eventString = (isImpromptu ? QT_TRANSLATE_NOOP("", "%1% has joined the chat") : QT_TRANSLATE_NOOP("", "%1% has entered the room"));
}
break;
case Part:
if (sorted[i].size() > 1) {
- eventString = QT_TRANSLATE_NOOP("", "%1% have left the room");
+ eventString = (isImpromptu ? QT_TRANSLATE_NOOP("", "%1% have left the chat") : QT_TRANSLATE_NOOP("", "%1% have left the room"));
}
else {
- eventString = QT_TRANSLATE_NOOP("", "%1% has left the room");
+ eventString = (isImpromptu ? QT_TRANSLATE_NOOP("", "%1% have left the chat") : QT_TRANSLATE_NOOP("", "%1% has left the room"));
}
break;
case JoinThenPart:
if (sorted[i].size() > 1) {
- eventString = QT_TRANSLATE_NOOP("", "%1% have entered then left the room");
+ eventString = (isImpromptu ? QT_TRANSLATE_NOOP("", "%1% have joined then left the chat") : QT_TRANSLATE_NOOP("", "%1% have entered then left the room"));
}
else {
- eventString = QT_TRANSLATE_NOOP("", "%1% has entered then left the room");
+ eventString = (isImpromptu ? QT_TRANSLATE_NOOP("", "%1% has joined then left the chat") : QT_TRANSLATE_NOOP("", "%1% has entered then left the room"));
}
break;
case PartThenJoin:
if (sorted[i].size() > 1) {
- eventString = QT_TRANSLATE_NOOP("", "%1% have left then returned to the room");
+ eventString = (isImpromptu ? QT_TRANSLATE_NOOP("", "%1% have left then returned to the chat") : QT_TRANSLATE_NOOP("", "%1% have left then returned to the room"));
}
else {
- eventString = QT_TRANSLATE_NOOP("", "%1% has left then returned to the room");
+ eventString = (isImpromptu ? QT_TRANSLATE_NOOP("", "%1% has left then returned to the chat") : QT_TRANSLATE_NOOP("", "%1% has left then returned to the room"));
}
break;
}
@@ -717,17 +791,29 @@ void MUCController::handleConfigureRequest(Form::ref form) {
void MUCController::handleConfigurationFailed(ErrorPayload::ref error) {
std::string errorMessage = getErrorMessage(error);
errorMessage = str(format(QT_TRANSLATE_NOOP("", "Room configuration failed: %1%.")) % errorMessage);
- chatWindow_->addErrorMessage(errorMessage);
+ chatWindow_->addErrorMessage(chatMessageParser_->parseMessageBody(errorMessage));
}
void MUCController::handleOccupantRoleChangeFailed(ErrorPayload::ref error, const JID&, MUCOccupant::Role) {
std::string errorMessage = getErrorMessage(error);
errorMessage = str(format(QT_TRANSLATE_NOOP("", "Occupant role change failed: %1%.")) % errorMessage);
- chatWindow_->addErrorMessage(errorMessage);
+ chatWindow_->addErrorMessage(chatMessageParser_->parseMessageBody(errorMessage));
+}
+
+void MUCController::configureAsImpromptuRoom(Form::ref form) {
+ muc_->configureRoom(buildImpromptuRoomConfiguration(form));
+ isImpromptuAlreadyConfigured_ = true;
+ onImpromptuConfigCompleted();
}
void MUCController::handleConfigurationFormReceived(Form::ref form) {
- chatWindow_->showRoomConfigurationForm(form);
+ if (isImpromptu_) {
+ if (!isImpromptuAlreadyConfigured_) {
+ configureAsImpromptuRoom(form);
+ }
+ } else {
+ chatWindow_->showRoomConfigurationForm(form);
+ }
}
void MUCController::handleConfigurationCancelled() {
@@ -738,32 +824,18 @@ void MUCController::handleDestroyRoomRequest() {
muc_->destroyRoom();
}
-void MUCController::handleInvitePersonToThisMUCRequest() {
- if (!inviteWindow_) {
- inviteWindow_ = chatWindow_->createInviteToChatWindow();
- inviteWindow_->onCompleted.connect(boost::bind(&MUCController::handleInviteToMUCWindowCompleted, this));
- inviteWindow_->onDismissed.connect(boost::bind(&MUCController::handleInviteToMUCWindowDismissed, this));
- }
- std::vector<std::pair<JID, std::string> > autoCompletes;
- foreach (XMPPRosterItem item, xmppRoster_->getItems()) {
- std::pair<JID, std::string> jidName;
- jidName.first = item.getJID();
- jidName.second = item.getName();
- autoCompletes.push_back(jidName);
- //std::cerr << "MUCController adding " << item.getJID().toString() << std::endl;
- }
- inviteWindow_->setAutoCompletions(autoCompletes);
-}
-
-void MUCController::handleInviteToMUCWindowDismissed() {
- inviteWindow_= NULL;
+void MUCController::handleInvitePersonToThisMUCRequest(const std::vector<JID>& jidsToInvite) {
+ boost::shared_ptr<UIEvent> event(new RequestInviteToMUCUIEvent(muc_->getJID(), jidsToInvite));
+ eventStream_->send(event);
}
-void MUCController::handleInviteToMUCWindowCompleted() {
- foreach (const JID& jid, inviteWindow_->getJIDs()) {
- muc_->invitePerson(jid, inviteWindow_->getReason());
+void MUCController::handleUIEvent(boost::shared_ptr<UIEvent> event) {
+ boost::shared_ptr<InviteToMUCUIEvent> inviteEvent = boost::dynamic_pointer_cast<InviteToMUCUIEvent>(event);
+ if (inviteEvent && inviteEvent->getRoom() == muc_->getJID()) {
+ foreach (const JID& jid, inviteEvent->getInvites()) {
+ muc_->invitePerson(jid, inviteEvent->getReason(), isImpromptu_);
+ }
}
- inviteWindow_ = NULL;
}
void MUCController::handleGetAffiliationsRequest() {
@@ -811,7 +883,7 @@ void MUCController::addRecentLogs() {
bool senderIsSelf = nick_ == message.getFromJID().getResource();
// the chatWindow uses utc timestamps
- addMessage(message.getMessage(), senderDisplayNameFromMessage(message.getFromJID()), senderIsSelf, boost::shared_ptr<SecurityLabel>(new SecurityLabel()), std::string(avatarManager_->getAvatarPath(message.getFromJID()).string()), message.getTime() - boost::posix_time::hours(message.getOffset()));
+ addMessage(message.getMessage(), senderDisplayNameFromMessage(message.getFromJID()), senderIsSelf, boost::shared_ptr<SecurityLabel>(new SecurityLabel()), avatarManager_->getAvatarPath(message.getFromJID()), message.getTime() - boost::posix_time::hours(message.getOffset()), HighlightAction());
}
}
@@ -840,4 +912,78 @@ void MUCController::checkDuplicates(boost::shared_ptr<Message> newMessage) {
}
}
+void MUCController::setNick(const std::string& nick) {
+ nick_ = nick;
+ highlighter_->setNick(nick_);
+}
+
+Form::ref MUCController::buildImpromptuRoomConfiguration(Form::ref roomConfigurationForm) {
+ Form::ref result = boost::make_shared<Form>(Form::SubmitType);
+ std::string impromptuConfigs[] = { "muc#roomconfig_enablelogging", "muc#roomconfig_persistentroom", "muc#roomconfig_publicroom", "muc#roomconfig_whois"};
+ std::set<std::string> impromptuConfigsMissing(impromptuConfigs, impromptuConfigs + 4);
+ foreach (boost::shared_ptr<FormField> field, roomConfigurationForm->getFields()) {
+ boost::shared_ptr<FormField> resultField;
+ if (field->getName() == "muc#roomconfig_enablelogging") {
+ resultField = boost::make_shared<FormField>(FormField::BooleanType, "0");
+ }
+ if (field->getName() == "muc#roomconfig_persistentroom") {
+ resultField = boost::make_shared<FormField>(FormField::BooleanType, "0");
+ }
+ if (field->getName() == "muc#roomconfig_publicroom") {
+ resultField = boost::make_shared<FormField>(FormField::BooleanType, "0");
+ }
+ if (field->getName() == "muc#roomconfig_whois") {
+ resultField = boost::make_shared<FormField>(FormField::ListSingleType, "anyone");
+ }
+
+ if (field->getName() == "FORM_TYPE") {
+ resultField = boost::make_shared<FormField>(FormField::HiddenType, "http://jabber.org/protocol/muc#roomconfig");
+ }
+
+ if (resultField) {
+ impromptuConfigsMissing.erase(field->getName());
+ resultField->setName(field->getName());
+ result->addField(resultField);
+ }
+ }
+
+ foreach (const std::string& config, impromptuConfigsMissing) {
+ if (config == "muc#roomconfig_publicroom") {
+ chatWindow_->addSystemMessage(chatMessageParser_->parseMessageBody(QT_TRANSLATE_NOOP("", "This server doesn't support hiding your chat from other users.")), ChatWindow::DefaultDirection);
+ } else if (config == "muc#roomconfig_whois") {
+ chatWindow_->addSystemMessage(chatMessageParser_->parseMessageBody(QT_TRANSLATE_NOOP("", "This server doesn't support sharing people's real identity in this chat.")), ChatWindow::DefaultDirection);
+ }
+ }
+
+ return result;
+}
+
+void MUCController::setImpromptuWindowTitle() {
+ std::string title;
+ typedef std::pair<std::string, MUCOccupant> StringMUCOccupantPair;
+ std::map<std::string, MUCOccupant> occupants = muc_->getOccupants();
+ if (occupants.size() <= 1) {
+ title = QT_TRANSLATE_NOOP("", "Empty Chat");
+ } else {
+ foreach (StringMUCOccupantPair pair, occupants) {
+ if (pair.first != nick_) {
+ title += (title.empty() ? "" : ", ") + pair.first;
+ }
+ }
+ }
+ chatWindow_->setName(title);
+}
+
+void MUCController::handleRoomUnlocked() {
+ // Handle buggy MUC implementations where the joined room already exists and is unlocked.
+ // Configure the room again in this case.
+ if (!isImpromptuAlreadyConfigured_) {
+ if (isImpromptu_ && (muc_->getOccupant(nick_).getAffiliation() == MUCOccupant::Owner)) {
+ muc_->requestConfigurationForm();
+ } else if (isImpromptu_) {
+ onImpromptuConfigCompleted();
+ }
+ }
+}
+
}
diff --git a/Swift/Controllers/Chat/MUCController.h b/Swift/Controllers/Chat/MUCController.h
index 63893d0..9283438 100644
--- a/Swift/Controllers/Chat/MUCController.h
+++ b/Swift/Controllers/Chat/MUCController.h
@@ -1,24 +1,27 @@
/*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2013 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#pragma once
+#include <set>
+#include <string>
+#include <map>
+
#include <boost/shared_ptr.hpp>
-#include <Swiften/Base/boost_bsignals.h>
#include <boost/signals/connection.hpp>
-#include <set>
-#include <string>
+#include <Swiften/Base/boost_bsignals.h>
#include <Swiften/Network/Timer.h>
-#include <Swift/Controllers/Chat/ChatControllerBase.h>
#include <Swiften/Elements/Message.h>
#include <Swiften/Elements/DiscoInfo.h>
#include <Swiften/JID/JID.h>
#include <Swiften/MUC/MUC.h>
#include <Swiften/Elements/MUCOccupant.h>
+
+#include <Swift/Controllers/Chat/ChatControllerBase.h>
#include <Swift/Controllers/Roster/RosterItem.h>
#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
@@ -31,30 +34,35 @@ namespace Swift {
class UIEventStream;
class TimerFactory;
class TabComplete;
- class InviteToChatWindow;
class XMPPRoster;
+ class HighlightManager;
+ class UIEvent;
enum JoinPart {Join, Part, JoinThenPart, PartThenJoin};
struct NickJoinPart {
- NickJoinPart(const std::string& nick, JoinPart type) : nick(nick), type(type) {};
+ NickJoinPart(const std::string& nick, JoinPart type) : nick(nick), type(type) {}
std::string nick;
JoinPart type;
};
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, PresenceOracle* presenceOracle, AvatarManager* avatarManager, UIEventStream* events, bool useDelayForLatency, TimerFactory* timerFactory, EventController* eventController, EntityCapsProvider* entityCapsProvider, XMPPRoster* roster, HistoryController* historyController, MUCRegistry* mucRegistry);
+ MUCController(const JID& self, MUC::ref muc, const boost::optional<std::string>& password, const std::string &nick, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, PresenceOracle* presenceOracle, AvatarManager* avatarManager, UIEventStream* events, bool useDelayForLatency, TimerFactory* timerFactory, EventController* eventController, EntityCapsProvider* entityCapsProvider, XMPPRoster* roster, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ChatMessageParser* chatMessageParser, bool isImpromptu, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider);
~MUCController();
boost::signal<void ()> onUserLeft;
boost::signal<void ()> onUserJoined;
+ boost::signal<void ()> onImpromptuConfigCompleted;
virtual void setOnline(bool online);
void rejoin();
static void appendToJoinParts(std::vector<NickJoinPart>& joinParts, const NickJoinPart& newEvent);
- static std::string generateJoinPartString(const std::vector<NickJoinPart>& joinParts);
+ static std::string generateJoinPartString(const std::vector<NickJoinPart>& joinParts, bool isImpromptu);
static std::string concatenateListOfNames(const std::vector<NickJoinPart>& joinParts);
bool isJoined();
const std::string& getNick();
+ bool isImpromptu() const;
+ std::map<std::string, JID> getParticipantJIDs() const;
+ void sendInvites(const std::vector<JID>& jids, const std::string& reason) const;
protected:
void preSendMessageRequest(boost::shared_ptr<Message> message);
@@ -62,7 +70,7 @@ namespace Swift {
std::string senderDisplayNameFromMessage(const JID& from);
boost::optional<boost::posix_time::ptime> getMessageTimestamp(boost::shared_ptr<Message> message) const;
void preHandleIncomingMessage(boost::shared_ptr<MessageEvent>);
- void postHandleIncomingMessage(boost::shared_ptr<MessageEvent>);
+ void postHandleIncomingMessage(boost::shared_ptr<MessageEvent>, const HighlightAction&);
void cancelReplaces();
void logMessage(const std::string& message, const JID& fromJID, const JID& toJID, const boost::posix_time::ptime& timeStamp, bool isIncoming);
@@ -98,7 +106,7 @@ namespace Swift {
void handleConfigurationFailed(ErrorPayload::ref);
void handleConfigurationFormReceived(Form::ref);
void handleDestroyRoomRequest();
- void handleInvitePersonToThisMUCRequest();
+ void handleInvitePersonToThisMUCRequest(const std::vector<JID>& jidsToInvite);
void handleConfigurationCancelled();
void handleOccupantRoleChangeFailed(ErrorPayload::ref, const JID&, MUCOccupant::Role);
void handleGetAffiliationsRequest();
@@ -106,8 +114,14 @@ namespace Swift {
void handleChangeAffiliationsRequest(const std::vector<std::pair<MUCOccupant::Affiliation, JID> >& changes);
void handleInviteToMUCWindowDismissed();
void handleInviteToMUCWindowCompleted();
+ void handleUIEvent(boost::shared_ptr<UIEvent> event);
void addRecentLogs();
void checkDuplicates(boost::shared_ptr<Message> newMessage);
+ void setNick(const std::string& nick);
+ void setImpromptuWindowTitle();
+ void handleRoomUnlocked();
+ void configureAsImpromptuRoom(Form::ref form);
+ Form::ref buildImpromptuRoomConfiguration(Form::ref roomConfigurationForm);
private:
MUC::ref muc_;
@@ -127,9 +141,11 @@ namespace Swift {
std::vector<NickJoinPart> joinParts_;
boost::posix_time::ptime lastActivity_;
boost::optional<std::string> password_;
- InviteToChatWindow* inviteWindow_;
XMPPRoster* xmppRoster_;
std::vector<HistoryMessage> joinContext_;
+ size_t renameCounter_;
+ bool isImpromptu_;
+ bool isImpromptuAlreadyConfigured_;
};
}
diff --git a/Swift/Controllers/Chat/UnitTest/ChatMessageParserTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatMessageParserTest.cpp
new file mode 100644
index 0000000..44d7834
--- /dev/null
+++ b/Swift/Controllers/Chat/UnitTest/ChatMessageParserTest.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2013 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <hippomocks.h>
+
+#include <Swift/Controllers/Chat/ChatMessageParser.h>
+
+using namespace Swift;
+
+class ChatMessageParserTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(ChatMessageParserTest);
+ CPPUNIT_TEST(testFullBody);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp() {
+ smile1_ = ":)";
+ smile1Path_ = "/blah/smile1.png";
+ smile2_ = ":(";
+ smile2Path_ = "/blah/smile2.jpg";
+ emoticons_[smile1_] = smile1Path_;
+ emoticons_[smile2_] = smile2Path_;
+ }
+
+ void tearDown() {
+ emoticons_.clear();
+ }
+
+ void assertText(const ChatWindow::ChatMessage& result, size_t index, const std::string& text) {
+ boost::shared_ptr<ChatWindow::ChatTextMessagePart> part = boost::dynamic_pointer_cast<ChatWindow::ChatTextMessagePart>(result.getParts()[index]);
+ CPPUNIT_ASSERT_EQUAL(text, part->text);
+ }
+
+ void assertEmoticon(const ChatWindow::ChatMessage& result, size_t index, const std::string& text, const std::string& path) {
+ boost::shared_ptr<ChatWindow::ChatEmoticonMessagePart> part = boost::dynamic_pointer_cast<ChatWindow::ChatEmoticonMessagePart>(result.getParts()[index]);
+ CPPUNIT_ASSERT_EQUAL(text, part->alternativeText);
+ CPPUNIT_ASSERT_EQUAL(path, part->imagePath);
+ }
+
+ void assertURL(const ChatWindow::ChatMessage& result, size_t index, const std::string& text) {
+ boost::shared_ptr<ChatWindow::ChatURIMessagePart> part = boost::dynamic_pointer_cast<ChatWindow::ChatURIMessagePart>(result.getParts()[index]);
+ CPPUNIT_ASSERT_EQUAL(text, part->target);
+ }
+
+ void testFullBody() {
+ ChatMessageParser testling(emoticons_);
+ ChatWindow::ChatMessage result = testling.parseMessageBody(":) shiny :( :) http://wonderland.lit/blah http://denmark.lit boom boom");
+ assertEmoticon(result, 0, smile1_, smile1Path_);
+ assertText(result, 1, " shiny ");
+ assertEmoticon(result, 2, smile2_, smile2Path_);
+ assertText(result, 3, " ");
+ assertEmoticon(result, 4, smile1_, smile1Path_);
+ assertText(result, 5, " ");
+ assertURL(result, 6, "http://wonderland.lit/blah");
+ assertText(result, 7, " ");
+ assertURL(result, 8, "http://denmark.lit");
+ assertText(result, 9, " boom boom");
+ }
+
+private:
+ std::map<std::string, std::string> emoticons_;
+ std::string smile1_;
+ std::string smile1Path_;
+ std::string smile2_;
+ std::string smile2Path_;
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(ChatMessageParserTest);
+
diff --git a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
index 482b19c..f5a3003 100644
--- a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
+++ b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
@@ -10,48 +10,49 @@
#include <boost/bind.hpp>
-#include "Swift/Controllers/Chat/ChatsManager.h"
-
-#include "Swift/Controllers/Chat/UnitTest/MockChatListWindow.h"
-#include "Swift/Controllers/UIInterfaces/ChatWindow.h"
-#include "Swift/Controllers/Settings/DummySettingsProvider.h"
-#include "Swift/Controllers/UIInterfaces/ChatWindowFactory.h"
-#include "Swift/Controllers/UIInterfaces/ChatListWindowFactory.h"
-#include "Swift/Controllers/UIInterfaces/WhiteboardWindowFactory.h"
-#include "Swift/Controllers/UIInterfaces/JoinMUCWindowFactory.h"
-#include "Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h"
-#include "Swiften/Client/Client.h"
-#include "Swiften/Disco/EntityCapsManager.h"
-#include "Swiften/Disco/CapsProvider.h"
-#include "Swiften/MUC/MUCManager.h"
-#include "Swift/Controllers/Chat/ChatController.h"
-#include "Swift/Controllers/XMPPEvents/EventController.h"
-#include "Swift/Controllers/Chat/MUCController.h"
-#include "Swiften/Presence/StanzaChannelPresenceSender.h"
-#include "Swiften/Avatars/NullAvatarManager.h"
-#include "Swiften/Avatars/AvatarMemoryStorage.h"
-#include "Swiften/VCards/VCardManager.h"
-#include "Swiften/VCards/VCardMemoryStorage.h"
-#include "Swiften/Client/NickResolver.h"
-#include "Swiften/Presence/DirectedPresenceSender.h"
-#include "Swiften/Roster/XMPPRosterImpl.h"
-#include "Swift/Controllers/UnitTest/MockChatWindow.h"
-#include "Swiften/Client/DummyStanzaChannel.h"
-#include "Swiften/Queries/DummyIQChannel.h"
-#include "Swiften/Presence/PresenceOracle.h"
-#include "Swiften/Jingle/JingleSessionManager.h"
-#include "Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h"
-#include "Swift/Controllers/UIEvents/RequestChatUIEvent.h"
-#include "Swift/Controllers/UIEvents/JoinMUCUIEvent.h"
-#include "Swift/Controllers/UIEvents/UIEventStream.h"
+#include <Swift/Controllers/Chat/ChatsManager.h>
+
+#include <Swift/Controllers/Chat/UnitTest/MockChatListWindow.h>
+#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
+#include <Swift/Controllers/Settings/DummySettingsProvider.h>
+#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h>
+#include <Swift/Controllers/UIInterfaces/ChatListWindowFactory.h>
+#include <Swift/Controllers/UIInterfaces/WhiteboardWindowFactory.h>
+#include <Swift/Controllers/UIInterfaces/JoinMUCWindowFactory.h>
+#include <Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h>
+#include <Swiften/Client/Client.h>
+#include <Swiften/Disco/EntityCapsManager.h>
+#include <Swiften/Disco/CapsProvider.h>
+#include <Swiften/MUC/MUCManager.h>
+#include <Swift/Controllers/Chat/ChatController.h>
+#include <Swift/Controllers/XMPPEvents/EventController.h>
+#include <Swift/Controllers/Chat/MUCController.h>
+#include <Swiften/Presence/StanzaChannelPresenceSender.h>
+#include <Swiften/Avatars/NullAvatarManager.h>
+#include <Swiften/Avatars/AvatarMemoryStorage.h>
+#include <Swiften/VCards/VCardManager.h>
+#include <Swiften/VCards/VCardMemoryStorage.h>
+#include <Swiften/Client/NickResolver.h>
+#include <Swiften/Presence/DirectedPresenceSender.h>
+#include <Swiften/Roster/XMPPRosterImpl.h>
+#include <Swift/Controllers/UnitTest/MockChatWindow.h>
+#include <Swiften/Client/DummyStanzaChannel.h>
+#include <Swiften/Queries/DummyIQChannel.h>
+#include <Swiften/Presence/PresenceOracle.h>
+#include <Swiften/Jingle/JingleSessionManager.h>
+#include <Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h>
+#include <Swift/Controllers/UIEvents/RequestChatUIEvent.h>
+#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h>
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
#include <Swift/Controllers/ProfileSettingsProvider.h>
-#include "Swift/Controllers/FileTransfer/FileTransferOverview.h"
-#include "Swiften/Elements/DeliveryReceiptRequest.h"
-#include "Swiften/Elements/DeliveryReceipt.h"
+#include <Swift/Controllers/FileTransfer/FileTransferOverview.h>
+#include <Swiften/Elements/DeliveryReceiptRequest.h>
+#include <Swiften/Elements/DeliveryReceipt.h>
#include <Swiften/Base/Algorithm.h>
#include <Swift/Controllers/SettingConstants.h>
#include <Swift/Controllers/WhiteboardManager.h>
#include <Swiften/Whiteboard/WhiteboardSessionManager.h>
+#include <Swiften/Client/ClientBlockListManager.h>
using namespace Swift;
@@ -106,18 +107,22 @@ public:
avatarManager_ = new NullAvatarManager();
wbSessionManager_ = new WhiteboardSessionManager(iqRouter_, stanzaChannel_, presenceOracle_, entityCapsManager_);
wbManager_ = new WhiteboardManager(whiteboardWindowFactory_, uiEventStream_, nickResolver_, wbSessionManager_);
+ highlightManager_ = new HighlightManager(settings_);
mocks_->ExpectCall(chatListWindowFactory_, ChatListWindowFactory::createChatListWindow).With(uiEventStream_).Return(chatListWindow_);
- manager_ = new ChatsManager(jid_, stanzaChannel_, iqRouter_, eventController_, chatWindowFactory_, joinMUCWindowFactory_, nickResolver_, presenceOracle_, directedPresenceSender_, uiEventStream_, chatListWindowFactory_, true, NULL, mucRegistry_, entityCapsManager_, mucManager_, mucSearchWindowFactory_, profileSettings_, ftOverview_, xmppRoster_, false, settings_, NULL, wbManager_);
+ clientBlockListManager_ = new ClientBlockListManager(iqRouter_);
+ manager_ = new ChatsManager(jid_, stanzaChannel_, iqRouter_, eventController_, chatWindowFactory_, joinMUCWindowFactory_, nickResolver_, presenceOracle_, directedPresenceSender_, uiEventStream_, chatListWindowFactory_, true, NULL, mucRegistry_, entityCapsManager_, mucManager_, mucSearchWindowFactory_, profileSettings_, ftOverview_, xmppRoster_, false, settings_, NULL, wbManager_, highlightManager_, clientBlockListManager_, emoticons_, NULL);
manager_->setAvatarManager(avatarManager_);
- };
+ }
void tearDown() {
+ delete highlightManager_;
//delete chatListWindowFactory
delete profileSettings_;
delete avatarManager_;
delete manager_;
+ delete clientBlockListManager_;
delete ftOverview_;
delete ftManager_;
delete wbSessionManager_;
@@ -481,6 +486,9 @@ private:
FileTransferManager* ftManager_;
WhiteboardSessionManager* wbSessionManager_;
WhiteboardManager* wbManager_;
+ HighlightManager* highlightManager_;
+ ClientBlockListManager* clientBlockListManager_;
+ std::map<std::string, std::string> emoticons_;
};
CPPUNIT_TEST_SUITE_REGISTRATION(ChatsManagerTest);
diff --git a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
index 4f37229..5ca0687 100644
--- a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
+++ b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2013 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -26,6 +26,14 @@
#include "Swiften/Network/TimerFactory.h"
#include "Swiften/Elements/MUCUserPayload.h"
#include "Swiften/Disco/DummyEntityCapsProvider.h"
+#include <Swiften/VCards/VCardMemoryStorage.h>
+#include <Swiften/Crypto/PlatformCryptoProvider.h>
+#include <Swiften/VCards/VCardManager.h>
+#include <Swift/Controllers/Settings/DummySettingsProvider.h>
+#include <Swift/Controllers/Chat/ChatMessageParser.h>
+#include <Swift/Controllers/Chat/UserSearchController.h>
+#include <Swift/Controllers/UIInterfaces/UserSearchWindowFactory.h>
+#include <Swiften/Crypto/CryptoProvider.h>
using namespace Swift;
@@ -44,6 +52,7 @@ class MUCControllerTest : public CppUnit::TestFixture {
public:
void setUp() {
+ crypto_ = boost::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create());
self_ = JID("girl@wonderland.lit/rabbithole");
nick_ = "aLiCe";
mucJID_ = JID("teaparty@rooms.wonderland.lit");
@@ -53,6 +62,7 @@ public:
iqRouter_ = new IQRouter(iqChannel_);
eventController_ = new EventController();
chatWindowFactory_ = mocks_->InterfaceMock<ChatWindowFactory>();
+ userSearchWindowFactory_ = mocks_->InterfaceMock<UserSearchWindowFactory>();
presenceOracle_ = new PresenceOracle(stanzaChannel_);
presenceSender_ = new StanzaChannelPresenceSender(stanzaChannel_);
directedPresenceSender_ = new DirectedPresenceSender(presenceSender_);
@@ -62,12 +72,21 @@ public:
window_ = new MockChatWindow();
mucRegistry_ = new MUCRegistry();
entityCapsProvider_ = new DummyEntityCapsProvider();
+ settings_ = new DummySettingsProvider();
+ highlightManager_ = new HighlightManager(settings_);
muc_ = boost::make_shared<MUC>(stanzaChannel_, iqRouter_, directedPresenceSender_, mucJID_, mucRegistry_);
mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(muc_->getJID(), uiEventStream_).Return(window_);
- controller_ = new MUCController (self_, muc_, boost::optional<std::string>(), nick_, stanzaChannel_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory, eventController_, entityCapsProvider_, NULL, NULL, mucRegistry_);
- };
+ chatMessageParser_ = new ChatMessageParser(std::map<std::string, std::string>());
+ vcardStorage_ = new VCardMemoryStorage(crypto_.get());
+ vcardManager_ = new VCardManager(self_, iqRouter_, vcardStorage_);
+ controller_ = new MUCController (self_, muc_, boost::optional<std::string>(), nick_, stanzaChannel_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory, eventController_, entityCapsProvider_, NULL, NULL, mucRegistry_, highlightManager_, chatMessageParser_, false, NULL);
+ }
void tearDown() {
+ delete vcardManager_;
+ delete vcardStorage_;
+ delete highlightManager_;
+ delete settings_;
delete entityCapsProvider_;
delete controller_;
delete eventController_;
@@ -81,6 +100,7 @@ public:
delete iqChannel_;
delete mucRegistry_;
delete avatarManager_;
+ delete chatMessageParser_;
}
void finishJoin() {
@@ -296,25 +316,25 @@ public:
void testJoinPartStringContructionSimple() {
std::vector<NickJoinPart> list;
list.push_back(NickJoinPart("Kev", Join));
- CPPUNIT_ASSERT_EQUAL(std::string("Kev has entered the room"), MUCController::generateJoinPartString(list));
+ CPPUNIT_ASSERT_EQUAL(std::string("Kev has entered the room"), MUCController::generateJoinPartString(list, false));
list.push_back(NickJoinPart("Remko", Part));
- CPPUNIT_ASSERT_EQUAL(std::string("Kev has entered the room and Remko has left the room"), MUCController::generateJoinPartString(list));
+ CPPUNIT_ASSERT_EQUAL(std::string("Kev has entered the room and Remko has left the room"), MUCController::generateJoinPartString(list, false));
list.push_back(NickJoinPart("Bert", Join));
- CPPUNIT_ASSERT_EQUAL(std::string("Kev and Bert have entered the room and Remko has left the room"), MUCController::generateJoinPartString(list));
+ CPPUNIT_ASSERT_EQUAL(std::string("Kev and Bert have entered the room and Remko has left the room"), MUCController::generateJoinPartString(list, false));
list.push_back(NickJoinPart("Ernie", Join));
- CPPUNIT_ASSERT_EQUAL(std::string("Kev, Bert and Ernie have entered the room and Remko has left the room"), MUCController::generateJoinPartString(list));
+ CPPUNIT_ASSERT_EQUAL(std::string("Kev, Bert and Ernie have entered the room and Remko has left the room"), MUCController::generateJoinPartString(list, false));
}
void testJoinPartStringContructionMixed() {
std::vector<NickJoinPart> list;
list.push_back(NickJoinPart("Kev", JoinThenPart));
- CPPUNIT_ASSERT_EQUAL(std::string("Kev has entered then left the room"), MUCController::generateJoinPartString(list));
+ CPPUNIT_ASSERT_EQUAL(std::string("Kev has entered then left the room"), MUCController::generateJoinPartString(list, false));
list.push_back(NickJoinPart("Remko", Part));
- CPPUNIT_ASSERT_EQUAL(std::string("Remko has left the room and Kev has entered then left the room"), MUCController::generateJoinPartString(list));
+ CPPUNIT_ASSERT_EQUAL(std::string("Remko has left the room and Kev has entered then left the room"), MUCController::generateJoinPartString(list, false));
list.push_back(NickJoinPart("Bert", PartThenJoin));
- CPPUNIT_ASSERT_EQUAL(std::string("Remko has left the room, Kev has entered then left the room and Bert has left then returned to the room"), MUCController::generateJoinPartString(list));
+ CPPUNIT_ASSERT_EQUAL(std::string("Remko has left the room, Kev has entered then left the room and Bert has left then returned to the room"), MUCController::generateJoinPartString(list, false));
list.push_back(NickJoinPart("Ernie", JoinThenPart));
- CPPUNIT_ASSERT_EQUAL(std::string("Remko has left the room, Kev and Ernie have entered then left the room and Bert has left then returned to the room"), MUCController::generateJoinPartString(list));
+ CPPUNIT_ASSERT_EQUAL(std::string("Remko has left the room, Kev and Ernie have entered then left the room and Bert has left then returned to the room"), MUCController::generateJoinPartString(list, false));
}
private:
@@ -327,6 +347,7 @@ private:
IQRouter* iqRouter_;
EventController* eventController_;
ChatWindowFactory* chatWindowFactory_;
+ UserSearchWindowFactory* userSearchWindowFactory_;
MUCController* controller_;
// NickResolver* nickResolver_;
PresenceOracle* presenceOracle_;
@@ -338,6 +359,12 @@ private:
MockChatWindow* window_;
MUCRegistry* mucRegistry_;
DummyEntityCapsProvider* entityCapsProvider_;
+ DummySettingsProvider* settings_;
+ HighlightManager* highlightManager_;
+ ChatMessageParser* chatMessageParser_;
+ boost::shared_ptr<CryptoProvider> crypto_;
+ VCardManager* vcardManager_;
+ VCardMemoryStorage* vcardStorage_;
};
CPPUNIT_TEST_SUITE_REGISTRATION(MUCControllerTest);
diff --git a/Swift/Controllers/Chat/UnitTest/MockChatListWindow.h b/Swift/Controllers/Chat/UnitTest/MockChatListWindow.h
index 5bbd490..5fa264d 100644
--- a/Swift/Controllers/Chat/UnitTest/MockChatListWindow.h
+++ b/Swift/Controllers/Chat/UnitTest/MockChatListWindow.h
@@ -12,12 +12,12 @@ namespace Swift {
class MockChatListWindow : public ChatListWindow {
public:
- MockChatListWindow() {};
- virtual ~MockChatListWindow() {};
+ MockChatListWindow() {}
+ virtual ~MockChatListWindow() {}
void addMUCBookmark(const MUCBookmark& /*bookmark*/) {}
void removeMUCBookmark(const MUCBookmark& /*bookmark*/) {}
- void addWhiteboardSession(const ChatListWindow::Chat& /*chat*/) {};
- void removeWhiteboardSession(const JID& /*jid*/) {};
+ void addWhiteboardSession(const ChatListWindow::Chat& /*chat*/) {}
+ void removeWhiteboardSession(const JID& /*jid*/) {}
void setBookmarksEnabled(bool /*enabled*/) {}
void setRecents(const std::list<ChatListWindow::Chat>& /*recents*/) {}
void setUnreadCount(int /*unread*/) {}
diff --git a/Swift/Controllers/Chat/UserSearchController.cpp b/Swift/Controllers/Chat/UserSearchController.cpp
index 839f4fa..3c7eb67 100644
--- a/Swift/Controllers/Chat/UserSearchController.cpp
+++ b/Swift/Controllers/Chat/UserSearchController.cpp
@@ -15,18 +15,24 @@
#include <Swiften/Disco/GetDiscoItemsRequest.h>
#include <Swiften/Disco/DiscoServiceWalker.h>
#include <Swiften/VCards/VCardManager.h>
+#include <Swiften/Presence/PresenceOracle.h>
+#include <Swiften/Avatars/AvatarManager.h>
#include <Swift/Controllers/ContactEditController.h>
#include <Swift/Controllers/UIEvents/UIEventStream.h>
#include <Swift/Controllers/UIEvents/RequestChatWithUserDialogUIEvent.h>
#include <Swift/Controllers/UIEvents/RequestAddUserDialogUIEvent.h>
+#include <Swift/Controllers/UIEvents/RequestInviteToMUCUIEvent.h>
#include <Swift/Controllers/UIInterfaces/UserSearchWindow.h>
#include <Swift/Controllers/UIInterfaces/UserSearchWindowFactory.h>
#include <Swift/Controllers/Roster/RosterController.h>
+#include <Swift/Controllers/ContactSuggester.h>
namespace Swift {
-UserSearchController::UserSearchController(Type type, const JID& jid, UIEventStream* uiEventStream, VCardManager* vcardManager, UserSearchWindowFactory* factory, IQRouter* iqRouter, RosterController* rosterController) : type_(type), jid_(jid), uiEventStream_(uiEventStream), vcardManager_(vcardManager), factory_(factory), iqRouter_(iqRouter), rosterController_(rosterController) {
+UserSearchController::UserSearchController(Type type, const JID& jid, UIEventStream* uiEventStream, VCardManager* vcardManager, UserSearchWindowFactory* factory, IQRouter* iqRouter, RosterController* rosterController, ContactSuggester* contactSuggester, AvatarManager* avatarManager, PresenceOracle* presenceOracle) : type_(type), jid_(jid), uiEventStream_(uiEventStream), vcardManager_(vcardManager), factory_(factory), iqRouter_(iqRouter), rosterController_(rosterController), contactSuggester_(contactSuggester), avatarManager_(avatarManager), presenceOracle_(presenceOracle) {
uiEventStream_->onUIEvent.connect(boost::bind(&UserSearchController::handleUIEvent, this, _1));
vcardManager_->onVCardChanged.connect(boost::bind(&UserSearchController::handleVCardChanged, this, _1, _2));
+ avatarManager_->onAvatarChanged.connect(boost::bind(&UserSearchController::handleAvatarChanged, this, _1));
+ presenceOracle_->onPresenceChange.connect(boost::bind(&UserSearchController::handlePresenceChanged, this, _1));
window_ = NULL;
discoWalker_ = NULL;
}
@@ -38,40 +44,61 @@ UserSearchController::~UserSearchController() {
window_->onNameSuggestionRequested.disconnect(boost::bind(&UserSearchController::handleNameSuggestionRequest, this, _1));
window_->onFormRequested.disconnect(boost::bind(&UserSearchController::handleFormRequested, this, _1));
window_->onSearchRequested.disconnect(boost::bind(&UserSearchController::handleSearch, this, _1, _2));
+ window_->onJIDUpdateRequested.disconnect(boost::bind(&UserSearchController::handleJIDUpdateRequested, this, _1));
delete window_;
}
+ presenceOracle_->onPresenceChange.disconnect(boost::bind(&UserSearchController::handlePresenceChanged, this, _1));
+ avatarManager_->onAvatarChanged.disconnect(boost::bind(&UserSearchController::handleAvatarChanged, this, _1));
vcardManager_->onVCardChanged.disconnect(boost::bind(&UserSearchController::handleVCardChanged, this, _1, _2));
uiEventStream_->onUIEvent.disconnect(boost::bind(&UserSearchController::handleUIEvent, this, _1));
}
+UserSearchWindow* UserSearchController::getUserSearchWindow() {
+ initializeUserWindow();
+ assert(window_);
+ return window_;
+}
+
+void UserSearchController::setCanInitiateImpromptuMUC(bool supportsImpromptu) {
+ if (!window_) {
+ initializeUserWindow();
+ }
+ window_->setCanStartImpromptuChats(supportsImpromptu);
+}
+
void UserSearchController::handleUIEvent(boost::shared_ptr<UIEvent> event) {
bool handle = false;
- boost::shared_ptr<RequestAddUserDialogUIEvent> request = boost::shared_ptr<RequestAddUserDialogUIEvent>();
- if (type_ == AddContact) {
- if ((request = boost::dynamic_pointer_cast<RequestAddUserDialogUIEvent>(event))) {
- handle = true;
- }
- } else {
- if (boost::dynamic_pointer_cast<RequestChatWithUserDialogUIEvent>(event)) {
- handle = true;
- }
+ boost::shared_ptr<RequestAddUserDialogUIEvent> addUserRequest = boost::shared_ptr<RequestAddUserDialogUIEvent>();
+ RequestInviteToMUCUIEvent::ref inviteToMUCRequest = RequestInviteToMUCUIEvent::ref();
+ switch (type_) {
+ case AddContact:
+ if ((addUserRequest = boost::dynamic_pointer_cast<RequestAddUserDialogUIEvent>(event))) {
+ handle = true;
+ }
+ break;
+ case StartChat:
+ if (boost::dynamic_pointer_cast<RequestChatWithUserDialogUIEvent>(event)) {
+ handle = true;
+ }
+ break;
+ case InviteToChat:
+ if ((inviteToMUCRequest = boost::dynamic_pointer_cast<RequestInviteToMUCUIEvent>(event))) {
+ handle = true;
+ }
+ break;
}
if (handle) {
- if (!window_) {
- window_ = factory_->createUserSearchWindow(type_ == AddContact ? UserSearchWindow::AddContact : UserSearchWindow::ChatToContact, uiEventStream_, rosterController_->getGroups());
- window_->onNameSuggestionRequested.connect(boost::bind(&UserSearchController::handleNameSuggestionRequest, this, _1));
- window_->onFormRequested.connect(boost::bind(&UserSearchController::handleFormRequested, this, _1));
- window_->onSearchRequested.connect(boost::bind(&UserSearchController::handleSearch, this, _1, _2));
- window_->setSelectedService(JID(jid_.getDomain()));
- window_->clear();
- }
+ initializeUserWindow();
window_->show();
- if (request) {
- const std::string& name = request->getPredefinedName();
- const JID& jid = request->getPredefinedJID();
+ if (addUserRequest) {
+ const std::string& name = addUserRequest->getPredefinedName();
+ const JID& jid = addUserRequest->getPredefinedJID();
if (!name.empty() && jid.isValid()) {
window_->prepopulateJIDAndName(jid, name);
}
+ } else if (inviteToMUCRequest) {
+ window_->setJIDs(inviteToMUCRequest->getInvites());
+ window_->setRoomJID(inviteToMUCRequest->getRoom());
}
return;
}
@@ -98,7 +125,6 @@ void UserSearchController::endDiscoWalker() {
}
}
-
void UserSearchController::handleDiscoServiceFound(const JID& jid, boost::shared_ptr<DiscoInfo> info) {
//bool isUserDirectory = false;
bool supports55 = false;
@@ -166,11 +192,64 @@ void UserSearchController::handleNameSuggestionRequest(const JID &jid) {
}
}
+void UserSearchController::handleContactSuggestionsRequested(std::string text) {
+ window_->setContactSuggestions(contactSuggester_->getSuggestions(text));
+}
+
void UserSearchController::handleVCardChanged(const JID& jid, VCard::ref vcard) {
if (jid == suggestionsJID_) {
window_->setNameSuggestions(ContactEditController::nameSuggestionsFromVCard(vcard));
suggestionsJID_ = JID();
}
+ handleJIDUpdateRequested(std::vector<JID>(1, jid));
+}
+
+void UserSearchController::handleAvatarChanged(const JID& jid) {
+ handleJIDUpdateRequested(std::vector<JID>(1, jid));
+}
+
+void UserSearchController::handlePresenceChanged(Presence::ref presence) {
+ handleJIDUpdateRequested(std::vector<JID>(1, presence->getFrom().toBare()));
+}
+
+void UserSearchController::handleJIDUpdateRequested(const std::vector<JID>& jids) {
+ if (window_) {
+ std::vector<Contact> updates;
+ foreach(const JID& jid, jids) {
+ updates.push_back(convertJIDtoContact(jid));
+ }
+ window_->updateContacts(updates);
+ }
+}
+
+Contact UserSearchController::convertJIDtoContact(const JID& jid) {
+ Contact contact;
+ contact.jid = jid;
+
+ // name lookup
+ boost::optional<XMPPRosterItem> rosterItem = rosterController_->getItem(jid);
+ if (rosterItem && !rosterItem->getName().empty()) {
+ contact.name = rosterItem->getName();
+ } else {
+ VCard::ref vcard = vcardManager_->getVCard(jid);
+ if (vcard && !vcard->getFullName().empty()) {
+ contact.name = vcard->getFullName();
+ } else {
+ contact.name = jid.toString();
+ }
+ }
+
+ // presence lookup
+ Presence::ref presence = presenceOracle_->getHighestPriorityPresence(jid);
+ if (presence) {
+ contact.statusType = presence->getShow();
+ } else {
+ contact.statusType = StatusShow::None;
+ }
+
+ // avatar lookup
+ contact.avatarPath = avatarManager_->getAvatarPath(jid);
+ return contact;
}
void UserSearchController::handleDiscoWalkFinished() {
@@ -178,4 +257,30 @@ void UserSearchController::handleDiscoWalkFinished() {
endDiscoWalker();
}
+void UserSearchController::initializeUserWindow() {
+ if (!window_) {
+ UserSearchWindow::Type windowType = UserSearchWindow::AddContact;
+ switch(type_) {
+ case AddContact:
+ windowType = UserSearchWindow::AddContact;
+ break;
+ case StartChat:
+ windowType = UserSearchWindow::ChatToContact;
+ break;
+ case InviteToChat:
+ windowType = UserSearchWindow::InviteToChat;
+ break;
+ }
+
+ window_ = factory_->createUserSearchWindow(windowType, uiEventStream_, rosterController_->getGroups());
+ window_->onNameSuggestionRequested.connect(boost::bind(&UserSearchController::handleNameSuggestionRequest, this, _1));
+ window_->onFormRequested.connect(boost::bind(&UserSearchController::handleFormRequested, this, _1));
+ window_->onSearchRequested.connect(boost::bind(&UserSearchController::handleSearch, this, _1, _2));
+ window_->onContactSuggestionsRequested.connect(boost::bind(&UserSearchController::handleContactSuggestionsRequested, this, _1));
+ window_->onJIDUpdateRequested.connect(boost::bind(&UserSearchController::handleJIDUpdateRequested, this, _1));
+ window_->setSelectedService(JID(jid_.getDomain()));
+ window_->clear();
+ }
+}
+
}
diff --git a/Swift/Controllers/Chat/UserSearchController.h b/Swift/Controllers/Chat/UserSearchController.h
index ce0754c..21cad5e 100644
--- a/Swift/Controllers/Chat/UserSearchController.h
+++ b/Swift/Controllers/Chat/UserSearchController.h
@@ -18,6 +18,7 @@
#include <Swiften/Elements/DiscoItems.h>
#include <Swiften/Elements/ErrorPayload.h>
#include <Swiften/Elements/VCard.h>
+#include <Swiften/Elements/Presence.h>
namespace Swift {
class UIEventStream;
@@ -28,6 +29,10 @@ namespace Swift {
class DiscoServiceWalker;
class RosterController;
class VCardManager;
+ class ContactSuggester;
+ class AvatarManager;
+ class PresenceOracle;
+ class Contact;
class UserSearchResult {
public:
@@ -41,10 +46,13 @@ namespace Swift {
class UserSearchController {
public:
- enum Type {AddContact, StartChat};
- UserSearchController(Type type, const JID& jid, UIEventStream* uiEventStream, VCardManager* vcardManager, UserSearchWindowFactory* userSearchWindowFactory, IQRouter* iqRouter, RosterController* rosterController);
+ enum Type {AddContact, StartChat, InviteToChat};
+ UserSearchController(Type type, const JID& jid, UIEventStream* uiEventStream, VCardManager* vcardManager, UserSearchWindowFactory* userSearchWindowFactory, IQRouter* iqRouter, RosterController* rosterController, ContactSuggester* contactSuggester, AvatarManager* avatarManager, PresenceOracle* presenceOracle);
~UserSearchController();
+ UserSearchWindow* getUserSearchWindow();
+ void setCanInitiateImpromptuMUC(bool supportsImpromptu);
+
private:
void handleUIEvent(boost::shared_ptr<UIEvent> event);
void handleFormRequested(const JID& service);
@@ -54,8 +62,14 @@ namespace Swift {
void handleSearch(boost::shared_ptr<SearchPayload> fields, const JID& jid);
void handleSearchResponse(boost::shared_ptr<SearchPayload> results, ErrorPayload::ref error);
void handleNameSuggestionRequest(const JID& jid);
+ void handleContactSuggestionsRequested(std::string text);
void handleVCardChanged(const JID& jid, VCard::ref vcard);
+ void handleAvatarChanged(const JID& jid);
+ void handlePresenceChanged(Presence::ref presence);
+ void handleJIDUpdateRequested(const std::vector<JID>& jids);
+ Contact convertJIDtoContact(const JID& jid);
void endDiscoWalker();
+ void initializeUserWindow();
private:
Type type_;
@@ -68,5 +82,8 @@ namespace Swift {
RosterController* rosterController_;
UserSearchWindow* window_;
DiscoServiceWalker* discoWalker_;
+ ContactSuggester* contactSuggester_;
+ AvatarManager* avatarManager_;
+ PresenceOracle* presenceOracle_;
};
}
diff --git a/Swift/Controllers/ChatMessageSummarizer.cpp b/Swift/Controllers/ChatMessageSummarizer.cpp
index d95a177..014e032 100644
--- a/Swift/Controllers/ChatMessageSummarizer.cpp
+++ b/Swift/Controllers/ChatMessageSummarizer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011 Kevin Smith
+ * Copyright (c) 2011-2013 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -38,7 +38,7 @@ string ChatMessageSummarizer::getSummary(const string& current, const vector<Unr
string result(QT_TRANSLATE_NOOP("", "%1% and %2% others (%3%)"));
myString = str(format(result) % myString % others.size() % otherCount);
} else if (!others.empty()) {
- string result(QT_TRANSLATE_NOOP("", "%1%, %2% (%3%)"));
+ string result(QT_TRANSLATE_NOOP("", "%1%; %2% (%3%)"));
myString = str(format(result) % myString % others[0].first % otherCount);
}
return myString;
diff --git a/Swift/Controllers/Contact.cpp b/Swift/Controllers/Contact.cpp
new file mode 100644
index 0000000..7eb446c
--- /dev/null
+++ b/Swift/Controllers/Contact.cpp
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <Swift/Controllers/Contact.h>
+
+namespace Swift {
+
+Contact::Contact() {
+}
+
+Contact::Contact(const std::string& name, const JID& jid, StatusShow::Type statusType, const boost::filesystem::path& path) : name(name), jid(jid), statusType(statusType), avatarPath(path) {
+}
+
+}
diff --git a/Swift/Controllers/Contact.h b/Swift/Controllers/Contact.h
new file mode 100644
index 0000000..039cd23
--- /dev/null
+++ b/Swift/Controllers/Contact.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/filesystem/path.hpp>
+
+#include <Swiften/Elements/StatusShow.h>
+#include <Swiften/JID/JID.h>
+
+namespace Swift {
+
+class Contact {
+ public:
+ Contact();
+ Contact(const std::string& name, const JID& jid, StatusShow::Type statusType, const boost::filesystem::path& path);
+
+ public:
+ std::string name;
+ JID jid;
+ StatusShow::Type statusType;
+ boost::filesystem::path avatarPath;
+};
+
+}
diff --git a/Swift/Controllers/ContactProvider.cpp b/Swift/Controllers/ContactProvider.cpp
new file mode 100644
index 0000000..7dd1abf
--- /dev/null
+++ b/Swift/Controllers/ContactProvider.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <Swift/Controllers/ContactProvider.h>
+
+namespace Swift {
+
+ContactProvider::~ContactProvider() {
+
+}
+
+}
diff --git a/Swift/Controllers/ContactProvider.h b/Swift/Controllers/ContactProvider.h
new file mode 100644
index 0000000..9ce371f
--- /dev/null
+++ b/Swift/Controllers/ContactProvider.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <vector>
+
+#include <Swift/Controllers/Contact.h>
+
+namespace Swift {
+
+class ContactProvider {
+ public:
+ virtual ~ContactProvider();
+ virtual std::vector<Contact> getContacts() = 0;
+};
+
+}
diff --git a/Swift/Controllers/ContactSuggester.cpp b/Swift/Controllers/ContactSuggester.cpp
new file mode 100644
index 0000000..f1104b0
--- /dev/null
+++ b/Swift/Controllers/ContactSuggester.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <Swift/Controllers/ContactSuggester.h>
+
+#include <boost/algorithm/string/find.hpp>
+#include <boost/lambda/lambda.hpp>
+#include <boost/lambda/bind.hpp>
+
+#include <Swiften/Base/Algorithm.h>
+#include <Swiften/Base/foreach.h>
+#include <Swiften/JID/JID.h>
+
+#include <Swift/Controllers/ContactProvider.h>
+
+#include <algorithm>
+#include <vector>
+#include <set>
+
+namespace lambda = boost::lambda;
+
+namespace Swift {
+
+ContactSuggester::ContactSuggester() {
+}
+
+ContactSuggester::~ContactSuggester() {
+}
+
+void ContactSuggester::addContactProvider(ContactProvider* provider) {
+ contactProviders_.push_back(provider);
+}
+
+bool ContactSuggester::matchContact(const std::string& search, const Contact& c) {
+ return fuzzyMatch(c.name, search) || fuzzyMatch(c.jid.toString(), search);
+}
+
+std::vector<Contact> ContactSuggester::getSuggestions(const std::string& search) const {
+ std::vector<Contact> results;
+
+ foreach(ContactProvider* provider, contactProviders_) {
+ append(results, provider->getContacts());
+ }
+
+ std::sort(results.begin(), results.end(),
+ lambda::bind(&Contact::jid, lambda::_1) < lambda::bind(&Contact::jid, lambda::_2));
+ results.erase(std::unique(results.begin(), results.end(),
+ lambda::bind(&Contact::jid, lambda::_1) == lambda::bind(&Contact::jid, lambda::_2)),
+ results.end());
+ results.erase(std::remove_if(results.begin(), results.end(), !lambda::bind(&ContactSuggester::matchContact, search, lambda::_1)),
+ results.end());
+ std::sort(results.begin(), results.end(), ContactSuggester::chatSortPredicate);
+
+ return results;
+}
+
+bool ContactSuggester::fuzzyMatch(std::string text, std::string match) {
+ for (std::string::iterator currentQueryChar = match.begin(); currentQueryChar != match.end(); currentQueryChar++) {
+ //size_t result = text.find(*currentQueryChar);
+ std::string::iterator result = boost::algorithm::ifind_first(text, std::string(currentQueryChar, currentQueryChar+1)).begin();
+ if (result == text.end()) {
+ return false;
+ }
+ text.erase(result);
+ }
+ return true;
+}
+
+bool ContactSuggester::chatSortPredicate(const Contact& a, const Contact& b) {
+ if (a.statusType == b.statusType) {
+ return a.name.compare(b.name) < 0;
+ } else {
+ return a.statusType < b.statusType;
+ }
+}
+
+}
diff --git a/Swift/Controllers/ContactSuggester.h b/Swift/Controllers/ContactSuggester.h
new file mode 100644
index 0000000..137e5d3
--- /dev/null
+++ b/Swift/Controllers/ContactSuggester.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include <Swift/Controllers/Contact.h>
+
+namespace Swift {
+ class ContactProvider;
+
+ class ContactSuggester {
+ public:
+ ContactSuggester();
+ ~ContactSuggester();
+
+ void addContactProvider(ContactProvider* provider);
+
+ std::vector<Contact> getSuggestions(const std::string& search) const;
+ private:
+ static bool matchContact(const std::string& search, const Contact& c);
+ /**
+ * Performs fuzzy matching on the string text. Matches when each character of match string is present in sequence in text string.
+ */
+ static bool fuzzyMatch(std::string text, std::string match);
+ static bool chatSortPredicate(const Contact& a, const Contact& b);
+
+ private:
+ std::vector<ContactProvider*> contactProviders_;
+ };
+}
diff --git a/Swift/Controllers/ContactsFromXMPPRoster.cpp b/Swift/Controllers/ContactsFromXMPPRoster.cpp
new file mode 100644
index 0000000..15a7767
--- /dev/null
+++ b/Swift/Controllers/ContactsFromXMPPRoster.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <Swift/Controllers/ContactsFromXMPPRoster.h>
+
+#include <Swiften/Base/foreach.h>
+
+#include <Swiften/Avatars/AvatarManager.h>
+#include <Swiften/Presence/PresenceOracle.h>
+#include <Swiften/Roster/XMPPRoster.h>
+#include <Swiften/Roster/XMPPRosterItem.h>
+
+namespace Swift {
+
+ContactsFromXMPPRoster::ContactsFromXMPPRoster(XMPPRoster* roster, AvatarManager* avatarManager, PresenceOracle* presenceOracle) : roster_(roster), avatarManager_(avatarManager), presenceOracle_(presenceOracle) {
+}
+
+ContactsFromXMPPRoster::~ContactsFromXMPPRoster() {
+}
+
+std::vector<Contact> ContactsFromXMPPRoster::getContacts() {
+ std::vector<Contact> results;
+ std::vector<XMPPRosterItem> rosterItems = roster_->getItems();
+ foreach(const XMPPRosterItem& rosterItem, rosterItems) {
+ Contact contact(rosterItem.getName().empty() ? rosterItem.getJID().toString() : rosterItem.getName(), rosterItem.getJID(), StatusShow::None,"");
+ contact.statusType = presenceOracle_->getHighestPriorityPresence(contact.jid) ? presenceOracle_->getHighestPriorityPresence(contact.jid)->getShow() : StatusShow::None;
+ contact.avatarPath = avatarManager_->getAvatarPath(contact.jid);
+ results.push_back(contact);
+ }
+ return results;
+}
+
+}
diff --git a/Swift/Controllers/ContactsFromXMPPRoster.h b/Swift/Controllers/ContactsFromXMPPRoster.h
new file mode 100644
index 0000000..3815a99
--- /dev/null
+++ b/Swift/Controllers/ContactsFromXMPPRoster.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swift/Controllers/ContactProvider.h>
+
+namespace Swift {
+
+class PresenceOracle;
+class AvatarManager;
+class XMPPRoster;
+
+class ContactsFromXMPPRoster : public ContactProvider {
+ public:
+ ContactsFromXMPPRoster(XMPPRoster* roster, AvatarManager* avatarManager, PresenceOracle* presenceOracle);
+ virtual ~ContactsFromXMPPRoster();
+
+ virtual std::vector<Contact> getContacts();
+ private:
+ XMPPRoster* roster_;
+ AvatarManager* avatarManager_;
+ PresenceOracle* presenceOracle_;
+};
+
+}
diff --git a/Swift/Controllers/DummySoundPlayer.h b/Swift/Controllers/DummySoundPlayer.h
index 36dcb28..b91192c 100644
--- a/Swift/Controllers/DummySoundPlayer.h
+++ b/Swift/Controllers/DummySoundPlayer.h
@@ -11,6 +11,6 @@
namespace Swift {
class DummySoundPlayer : public SoundPlayer {
public:
- void playSound(SoundEffect sound) {};
+ void playSound(SoundEffect sound) {}
};
}
diff --git a/Swift/Controllers/DummySystemTray.h b/Swift/Controllers/DummySystemTray.h
index 41da4cd..451588e 100644
--- a/Swift/Controllers/DummySystemTray.h
+++ b/Swift/Controllers/DummySystemTray.h
@@ -11,8 +11,8 @@
namespace Swift {
class DummySystemTray : public SystemTray {
public:
- void setUnreadMessages(bool some) {};
- void setStatusType(StatusShow::Type type) {};
+ void setUnreadMessages(bool some) {}
+ void setStatusType(StatusShow::Type type) {}
void setConnecting() {}
};
}
diff --git a/Swift/Controllers/FileTransfer/FileTransferController.cpp b/Swift/Controllers/FileTransfer/FileTransferController.cpp
index 3feaf49..0160a7a 100644
--- a/Swift/Controllers/FileTransfer/FileTransferController.cpp
+++ b/Swift/Controllers/FileTransfer/FileTransferController.cpp
@@ -10,6 +10,7 @@
#include <Swiften/FileTransfer/FileReadBytestream.h>
#include <Swiften/Base/boost_bsignals.h>
#include <boost/bind.hpp>
+#include <boost/filesystem.hpp>
#include "Swift/Controllers/UIInterfaces/ChatWindow.h"
#include <Swiften/Base/Log.h>
#include <Swift/Controllers/Intl.h>
@@ -24,7 +25,7 @@ FileTransferController::FileTransferController(const JID& receipient, const std:
}
FileTransferController::FileTransferController(IncomingFileTransfer::ref transfer) :
- sending(false), otherParty(transfer->getSender()), filename(transfer->filename), transfer(transfer), ftManager(0), ftProgressInfo(0), chatWindow(0), currentState(FileTransfer::State::WaitingForStart) {
+ sending(false), otherParty(transfer->getSender()), filename(transfer->getFileName()), transfer(transfer), ftManager(0), ftProgressInfo(0), chatWindow(0), currentState(FileTransfer::State::WaitingForStart) {
}
@@ -41,7 +42,7 @@ std::string FileTransferController::setChatWindow(ChatWindow* wnd, std::string n
if (sending) {
uiID = wnd->addFileTransfer(QT_TRANSLATE_NOOP("", "me"), true, filename, boost::filesystem::file_size(boost::filesystem::path(filename)));
} else {
- uiID = wnd->addFileTransfer(nickname, false, filename, transfer->fileSizeInBytes);
+ uiID = wnd->addFileTransfer(nickname, false, filename, transfer->getFileSizeInBytes());
}
return uiID;
}
@@ -64,7 +65,7 @@ int FileTransferController::getProgress() const {
boost::uintmax_t FileTransferController::getSize() const {
if (transfer) {
- return transfer->fileSizeInBytes;
+ return transfer->getFileSizeInBytes();
} else {
return 0;
}
@@ -75,9 +76,9 @@ void FileTransferController::start(std::string& description) {
fileReadStream = boost::make_shared<FileReadBytestream>(boost::filesystem::path(filename));
OutgoingFileTransfer::ref outgoingTransfer = ftManager->createOutgoingFileTransfer(otherParty, boost::filesystem::path(filename), description, fileReadStream);
if (outgoingTransfer) {
- ftProgressInfo = new FileTransferProgressInfo(outgoingTransfer->fileSizeInBytes);
+ ftProgressInfo = new FileTransferProgressInfo(outgoingTransfer->getFileSizeInBytes());
ftProgressInfo->onProgressPercentage.connect(boost::bind(&FileTransferController::handleProgressPercentageChange, this, _1));
- outgoingTransfer->onStateChange.connect(boost::bind(&FileTransferController::handleFileTransferStateChange, this, _1));
+ outgoingTransfer->onStateChanged.connect(boost::bind(&FileTransferController::handleFileTransferStateChange, this, _1));
outgoingTransfer->onProcessedBytes.connect(boost::bind(&FileTransferProgressInfo::setBytesProcessed, ftProgressInfo, _1));
outgoingTransfer->start();
transfer = outgoingTransfer;
@@ -92,9 +93,9 @@ void FileTransferController::accept(std::string& file) {
if (incomingTransfer) {
fileWriteStream = boost::make_shared<FileWriteBytestream>(boost::filesystem::path(file));
- ftProgressInfo = new FileTransferProgressInfo(transfer->fileSizeInBytes);
+ ftProgressInfo = new FileTransferProgressInfo(transfer->getFileSizeInBytes());
ftProgressInfo->onProgressPercentage.connect(boost::bind(&FileTransferController::handleProgressPercentageChange, this, _1));
- transfer->onStateChange.connect(boost::bind(&FileTransferController::handleFileTransferStateChange, this, _1));
+ transfer->onStateChanged.connect(boost::bind(&FileTransferController::handleFileTransferStateChange, this, _1));
transfer->onProcessedBytes.connect(boost::bind(&FileTransferProgressInfo::setBytesProcessed, ftProgressInfo, _1));
incomingTransfer->accept(fileWriteStream);
} else {
@@ -113,7 +114,10 @@ void FileTransferController::cancel() {
void FileTransferController::handleFileTransferStateChange(FileTransfer::State state) {
currentState = state;
onStateChage();
- switch(state.state) {
+ switch(state.type) {
+ case FileTransfer::State::Initial:
+ assert(false);
+ return;
case FileTransfer::State::Negotiating:
chatWindow->setFileTransferStatus(uiID, ChatWindow::Negotiating);
return;
@@ -138,7 +142,7 @@ void FileTransferController::handleFileTransferStateChange(FileTransfer::State s
case FileTransfer::State::WaitingForStart:
return;
}
- std::cerr << "Unhandled FileTransfer::State!" << std::endl;
+ assert(false);
}
void FileTransferController::handleProgressPercentageChange(int percentage) {
diff --git a/Swift/Controllers/FileTransfer/FileTransferProgressInfo.cpp b/Swift/Controllers/FileTransfer/FileTransferProgressInfo.cpp
index 6d19fa1..3081f71 100644
--- a/Swift/Controllers/FileTransfer/FileTransferProgressInfo.cpp
+++ b/Swift/Controllers/FileTransfer/FileTransferProgressInfo.cpp
@@ -6,6 +6,8 @@
#include "FileTransferProgressInfo.h"
+#include <boost/numeric/conversion/cast.hpp>
+
#include <Swiften/Base/Log.h>
namespace Swift {
@@ -16,7 +18,7 @@ FileTransferProgressInfo::FileTransferProgressInfo(boost::uintmax_t completeByte
void FileTransferProgressInfo::setBytesProcessed(int processedBytes) {
int oldPercentage = int(double(completedBytes) / double(completeBytes) * 100.0);
- completedBytes += processedBytes;
+ completedBytes += boost::numeric_cast<boost::uintmax_t>(processedBytes);
int newPercentage = int(double(completedBytes) / double(completeBytes) * 100.0);
if (oldPercentage != newPercentage) {
onProgressPercentage(newPercentage);
diff --git a/Swift/Controllers/HighlightAction.cpp b/Swift/Controllers/HighlightAction.cpp
new file mode 100644
index 0000000..d4d199d
--- /dev/null
+++ b/Swift/Controllers/HighlightAction.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2012 Maciej Niedzielski
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <Swift/Controllers/HighlightAction.h>
+
+namespace Swift {
+
+void HighlightAction::setHighlightText(bool highlightText)
+{
+ highlightText_ = highlightText;
+ if (!highlightText_) {
+ textColor_.clear();
+ textBackground_.clear();
+ }
+}
+
+void HighlightAction::setPlaySound(bool playSound)
+{
+ playSound_ = playSound;
+ if (!playSound_) {
+ soundFile_.clear();
+ }
+}
+
+}
diff --git a/Swift/Controllers/HighlightAction.h b/Swift/Controllers/HighlightAction.h
new file mode 100644
index 0000000..bfbed74
--- /dev/null
+++ b/Swift/Controllers/HighlightAction.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2012 Maciej Niedzielski
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <string>
+
+namespace Swift {
+
+ class HighlightRule;
+
+ class HighlightAction {
+ public:
+ HighlightAction() : highlightText_(false), playSound_(false) {}
+
+ bool highlightText() const { return highlightText_; }
+ void setHighlightText(bool highlightText);
+
+ const std::string& getTextColor() const { return textColor_; }
+ void setTextColor(const std::string& textColor) { textColor_ = textColor; }
+
+ const std::string& getTextBackground() const { return textBackground_; }
+ void setTextBackground(const std::string& textBackground) { textBackground_ = textBackground; }
+
+ bool playSound() const { return playSound_; }
+ void setPlaySound(bool playSound);
+
+ const std::string& getSoundFile() const { return soundFile_; }
+ void setSoundFile(const std::string& soundFile) { soundFile_ = soundFile; }
+
+ bool isEmpty() const { return !highlightText_ && !playSound_; }
+
+ private:
+ bool highlightText_;
+ std::string textColor_;
+ std::string textBackground_;
+
+ bool playSound_;
+ std::string soundFile_;
+ };
+
+}
diff --git a/Swift/Controllers/HighlightEditorController.cpp b/Swift/Controllers/HighlightEditorController.cpp
new file mode 100644
index 0000000..899e4bb
--- /dev/null
+++ b/Swift/Controllers/HighlightEditorController.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2012 Maciej Niedzielski
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <boost/bind.hpp>
+
+#include <Swift/Controllers/HighlightEditorController.h>
+#include <Swift/Controllers/UIInterfaces/HighlightEditorWidget.h>
+#include <Swift/Controllers/UIInterfaces/HighlightEditorWidgetFactory.h>
+#include <Swift/Controllers/UIEvents/RequestHighlightEditorUIEvent.h>
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
+
+namespace Swift {
+
+HighlightEditorController::HighlightEditorController(UIEventStream* uiEventStream, HighlightEditorWidgetFactory* highlightEditorWidgetFactory, HighlightManager* highlightManager) : highlightEditorWidgetFactory_(highlightEditorWidgetFactory), highlightEditorWidget_(NULL), highlightManager_(highlightManager)
+{
+ uiEventStream->onUIEvent.connect(boost::bind(&HighlightEditorController::handleUIEvent, this, _1));
+}
+
+HighlightEditorController::~HighlightEditorController()
+{
+ delete highlightEditorWidget_;
+ highlightEditorWidget_ = NULL;
+}
+
+void HighlightEditorController::handleUIEvent(boost::shared_ptr<UIEvent> rawEvent)
+{
+ boost::shared_ptr<RequestHighlightEditorUIEvent> event = boost::dynamic_pointer_cast<RequestHighlightEditorUIEvent>(rawEvent);
+ if (event) {
+ if (!highlightEditorWidget_) {
+ highlightEditorWidget_ = highlightEditorWidgetFactory_->createHighlightEditorWidget();
+ highlightEditorWidget_->setHighlightManager(highlightManager_);
+ }
+ highlightEditorWidget_->show();
+ }
+}
+
+}
diff --git a/Swift/Controllers/HighlightEditorController.h b/Swift/Controllers/HighlightEditorController.h
new file mode 100644
index 0000000..3868251
--- /dev/null
+++ b/Swift/Controllers/HighlightEditorController.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2012 Maciej Niedzielski
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swift/Controllers/UIEvents/UIEvent.h>
+
+namespace Swift {
+
+ class UIEventStream;
+
+ class HighlightEditorWidgetFactory;
+ class HighlightEditorWidget;
+
+ class HighlightManager;
+
+ class HighlightEditorController {
+ public:
+ HighlightEditorController(UIEventStream* uiEventStream, HighlightEditorWidgetFactory* highlightEditorWidgetFactory, HighlightManager* highlightManager);
+ ~HighlightEditorController();
+
+ HighlightManager* getHighlightManager() const { return highlightManager_; }
+
+ private:
+ void handleUIEvent(boost::shared_ptr<UIEvent> event);
+
+ private:
+ HighlightEditorWidgetFactory* highlightEditorWidgetFactory_;
+ HighlightEditorWidget* highlightEditorWidget_;
+ HighlightManager* highlightManager_;
+ };
+
+}
diff --git a/Swift/Controllers/HighlightManager.cpp b/Swift/Controllers/HighlightManager.cpp
new file mode 100644
index 0000000..7ab578e
--- /dev/null
+++ b/Swift/Controllers/HighlightManager.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2012 Maciej Niedzielski
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <cassert>
+
+#include <boost/algorithm/string.hpp>
+#include <boost/regex.hpp>
+#include <boost/bind.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+
+#include <Swiften/Base/foreach.h>
+#include <Swift/Controllers/HighlightManager.h>
+#include <Swift/Controllers/Highlighter.h>
+#include <Swift/Controllers/Settings/SettingsProvider.h>
+#include <Swift/Controllers/SettingConstants.h>
+
+/* How does highlighting work?
+ *
+ * HighlightManager manages a list of if-then rules used to highlight messages.
+ * Rule is represented by HighlightRule. Action ("then" part) is HighlightAction.
+ *
+ *
+ * HighlightManager is also used as a factory for Highlighter objects.
+ * Each ChatControllerBase has its own Highlighter.
+ * Highligher may be customized by using setNick(), etc.
+ *
+ * ChatControllerBase passes incoming messages to Highlighter and gets HighlightAction in return
+ * (first matching rule is returned).
+ * If needed, HighlightAction is then passed back to Highlighter for further handling.
+ * This results in HighlightManager emiting onHighlight event,
+ * which is handled by SoundController to play sound notification
+ */
+
+namespace Swift {
+
+HighlightManager::HighlightManager(SettingsProvider* settings)
+ : settings_(settings)
+ , storingSettings_(false)
+{
+ loadSettings();
+ settings_->onSettingChanged.connect(boost::bind(&HighlightManager::handleSettingChanged, this, _1));
+}
+
+void HighlightManager::handleSettingChanged(const std::string& settingPath)
+{
+ if (!storingSettings_ && SettingConstants::HIGHLIGHT_RULES.getKey() == settingPath) {
+ loadSettings();
+ }
+}
+
+void HighlightManager::loadSettings()
+{
+ std::string highlightRules = settings_->getSetting(SettingConstants::HIGHLIGHT_RULES);
+ if (highlightRules == "@") {
+ rules_ = getDefaultRules();
+ } else {
+ rules_ = rulesFromString(highlightRules);
+ }
+}
+
+std::string HighlightManager::rulesToString() const
+{
+ std::string s;
+ foreach (HighlightRule r, rules_) {
+ s += r.toString() + '\f';
+ }
+ if (s.size()) {
+ s.erase(s.end() - 1);
+ }
+ return s;
+}
+
+std::vector<HighlightRule> HighlightManager::rulesFromString(const std::string& rulesString)
+{
+ std::vector<HighlightRule> rules;
+ std::string s(rulesString);
+ typedef boost::split_iterator<std::string::iterator> split_iterator;
+ for (split_iterator it = boost::make_split_iterator(s, boost::first_finder("\f")); it != split_iterator(); ++it) {
+ HighlightRule r = HighlightRule::fromString(boost::copy_range<std::string>(*it));
+ if (!r.isEmpty()) {
+ rules.push_back(r);
+ }
+ }
+ return rules;
+}
+
+std::vector<HighlightRule> HighlightManager::getDefaultRules()
+{
+ std::vector<HighlightRule> rules;
+ HighlightRule r;
+ r.setMatchChat(true);
+ r.getAction().setPlaySound(true);
+ rules.push_back(r);
+ return rules;
+}
+
+void HighlightManager::storeSettings()
+{
+ storingSettings_ = true; // don't reload settings while saving
+ settings_->storeSetting(SettingConstants::HIGHLIGHT_RULES, rulesToString());
+ storingSettings_ = false;
+}
+
+HighlightRule HighlightManager::getRule(int index) const
+{
+ assert(index >= 0 && static_cast<size_t>(index) < rules_.size());
+ return rules_[static_cast<size_t>(index)];
+}
+
+void HighlightManager::setRule(int index, const HighlightRule& rule)
+{
+ assert(index >= 0 && static_cast<size_t>(index) < rules_.size());
+ rules_[static_cast<size_t>(index)] = rule;
+ storeSettings();
+}
+
+void HighlightManager::insertRule(int index, const HighlightRule& rule)
+{
+ assert(index >= 0 && boost::numeric_cast<std::vector<std::string>::size_type>(index) <= rules_.size());
+ rules_.insert(rules_.begin() + index, rule);
+ storeSettings();
+}
+
+void HighlightManager::removeRule(int index)
+{
+ assert(index >= 0 && boost::numeric_cast<std::vector<std::string>::size_type>(index) < rules_.size());
+ rules_.erase(rules_.begin() + index);
+ storeSettings();
+}
+
+Highlighter* HighlightManager::createHighlighter()
+{
+ return new Highlighter(this);
+}
+
+}
diff --git a/Swift/Controllers/HighlightManager.h b/Swift/Controllers/HighlightManager.h
new file mode 100644
index 0000000..d195d05
--- /dev/null
+++ b/Swift/Controllers/HighlightManager.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012 Maciej Niedzielski
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <vector>
+#include <string>
+
+#include <Swiften/Base/boost_bsignals.h>
+#include <Swift/Controllers/HighlightRule.h>
+
+namespace Swift {
+
+ class SettingsProvider;
+ class Highlighter;
+
+ class HighlightManager {
+ public:
+ HighlightManager(SettingsProvider* settings);
+
+ Highlighter* createHighlighter();
+
+ const std::vector<HighlightRule>& getRules() const { return rules_; }
+ HighlightRule getRule(int index) const;
+ void setRule(int index, const HighlightRule& rule);
+ void insertRule(int index, const HighlightRule& rule);
+ void removeRule(int index);
+
+ boost::signal<void (const HighlightAction&)> onHighlight;
+
+ private:
+ void handleSettingChanged(const std::string& settingPath);
+
+ std::string rulesToString() const;
+ static std::vector<HighlightRule> rulesFromString(const std::string&);
+ static std::vector<HighlightRule> getDefaultRules();
+
+ SettingsProvider* settings_;
+ bool storingSettings_;
+ void storeSettings();
+ void loadSettings();
+
+ std::vector<HighlightRule> rules_;
+ };
+
+}
diff --git a/Swift/Controllers/HighlightRule.cpp b/Swift/Controllers/HighlightRule.cpp
new file mode 100644
index 0000000..9ca7d86
--- /dev/null
+++ b/Swift/Controllers/HighlightRule.cpp
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2012 Maciej Niedzielski
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <algorithm>
+#include <boost/algorithm/string.hpp>
+#include <boost/lambda/lambda.hpp>
+
+#include <Swiften/Base/foreach.h>
+#include <Swiften/Base/Regex.h>
+#include <Swift/Controllers/HighlightRule.h>
+
+namespace Swift {
+
+HighlightRule::HighlightRule()
+ : nickIsKeyword_(false)
+ , matchCase_(false)
+ , matchWholeWords_(false)
+ , matchChat_(false)
+ , matchMUC_(false)
+{
+}
+
+boost::regex HighlightRule::regexFromString(const std::string & s) const
+{
+ std::string escaped = Regex::escape(s);
+ std::string word = matchWholeWords_ ? "\\b" : "";
+ boost::regex::flag_type flags = boost::regex::normal;
+ if (!matchCase_) {
+ flags |= boost::regex::icase;
+ }
+ return boost::regex(word + escaped + word, flags);
+}
+
+void HighlightRule::updateRegex() const
+{
+ keywordRegex_.clear();
+ foreach (const std::string & k, keywords_) {
+ keywordRegex_.push_back(regexFromString(k));
+ }
+ senderRegex_.clear();
+ foreach (const std::string & s, senders_) {
+ senderRegex_.push_back(regexFromString(s));
+ }
+}
+
+std::string HighlightRule::boolToString(bool b)
+{
+ return b ? "1" : "0";
+}
+
+bool HighlightRule::boolFromString(const std::string& s)
+{
+ return s == "1";
+}
+
+std::string HighlightRule::toString() const
+{
+ std::vector<std::string> v;
+ v.push_back(boost::join(senders_, "\t"));
+ v.push_back(boost::join(keywords_, "\t"));
+ v.push_back(boolToString(nickIsKeyword_));
+ v.push_back(boolToString(matchChat_));
+ v.push_back(boolToString(matchMUC_));
+ v.push_back(boolToString(matchCase_));
+ v.push_back(boolToString(matchWholeWords_));
+ v.push_back(boolToString(action_.highlightText()));
+ v.push_back(action_.getTextColor());
+ v.push_back(action_.getTextBackground());
+ v.push_back(boolToString(action_.playSound()));
+ v.push_back(action_.getSoundFile());
+ return boost::join(v, "\n");
+}
+
+HighlightRule HighlightRule::fromString(const std::string& s)
+{
+ std::vector<std::string> v;
+ boost::split(v, s, boost::is_any_of("\n"));
+
+ HighlightRule r;
+ size_t i = 0;
+ try {
+ boost::split(r.senders_, v.at(i++), boost::is_any_of("\t"));
+ r.senders_.erase(std::remove_if(r.senders_.begin(), r.senders_.end(), boost::lambda::_1 == ""), r.senders_.end());
+ boost::split(r.keywords_, v.at(i++), boost::is_any_of("\t"));
+ r.keywords_.erase(std::remove_if(r.keywords_.begin(), r.keywords_.end(), boost::lambda::_1 == ""), r.keywords_.end());
+ r.nickIsKeyword_ = boolFromString(v.at(i++));
+ r.matchChat_ = boolFromString(v.at(i++));
+ r.matchMUC_ = boolFromString(v.at(i++));
+ r.matchCase_ = boolFromString(v.at(i++));
+ r.matchWholeWords_ = boolFromString(v.at(i++));
+ r.action_.setHighlightText(boolFromString(v.at(i++)));
+ r.action_.setTextColor(v.at(i++));
+ r.action_.setTextBackground(v.at(i++));
+ r.action_.setPlaySound(boolFromString(v.at(i++)));
+ r.action_.setSoundFile(v.at(i++));
+ }
+ catch (std::out_of_range) {
+ // this may happen if more properties are added to HighlightRule object, etc...
+ // in such case, default values (set by default constructor) will be used
+ }
+
+ r.updateRegex();
+
+ return r;
+}
+
+bool HighlightRule::isMatch(const std::string& body, const std::string& sender, const std::string& nick, MessageType messageType) const
+{
+ if ((messageType == HighlightRule::ChatMessage && matchChat_) || (messageType == HighlightRule::MUCMessage && matchMUC_)) {
+
+ bool matchesKeyword = keywords_.empty() && (nick.empty() || !nickIsKeyword_);
+ bool matchesSender = senders_.empty();
+
+ foreach (const boost::regex & rx, keywordRegex_) {
+ if (boost::regex_search(body, rx)) {
+ matchesKeyword = true;
+ break;
+ }
+ }
+
+ if (!matchesKeyword && nickIsKeyword_ && !nick.empty()) {
+ if (boost::regex_search(body, regexFromString(nick))) {
+ matchesKeyword = true;
+ }
+ }
+
+ foreach (const boost::regex & rx, senderRegex_) {
+ if (boost::regex_search(sender, rx)) {
+ matchesSender = true;
+ break;
+ }
+ }
+
+ if (matchesKeyword && matchesSender) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void HighlightRule::setSenders(const std::vector<std::string>& senders)
+{
+ senders_ = senders;
+ updateRegex();
+}
+
+void HighlightRule::setKeywords(const std::vector<std::string>& keywords)
+{
+ keywords_ = keywords;
+ updateRegex();
+}
+
+void HighlightRule::setNickIsKeyword(bool nickIsKeyword)
+{
+ nickIsKeyword_ = nickIsKeyword;
+ updateRegex();
+}
+
+void HighlightRule::setMatchCase(bool matchCase)
+{
+ matchCase_ = matchCase;
+ updateRegex();
+}
+
+void HighlightRule::setMatchWholeWords(bool matchWholeWords)
+{
+ matchWholeWords_ = matchWholeWords;
+ updateRegex();
+}
+
+void HighlightRule::setMatchChat(bool matchChat)
+{
+ matchChat_ = matchChat;
+ updateRegex();
+}
+
+void HighlightRule::setMatchMUC(bool matchMUC)
+{
+ matchMUC_ = matchMUC;
+ updateRegex();
+}
+
+bool HighlightRule::isEmpty() const
+{
+ return senders_.empty() && keywords_.empty() && !nickIsKeyword_ && !matchChat_ && !matchMUC_ && action_.isEmpty();
+}
+
+}
diff --git a/Swift/Controllers/HighlightRule.h b/Swift/Controllers/HighlightRule.h
new file mode 100644
index 0000000..1abfa5a
--- /dev/null
+++ b/Swift/Controllers/HighlightRule.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2012 Maciej Niedzielski
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <vector>
+#include <string>
+
+#include <boost/regex.hpp>
+
+#include <Swift/Controllers/HighlightAction.h>
+
+namespace Swift {
+
+ class HighlightRule {
+ public:
+ HighlightRule();
+
+ enum MessageType { ChatMessage, MUCMessage };
+
+ bool isMatch(const std::string& body, const std::string& sender, const std::string& nick, MessageType) const;
+
+ const HighlightAction& getAction() const { return action_; }
+ HighlightAction& getAction() { return action_; }
+
+ static HighlightRule fromString(const std::string&);
+ std::string toString() const;
+
+ const std::vector<std::string>& getSenders() const { return senders_; }
+ void setSenders(const std::vector<std::string>&);
+
+ const std::vector<std::string>& getKeywords() const { return keywords_; }
+ void setKeywords(const std::vector<std::string>&);
+
+ bool getNickIsKeyword() const { return nickIsKeyword_; }
+ void setNickIsKeyword(bool);
+
+ bool getMatchCase() const { return matchCase_; }
+ void setMatchCase(bool);
+
+ bool getMatchWholeWords() const { return matchWholeWords_; }
+ void setMatchWholeWords(bool);
+
+ bool getMatchChat() const { return matchChat_; }
+ void setMatchChat(bool);
+
+ bool getMatchMUC() const { return matchMUC_; }
+ void setMatchMUC(bool);
+
+ bool isEmpty() const;
+
+ private:
+ static std::string boolToString(bool);
+ static bool boolFromString(const std::string&);
+
+ std::vector<std::string> senders_;
+ std::vector<std::string> keywords_;
+ bool nickIsKeyword_;
+
+ mutable std::vector<boost::regex> senderRegex_;
+ mutable std::vector<boost::regex> keywordRegex_;
+ void updateRegex() const;
+ boost::regex regexFromString(const std::string&) const;
+
+ bool matchCase_;
+ bool matchWholeWords_;
+
+ bool matchChat_;
+ bool matchMUC_;
+
+ HighlightAction action_;
+ };
+
+}
diff --git a/Swift/Controllers/Highlighter.cpp b/Swift/Controllers/Highlighter.cpp
new file mode 100644
index 0000000..754641a
--- /dev/null
+++ b/Swift/Controllers/Highlighter.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2012 Maciej Niedzielski
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <Swiften/Base/foreach.h>
+#include <Swift/Controllers/Highlighter.h>
+#include <Swift/Controllers/HighlightManager.h>
+
+namespace Swift {
+
+Highlighter::Highlighter(HighlightManager* manager)
+ : manager_(manager)
+{
+ setMode(ChatMode);
+}
+
+void Highlighter::setMode(Mode mode)
+{
+ mode_ = mode;
+ messageType_ = mode_ == ChatMode ? HighlightRule::ChatMessage : HighlightRule::MUCMessage;
+}
+
+HighlightAction Highlighter::findAction(const std::string& body, const std::string& sender) const
+{
+ foreach (const HighlightRule & r, manager_->getRules()) {
+ if (r.isMatch(body, sender, nick_, messageType_)) {
+ return r.getAction();
+ }
+ }
+
+ return HighlightAction();
+}
+
+void Highlighter::handleHighlightAction(const HighlightAction& action)
+{
+ manager_->onHighlight(action);
+}
+
+}
diff --git a/Swift/Controllers/Highlighter.h b/Swift/Controllers/Highlighter.h
new file mode 100644
index 0000000..d026f29
--- /dev/null
+++ b/Swift/Controllers/Highlighter.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2012 Maciej Niedzielski
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <Swift/Controllers/HighlightRule.h>
+
+namespace Swift {
+
+ class HighlightManager;
+
+ class Highlighter {
+ public:
+ Highlighter(HighlightManager* manager);
+
+ enum Mode { ChatMode, MUCMode };
+ void setMode(Mode mode);
+
+ void setNick(const std::string& nick) { nick_ = nick; }
+
+ HighlightAction findAction(const std::string& body, const std::string& sender) const;
+
+ void handleHighlightAction(const HighlightAction& action);
+
+ private:
+ HighlightManager* manager_;
+ Mode mode_;
+ HighlightRule::MessageType messageType_;
+ std::string nick_;
+ };
+
+}
diff --git a/Swift/Controllers/HistoryViewController.cpp b/Swift/Controllers/HistoryViewController.cpp
index 9343017..cfa2482 100644
--- a/Swift/Controllers/HistoryViewController.cpp
+++ b/Swift/Controllers/HistoryViewController.cpp
@@ -4,6 +4,12 @@
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
#include <Swift/Controllers/HistoryViewController.h>
#include <Swift/Controllers/UIInterfaces/HistoryWindowFactory.h>
@@ -15,6 +21,7 @@
#include <Swiften/Avatars/AvatarManager.h>
#include <Swift/Controllers/Roster/SetPresence.h>
#include <Swift/Controllers/Roster/SetAvatar.h>
+#include <Swiften/Base/Path.h>
namespace Swift {
static const std::string category[] = { "Contacts", "MUC", "Contacts" };
@@ -146,7 +153,7 @@ void HistoryViewController::handleNewMessage(const HistoryMessage& message) {
// update contacts
if (!contacts_[message.getType()].count(displayJID)) {
- roster_->addContact(displayJID, displayJID, nickResolver_->jidToNick(displayJID), category[message.getType()], avatarManager_->getAvatarPath(displayJID).string());
+ roster_->addContact(displayJID, displayJID, nickResolver_->jidToNick(displayJID), category[message.getType()], avatarManager_->getAvatarPath(displayJID));
}
contacts_[message.getType()][displayJID].insert(message.getTime().date());
@@ -154,7 +161,7 @@ void HistoryViewController::handleNewMessage(const HistoryMessage& message) {
void HistoryViewController::addNewMessage(const HistoryMessage& message, bool addAtTheTop) {
bool senderIsSelf = message.getFromJID().toBare() == selfJID_;
- std::string avatarPath = avatarManager_->getAvatarPath(message.getFromJID()).string();
+ std::string avatarPath = pathToString(avatarManager_->getAvatarPath(message.getFromJID()));
std::string nick = message.getType() != HistoryMessage::Groupchat ? nickResolver_->jidToNick(message.getFromJID()) : message.getFromJID().getResource();
historyWindow_->addMessage(message.getMessage(), nick, senderIsSelf, avatarPath, message.getTime(), addAtTheTop);
@@ -177,7 +184,7 @@ void HistoryViewController::handleReturnPressed(const std::string& keyword) {
else {
nick = nickResolver_->jidToNick(jid);
}
- roster_->addContact(jid, jid, nick, category[type], avatarManager_->getAvatarPath(jid).string());
+ roster_->addContact(jid, jid, nick, category[type], avatarManager_->getAvatarPath(jid));
Presence::ref presence = getPresence(jid, type == HistoryMessage::Groupchat);
@@ -323,8 +330,7 @@ void HistoryViewController::handlePresenceChanged(Presence::ref presence) {
}
void HistoryViewController::handleAvatarChanged(const JID& jid) {
- std::string path = avatarManager_->getAvatarPath(jid).string();
- roster_->applyOnItems(SetAvatar(jid, path));
+ roster_->applyOnItems(SetAvatar(jid, avatarManager_->getAvatarPath(jid)));
}
Presence::ref HistoryViewController::getPresence(const JID& jid, bool isMUC) {
diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp
index 28d890d..14f0727 100644
--- a/Swift/Controllers/MainController.cpp
+++ b/Swift/Controllers/MainController.cpp
@@ -1,83 +1,99 @@
/*
- * Copyright (c) 2010-2012 Kevin Smith
+ * Copyright (c) 2010-2013 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+/*
+ * Copyright (c) 2013 Remko Tronçon
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#include <Swift/Controllers/MainController.h>
+#include <stdlib.h>
+
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/smart_ptr/make_shared.hpp>
-#include <string>
-#include <stdlib.h>
#include <Swiften/Base/format.h>
#include <Swiften/Base/Algorithm.h>
#include <Swiften/Base/String.h>
#include <Swiften/StringCodecs/Base64.h>
+#include <Swiften/Network/TimerFactory.h>
+#include <Swiften/Client/Storages.h>
+#include <Swiften/VCards/VCardManager.h>
+#include <Swiften/Client/NickResolver.h>
+#include <Swiften/Base/foreach.h>
+#include <Swiften/Client/Client.h>
+#include <Swiften/Presence/PresenceSender.h>
+#include <Swiften/Elements/ChatState.h>
+#include <Swiften/Elements/Presence.h>
+#include <Swiften/Elements/VCardUpdate.h>
+#include <Swiften/Elements/DiscoInfo.h>
+#include <Swiften/Disco/CapsInfoGenerator.h>
+#include <Swiften/Disco/GetDiscoInfoRequest.h>
+#include <Swiften/Disco/ClientDiscoManager.h>
+#include <Swiften/VCards/GetVCardRequest.h>
+#include <Swiften/StringCodecs/Hexify.h>
+#include <Swiften/Network/NetworkFactories.h>
+#include <Swiften/FileTransfer/FileTransferManager.h>
+#include <Swiften/Client/ClientXMLTracer.h>
+#include <Swiften/Client/StanzaChannel.h>
+#include <Swiften/Client/ClientBlockListManager.h>
+#include <Swiften/Crypto/CryptoProvider.h>
+
+#include <SwifTools/Dock/Dock.h>
+#include <SwifTools/Notifier/TogglableNotifier.h>
+#include <SwifTools/Idle/IdleDetector.h>
+
#include <Swift/Controllers/Intl.h>
#include <Swift/Controllers/UIInterfaces/UIFactory.h>
-#include "Swiften/Network/TimerFactory.h"
-#include "Swift/Controllers/BuildVersion.h"
-#include "Swiften/Client/Storages.h"
-#include "Swiften/VCards/VCardManager.h"
-#include "Swift/Controllers/Chat/UserSearchController.h"
-#include "Swift/Controllers/Chat/ChatsManager.h"
-#include "Swift/Controllers/XMPPEvents/EventController.h"
-#include "Swift/Controllers/EventWindowController.h"
-#include "Swift/Controllers/UIInterfaces/LoginWindow.h"
-#include "Swift/Controllers/UIInterfaces/LoginWindowFactory.h"
-#include "Swift/Controllers/UIInterfaces/MainWindow.h"
-#include "Swift/Controllers/Chat/MUCController.h"
-#include "Swiften/Client/NickResolver.h"
-#include "Swift/Controllers/Roster/RosterController.h"
-#include "Swift/Controllers/SoundEventController.h"
-#include "Swift/Controllers/SoundPlayer.h"
-#include "Swift/Controllers/StatusTracker.h"
-#include "Swift/Controllers/SystemTray.h"
-#include "Swift/Controllers/SystemTrayController.h"
-#include "Swift/Controllers/XMLConsoleController.h"
+#include <Swift/Controllers/BuildVersion.h>
+#include <Swift/Controllers/Chat/UserSearchController.h>
+#include <Swift/Controllers/Chat/ChatsManager.h>
+#include <Swift/Controllers/XMPPEvents/EventController.h>
+#include <Swift/Controllers/EventWindowController.h>
+#include <Swift/Controllers/UIInterfaces/LoginWindow.h>
+#include <Swift/Controllers/UIInterfaces/LoginWindowFactory.h>
+#include <Swift/Controllers/UIInterfaces/MainWindow.h>
+#include <Swift/Controllers/Chat/MUCController.h>
+#include <Swift/Controllers/Roster/RosterController.h>
+#include <Swift/Controllers/SoundEventController.h>
+#include <Swift/Controllers/SoundPlayer.h>
+#include <Swift/Controllers/StatusTracker.h>
+#include <Swift/Controllers/SystemTray.h>
+#include <Swift/Controllers/SystemTrayController.h>
+#include <Swift/Controllers/XMLConsoleController.h>
#include <Swift/Controllers/HistoryController.h>
#include <Swift/Controllers/HistoryViewController.h>
-#include "Swift/Controllers/FileTransferListController.h"
-#include "Swift/Controllers/UIEvents/UIEventStream.h"
-#include "Swift/Controllers/PresenceNotifier.h"
-#include "Swift/Controllers/EventNotifier.h"
-#include "Swift/Controllers/Storages/StoragesFactory.h"
-#include "Swift/Controllers/WhiteboardManager.h"
-#include "SwifTools/Dock/Dock.h"
-#include "SwifTools/Notifier/TogglableNotifier.h"
-#include "Swiften/Base/foreach.h"
-#include "Swiften/Client/Client.h"
-#include "Swiften/Presence/PresenceSender.h"
-#include "Swiften/Elements/ChatState.h"
-#include "Swiften/Elements/Presence.h"
-#include "Swiften/Elements/VCardUpdate.h"
-#include "Swift/Controllers/Settings/SettingsProvider.h"
-#include "Swiften/Elements/DiscoInfo.h"
-#include "Swiften/Disco/CapsInfoGenerator.h"
-#include "Swiften/Disco/GetDiscoInfoRequest.h"
-#include "Swiften/Disco/ClientDiscoManager.h"
-#include "Swiften/VCards/GetVCardRequest.h"
-#include "Swiften/StringCodecs/SHA1.h"
-#include "Swiften/StringCodecs/Hexify.h"
-#include "Swift/Controllers/UIEvents/RequestChatUIEvent.h"
-#include "Swift/Controllers/UIEvents/JoinMUCUIEvent.h"
-#include "Swift/Controllers/Storages/CertificateStorageFactory.h"
-#include "Swift/Controllers/Storages/CertificateStorageTrustChecker.h"
-#include "Swiften/Network/NetworkFactories.h"
+#include <Swift/Controllers/FileTransferListController.h>
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
+#include <Swift/Controllers/PresenceNotifier.h>
+#include <Swift/Controllers/EventNotifier.h>
+#include <Swift/Controllers/Storages/StoragesFactory.h>
+#include <Swift/Controllers/WhiteboardManager.h>
+#include <Swift/Controllers/Settings/SettingsProvider.h>
+#include <Swift/Controllers/UIEvents/RequestChatUIEvent.h>
+#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h>
+#include <Swift/Controllers/Storages/CertificateStorageFactory.h>
+#include <Swift/Controllers/Storages/CertificateStorageTrustChecker.h>
#include <Swift/Controllers/ProfileController.h>
+#include <Swift/Controllers/ShowProfileController.h>
#include <Swift/Controllers/ContactEditController.h>
#include <Swift/Controllers/XMPPURIController.h>
-#include "Swift/Controllers/AdHocManager.h"
-#include <SwifTools/Idle/IdleDetector.h>
+#include <Swift/Controllers/AdHocManager.h>
#include <Swift/Controllers/FileTransfer/FileTransferOverview.h>
-#include <Swiften/FileTransfer/FileTransferManager.h>
-#include <Swiften/Client/ClientXMLTracer.h>
#include <Swift/Controllers/SettingConstants.h>
-#include <Swiften/Client/StanzaChannel.h>
+#include <Swift/Controllers/HighlightManager.h>
+#include <Swift/Controllers/HighlightEditorController.h>
+#include <Swift/Controllers/BlockListController.h>
+#include <Swiften/Crypto/CryptoProvider.h>
+#include <Swift/Controllers/ContactSuggester.h>
+#include <Swift/Controllers/ContactsFromXMPPRoster.h>
namespace Swift {
@@ -98,6 +114,7 @@ MainController::MainController(
Notifier* notifier,
URIHandler* uriHandler,
IdleDetector* idleDetector,
+ const std::map<std::string, std::string>& emoticons,
bool useDelayForLatency) :
eventLoop_(eventLoop),
networkFactories_(networkFactories),
@@ -109,7 +126,8 @@ MainController::MainController(
idleDetector_(idleDetector),
loginWindow_(NULL) ,
useDelayForLatency_(useDelayForLatency),
- ftOverview_(NULL) {
+ ftOverview_(NULL),
+ emoticons_(emoticons) {
storages_ = NULL;
certificateStorage_ = NULL;
statusTracker_ = NULL;
@@ -121,9 +139,15 @@ MainController::MainController(
historyViewController_ = NULL;
eventWindowController_ = NULL;
profileController_ = NULL;
+ blockListController_ = NULL;
+ showProfileController_ = NULL;
contactEditController_ = NULL;
userSearchControllerChat_ = NULL;
userSearchControllerAdd_ = NULL;
+ userSearchControllerInvite_ = NULL;
+ contactsFromRosterProvider_ = NULL;
+ contactSuggesterWithoutRoster_ = NULL;
+ contactSuggesterWithRoster_ = NULL;
whiteboardManager_ = NULL;
adHocManager_ = NULL;
quitRequested_ = false;
@@ -142,7 +166,11 @@ MainController::MainController(
systemTrayController_ = new SystemTrayController(eventController_, systemTray);
loginWindow_ = uiFactory_->createLoginWindow(uiEventStream_);
loginWindow_->setShowNotificationToggle(!notifier->isExternallyConfigured());
- soundEventController_ = new SoundEventController(eventController_, soundPlayer, settings);
+
+ highlightManager_ = new HighlightManager(settings_);
+ highlightEditorController_ = new HighlightEditorController(uiEventStream_, uiFactory_, highlightManager_);
+
+ soundEventController_ = new SoundEventController(eventController_, soundPlayer, settings, highlightManager_);
xmppURIController_ = new XMPPURIController(uriHandler_, uiEventStream_);
@@ -202,6 +230,8 @@ MainController::~MainController() {
eventController_->disconnectAll();
resetClient();
+ delete highlightEditorController_;
+ delete highlightManager_;
delete fileTransferListController_;
delete xmlConsoleController_;
delete xmppURIController_;
@@ -225,6 +255,8 @@ void MainController::resetClient() {
contactEditController_ = NULL;
delete profileController_;
profileController_ = NULL;
+ delete showProfileController_;
+ showProfileController_ = NULL;
delete eventWindowController_;
eventWindowController_ = NULL;
delete chatsManager_;
@@ -255,6 +287,14 @@ void MainController::resetClient() {
userSearchControllerChat_ = NULL;
delete userSearchControllerAdd_;
userSearchControllerAdd_ = NULL;
+ delete userSearchControllerInvite_;
+ userSearchControllerInvite_ = NULL;
+ delete contactSuggesterWithoutRoster_;
+ contactSuggesterWithoutRoster_ = NULL;
+ delete contactSuggesterWithRoster_;
+ contactSuggesterWithRoster_ = NULL;
+ delete contactsFromRosterProvider_;
+ contactsFromRosterProvider_ = NULL;
delete adHocManager_;
adHocManager_ = NULL;
delete whiteboardManager_;
@@ -297,16 +337,16 @@ void MainController::handleConnected() {
myStatusLooksOnline_ = true;
if (freshLogin) {
profileController_ = new ProfileController(client_->getVCardManager(), uiFactory_, uiEventStream_);
- srand(time(NULL));
- int randomPort = 10000 + rand() % 10000;
- client_->getFileTransferManager()->startListeningOnPort(randomPort);
+ showProfileController_ = new ShowProfileController(client_->getVCardManager(), uiFactory_, uiEventStream_);
ftOverview_ = new FileTransferOverview(client_->getFileTransferManager());
fileTransferListController_->setFileTransferOverview(ftOverview_);
- rosterController_ = new RosterController(jid_, client_->getRoster(), client_->getAvatarManager(), uiFactory_, client_->getNickManager(), client_->getNickResolver(), client_->getPresenceOracle(), client_->getSubscriptionManager(), eventController_, uiEventStream_, client_->getIQRouter(), settings_, client_->getEntityCapsProvider(), ftOverview_);
+ rosterController_ = new RosterController(jid_, client_->getRoster(), client_->getAvatarManager(), uiFactory_, client_->getNickManager(), client_->getNickResolver(), client_->getPresenceOracle(), client_->getSubscriptionManager(), eventController_, uiEventStream_, client_->getIQRouter(), settings_, client_->getEntityCapsProvider(), ftOverview_, client_->getClientBlockListManager());
rosterController_->onChangeStatusRequest.connect(boost::bind(&MainController::handleChangeStatusRequest, this, _1, _2));
rosterController_->onSignOutRequest.connect(boost::bind(&MainController::signOut, this));
rosterController_->getWindow()->onShowCertificateRequest.connect(boost::bind(&MainController::handleShowCertificateRequest, this));
+ blockListController_ = new BlockListController(client_->getClientBlockListManager(), uiEventStream_, uiFactory_, eventController_);
+
contactEditController_ = new ContactEditController(rosterController_, client_->getVCardManager(), uiFactory_, uiEventStream_);
whiteboardManager_ = new WhiteboardManager(uiFactory_, uiEventStream_, client_->getNickResolver(), client_->getWhiteboardSessionManager());
@@ -315,14 +355,22 @@ void MainController::handleConnected() {
* be before they receive stanzas that need it (e.g. bookmarks).*/
client_->getVCardManager()->requestOwnVCard();
+ contactSuggesterWithoutRoster_ = new ContactSuggester();
+ contactSuggesterWithRoster_ = new ContactSuggester();
+
+ userSearchControllerInvite_ = new UserSearchController(UserSearchController::InviteToChat, jid_, uiEventStream_, client_->getVCardManager(), uiFactory_, client_->getIQRouter(), rosterController_, contactSuggesterWithRoster_, client_->getAvatarManager(), client_->getPresenceOracle());
#ifdef SWIFT_EXPERIMENTAL_HISTORY
historyController_ = new HistoryController(storages_->getHistoryStorage());
historyViewController_ = new HistoryViewController(jid_, uiEventStream_, historyController_, client_->getNickResolver(), client_->getAvatarManager(), client_->getPresenceOracle(), uiFactory_);
- chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager(), uiFactory_, profileSettings_, ftOverview_, client_->getRoster(), !settings_->getSetting(SettingConstants::REMEMBER_RECENT_CHATS), settings_, historyController_, whiteboardManager_);
+ chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager(), uiFactory_, profileSettings_, ftOverview_, client_->getRoster(), !settings_->getSetting(SettingConstants::REMEMBER_RECENT_CHATS), settings_, historyController_, whiteboardManager_, highlightManager_, client_->getClientBlockListManager(), emoticons_, userSearchControllerInvite_);
#else
- chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager(), uiFactory_, profileSettings_, ftOverview_, client_->getRoster(), !settings_->getSetting(SettingConstants::REMEMBER_RECENT_CHATS), settings_, NULL, whiteboardManager_);
+ chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager(), uiFactory_, profileSettings_, ftOverview_, client_->getRoster(), !settings_->getSetting(SettingConstants::REMEMBER_RECENT_CHATS), settings_, NULL, whiteboardManager_, highlightManager_, client_->getClientBlockListManager(), &emoticons_, userSearchControllerInvite_);
#endif
-
+ contactsFromRosterProvider_ = new ContactsFromXMPPRoster(client_->getRoster(), client_->getAvatarManager(), client_->getPresenceOracle());
+ contactSuggesterWithoutRoster_->addContactProvider(chatsManager_);
+ contactSuggesterWithRoster_->addContactProvider(chatsManager_);
+ contactSuggesterWithRoster_->addContactProvider(contactsFromRosterProvider_);
+
client_->onMessageReceived.connect(boost::bind(&ChatsManager::handleIncomingMessage, chatsManager_, _1));
chatsManager_->setAvatarManager(client_->getAvatarManager());
@@ -348,10 +396,11 @@ void MainController::handleConnected() {
client_->getDiscoManager()->setCapsNode(CLIENT_NODE);
client_->getDiscoManager()->setDiscoInfo(discoInfo);
- userSearchControllerChat_ = new UserSearchController(UserSearchController::StartChat, jid_, uiEventStream_, client_->getVCardManager(), uiFactory_, client_->getIQRouter(), rosterController_);
- userSearchControllerAdd_ = new UserSearchController(UserSearchController::AddContact, jid_, uiEventStream_, client_->getVCardManager(), uiFactory_, client_->getIQRouter(), rosterController_);
+ userSearchControllerChat_ = new UserSearchController(UserSearchController::StartChat, jid_, uiEventStream_, client_->getVCardManager(), uiFactory_, client_->getIQRouter(), rosterController_, contactSuggesterWithRoster_, client_->getAvatarManager(), client_->getPresenceOracle());
+ userSearchControllerAdd_ = new UserSearchController(UserSearchController::AddContact, jid_, uiEventStream_, client_->getVCardManager(), uiFactory_, client_->getIQRouter(), rosterController_, contactSuggesterWithoutRoster_, client_->getAvatarManager(), client_->getPresenceOracle());
adHocManager_ = new AdHocManager(JID(boundJID_.getDomain()), uiFactory_, client_->getIQRouter(), uiEventStream_, rosterController_->getWindow());
+ chatsManager_->onImpromptuMUCServiceDiscovered.connect(boost::bind(&UserSearchController::setCanInitiateImpromptuMUC, userSearchControllerChat_, _1));
}
loginWindow_->setIsLoggingIn(false);
@@ -369,7 +418,9 @@ void MainController::handleConnected() {
contactEditController_->setAvailable(true);
/* Send presence later to catch all the incoming presences. */
sendPresence(statusTracker_->getNextPresence());
+
/* Enable chats last of all, so rejoining MUCs has the right sent presence */
+ assert(chatsManager_);
chatsManager_->setOnline(true);
}
@@ -440,7 +491,7 @@ void MainController::handleInputIdleChanged(bool idle) {
}
else {
if (idle) {
- if (statusTracker_->goAutoAway()) {
+ if (statusTracker_->goAutoAway(idleDetector_->getIdleTimeSeconds())) {
if (client_ && client_->isAvailable()) {
sendPresence(statusTracker_->getNextPresence());
}
@@ -545,7 +596,7 @@ void MainController::performLoginFromCachedCredentials() {
ClientOptions clientOptions = clientOptions_;
bool eagle = settings_->getSetting(SettingConstants::FORGET_PASSWORDS);
clientOptions.forgetPassword = eagle;
- clientOptions.useTLS = eagle ? ClientOptions::RequireTLS : ClientOptions::UseTLSWhenAvailable;
+ clientOptions.useTLS = eagle ? ClientOptions::RequireTLS : clientOptions_.useTLS;
client_->connect(clientOptions);
}
@@ -710,6 +761,10 @@ void MainController::handleServerDiscoInfoResponse(boost::shared_ptr<DiscoInfo>
if (!error) {
chatsManager_->setServerDiscoInfo(info);
adHocManager_->setServerDiscoInfo(info);
+ if (info->hasFeature(DiscoInfo::BlockingCommandFeature)) {
+ rosterController_->getWindow()->setBlockingCommandAvailable(true);
+ rosterController_->initBlockingCommand();
+ }
}
}
@@ -717,7 +772,7 @@ void MainController::handleVCardReceived(const JID& jid, VCard::ref vCard) {
if (!jid.equals(jid_, JID::WithoutResource) || !vCard || vCard->getPhoto().empty()) {
return;
}
- std::string hash = Hexify::hexify(SHA1::getHash(vCard->getPhoto()));
+ std::string hash = Hexify::hexify(networkFactories_->getCryptoProvider()->getSHA1Hash(vCard->getPhoto()));
if (hash != vCardPhotoHash_) {
vCardPhotoHash_ = hash;
if (client_ && client_->isAvailable()) {
diff --git a/Swift/Controllers/MainController.h b/Swift/Controllers/MainController.h
index 2e5bd05..6fbde6d 100644
--- a/Swift/Controllers/MainController.h
+++ b/Swift/Controllers/MainController.h
@@ -1,29 +1,33 @@
/*
- * Copyright (c) 2010-2012 Kevin Smith
+ * Copyright (c) 2010-2013 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#pragma once
-#include <Swiften/Base/boost_bsignals.h>
-#include <boost/shared_ptr.hpp>
#include <vector>
-
-#include "Swiften/Network/Timer.h"
+#include <map>
#include <string>
-#include "Swiften/Client/ClientError.h"
-#include "Swiften/JID/JID.h"
-#include "Swiften/Elements/DiscoInfo.h"
-#include "Swiften/Elements/VCard.h"
-#include "Swiften/Elements/ErrorPayload.h"
-#include "Swiften/Elements/Presence.h"
-#include "Swift/Controllers/Settings/SettingsProvider.h"
-#include "Swift/Controllers/ProfileSettingsProvider.h"
-#include "Swiften/Elements/CapsInfo.h"
-#include "Swift/Controllers/XMPPEvents/ErrorEvent.h"
-#include "Swift/Controllers/UIEvents/UIEvent.h"
-#include "Swiften/Client/ClientXMLTracer.h"
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/boost_bsignals.h>
+#include <Swiften/Network/Timer.h>
+#include <Swiften/Client/ClientError.h>
+#include <Swiften/JID/JID.h>
+#include <Swiften/Elements/DiscoInfo.h>
+#include <Swiften/Elements/VCard.h>
+#include <Swiften/Elements/ErrorPayload.h>
+#include <Swiften/Elements/Presence.h>
+#include <Swiften/Elements/CapsInfo.h>
+#include <Swiften/Client/ClientXMLTracer.h>
+
+#include <Swift/Controllers/Settings/SettingsProvider.h>
+#include <Swift/Controllers/ProfileSettingsProvider.h>
+#include <Swift/Controllers/XMPPEvents/ErrorEvent.h>
+#include <Swift/Controllers/UIEvents/UIEvent.h>
+
namespace Swift {
class IdleDetector;
@@ -43,6 +47,7 @@ namespace Swift {
class MUCController;
class Notifier;
class ProfileController;
+ class ShowProfileController;
class ContactEditController;
class TogglableNotifier;
class PresenceNotifier;
@@ -71,6 +76,11 @@ namespace Swift {
class AdHocCommandWindowFactory;
class FileTransferOverview;
class WhiteboardManager;
+ class HighlightManager;
+ class HighlightEditorController;
+ class BlockListController;
+ class ContactSuggester;
+ class ContactsFromXMPPRoster;
class MainController {
public:
@@ -87,6 +97,7 @@ namespace Swift {
Notifier* notifier,
URIHandler* uriHandler,
IdleDetector* idleDetector,
+ const std::map<std::string, std::string>& emoticons,
bool useDelayForLatency);
~MainController();
@@ -151,9 +162,14 @@ namespace Swift {
HistoryViewController* historyViewController_;
HistoryController* historyController_;
FileTransferListController* fileTransferListController_;
+ BlockListController* blockListController_;
ChatsManager* chatsManager_;
ProfileController* profileController_;
+ ShowProfileController* showProfileController_;
ContactEditController* contactEditController_;
+ ContactsFromXMPPRoster* contactsFromRosterProvider_;
+ ContactSuggester* contactSuggesterWithoutRoster_;
+ ContactSuggester* contactSuggesterWithRoster_;
JID jid_;
JID boundJID_;
SystemTrayController* systemTrayController_;
@@ -167,6 +183,7 @@ namespace Swift {
bool useDelayForLatency_;
UserSearchController* userSearchControllerChat_;
UserSearchController* userSearchControllerAdd_;
+ UserSearchController* userSearchControllerInvite_;
int timeBeforeNextReconnect_;
Timer::ref reconnectTimer_;
StatusTracker* statusTracker_;
@@ -176,5 +193,8 @@ namespace Swift {
static const int SecondsToWaitBeforeForceQuitting;
FileTransferOverview* ftOverview_;
WhiteboardManager* whiteboardManager_;
+ HighlightManager* highlightManager_;
+ HighlightEditorController* highlightEditorController_;
+ std::map<std::string, std::string> emoticons_;
};
}
diff --git a/Swift/Controllers/ProfileController.cpp b/Swift/Controllers/ProfileController.cpp
index 101e283..241cc2e 100644
--- a/Swift/Controllers/ProfileController.cpp
+++ b/Swift/Controllers/ProfileController.cpp
@@ -25,7 +25,7 @@ ProfileController::~ProfileController() {
if (profileWindow) {
vcardManager->onOwnVCardChanged.disconnect(boost::bind(&ProfileController::handleOwnVCardChanged, this, _1));
profileWindow->onVCardChangeRequest.disconnect(boost::bind(&ProfileController::handleVCardChangeRequest, this, _1));
- delete profileWindow;
+ profileWindow->onWindowAboutToBeClosed.disconnect(boost::bind(&ProfileController::handleProfileWindowAboutToBeClosed, this, _1));
}
uiEventStream->onUIEvent.disconnect(boost::bind(&ProfileController::handleUIEvent, this, _1));
}
@@ -37,7 +37,9 @@ void ProfileController::handleUIEvent(UIEvent::ref event) {
if (!profileWindow) {
profileWindow = profileWindowFactory->createProfileWindow();
+ profileWindow->setEditable(true);
profileWindow->onVCardChangeRequest.connect(boost::bind(&ProfileController::handleVCardChangeRequest, this, _1));
+ profileWindow->onWindowAboutToBeClosed.connect(boost::bind(&ProfileController::handleProfileWindowAboutToBeClosed, this, _1));
vcardManager->onOwnVCardChanged.connect(boost::bind(&ProfileController::handleOwnVCardChanged, this, _1));
}
gettingVCard = true;
@@ -75,6 +77,10 @@ void ProfileController::handleOwnVCardChanged(VCard::ref vcard) {
}
}
+void ProfileController::handleProfileWindowAboutToBeClosed(const JID&) {
+ profileWindow = NULL;
+}
+
void ProfileController::setAvailable(bool b) {
available = b;
if (!available) {
diff --git a/Swift/Controllers/ProfileController.h b/Swift/Controllers/ProfileController.h
index c1afcf9..538df36 100644
--- a/Swift/Controllers/ProfileController.h
+++ b/Swift/Controllers/ProfileController.h
@@ -29,6 +29,7 @@ namespace Swift {
void handleVCardChangeRequest(VCard::ref vcard);
void handleSetVCardResponse(ErrorPayload::ref);
void handleOwnVCardChanged(VCard::ref vcard);
+ void handleProfileWindowAboutToBeClosed(const JID&);
void updateDialogStatus();
private:
diff --git a/Swift/Controllers/Roster/ContactRosterItem.cpp b/Swift/Controllers/Roster/ContactRosterItem.cpp
index 8c388bf..70b4a1b 100644
--- a/Swift/Controllers/Roster/ContactRosterItem.cpp
+++ b/Swift/Controllers/Roster/ContactRosterItem.cpp
@@ -8,11 +8,15 @@
#include "Swift/Controllers/Roster/GroupRosterItem.h"
#include <Swiften/Base/foreach.h>
+#include <Swiften/Base/DateTime.h>
+#include <Swiften/Elements/Idle.h>
+
+#include <boost/date_time/posix_time/posix_time.hpp>
namespace Swift {
-ContactRosterItem::ContactRosterItem(const JID& jid, const JID& displayJID, const std::string& name, GroupRosterItem* parent) : RosterItem(name, parent), jid_(jid), displayJID_(displayJID) {
+ContactRosterItem::ContactRosterItem(const JID& jid, const JID& displayJID, const std::string& name, GroupRosterItem* parent) : RosterItem(name, parent), jid_(jid), displayJID_(displayJID), blockState_(BlockingNotSupported) {
}
ContactRosterItem::~ContactRosterItem() {
@@ -24,12 +28,12 @@ StatusShow::Type ContactRosterItem::getStatusShow() const {
StatusShow::Type ContactRosterItem::getSimplifiedStatusShow() const {
switch (shownPresence_ ? shownPresence_->getShow() : StatusShow::None) {
- case StatusShow::Online: return StatusShow::Online; break;
- case StatusShow::Away: return StatusShow::Away; break;
- case StatusShow::XA: return StatusShow::Away; break;
- case StatusShow::FFC: return StatusShow::Online; break;
- case StatusShow::DND: return StatusShow::DND; break;
- case StatusShow::None: return StatusShow::None; break;
+ case StatusShow::Online: return StatusShow::Online;
+ case StatusShow::Away: return StatusShow::Away;
+ case StatusShow::XA: return StatusShow::Away;
+ case StatusShow::FFC: return StatusShow::Online;
+ case StatusShow::DND: return StatusShow::DND;
+ case StatusShow::None: return StatusShow::None;
}
assert(false);
return StatusShow::None;
@@ -39,11 +43,20 @@ std::string ContactRosterItem::getStatusText() const {
return shownPresence_ ? shownPresence_->getStatus() : "";
}
-void ContactRosterItem::setAvatarPath(const std::string& path) {
+std::string ContactRosterItem::getIdleText() const {
+ Idle::ref idle = shownPresence_ ? shownPresence_->getPayload<Idle>() : Idle::ref();
+ if (!idle || idle->getSince().is_not_a_date_time()) {
+ return "";
+ } else {
+ return dateTimeToLocalString(idle->getSince());
+ }
+}
+
+void ContactRosterItem::setAvatarPath(const boost::filesystem::path& path) {
avatarPath_ = path;
onDataChanged();
}
-const std::string& ContactRosterItem::getAvatarPath() const {
+const boost::filesystem::path& ContactRosterItem::getAvatarPath() const {
return avatarPath_;
}
@@ -121,6 +134,14 @@ bool ContactRosterItem::supportsFeature(const Feature feature) const {
return features_.find(feature) != features_.end();
}
+void ContactRosterItem::setBlockState(BlockState state) {
+ blockState_ = state;
+}
+
+ContactRosterItem::BlockState ContactRosterItem::blockState() const {
+ return blockState_;
+}
+
}
diff --git a/Swift/Controllers/Roster/ContactRosterItem.h b/Swift/Controllers/Roster/ContactRosterItem.h
index 8389a44..67a9722 100644
--- a/Swift/Controllers/Roster/ContactRosterItem.h
+++ b/Swift/Controllers/Roster/ContactRosterItem.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2013 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -17,6 +17,8 @@
#include <boost/bind.hpp>
#include "Swiften/Base/boost_bsignals.h"
#include <boost/shared_ptr.hpp>
+#include <boost/date_time/posix_time/ptime.hpp>
+#include <boost/filesystem/path.hpp>
namespace Swift {
@@ -25,7 +27,13 @@ class ContactRosterItem : public RosterItem {
public:
enum Feature {
FileTransferFeature,
- WhiteboardFeature,
+ WhiteboardFeature
+ };
+
+ enum BlockState {
+ BlockingNotSupported,
+ IsBlocked,
+ IsUnblocked
};
public:
@@ -35,8 +43,9 @@ class ContactRosterItem : public RosterItem {
StatusShow::Type getStatusShow() const;
StatusShow::Type getSimplifiedStatusShow() const;
std::string getStatusText() const;
- void setAvatarPath(const std::string& path);
- const std::string& getAvatarPath() const;
+ std::string getIdleText() const;
+ void setAvatarPath(const boost::filesystem::path& path);
+ const boost::filesystem::path& getAvatarPath() const;
const JID& getJID() const;
void setDisplayJID(const JID& jid);
const JID& getDisplayJID() const;
@@ -50,15 +59,21 @@ class ContactRosterItem : public RosterItem {
void setSupportedFeatures(const std::set<Feature>& features);
bool supportsFeature(Feature feature) const;
+
+ void setBlockState(BlockState state);
+ BlockState blockState() const;
+
private:
JID jid_;
JID displayJID_;
- std::string avatarPath_;
+ boost::posix_time::ptime lastAvailableTime_;
+ boost::filesystem::path avatarPath_;
std::map<std::string, boost::shared_ptr<Presence> > presences_;
boost::shared_ptr<Presence> offlinePresence_;
boost::shared_ptr<Presence> shownPresence_;
std::vector<std::string> groups_;
std::set<Feature> features_;
+ BlockState blockState_;
};
}
diff --git a/Swift/Controllers/Roster/LeastCommonSubsequence.h b/Swift/Controllers/Roster/LeastCommonSubsequence.h
index dd3c95a..9d45679 100644
--- a/Swift/Controllers/Roster/LeastCommonSubsequence.h
+++ b/Swift/Controllers/Roster/LeastCommonSubsequence.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011 Remko Tronçon
+ * Copyright (c) 2011-2013 Remko Tronçon
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -7,6 +7,7 @@
#pragma once
#include <vector>
+#include <boost/numeric/conversion/cast.hpp>
namespace Swift {
using std::equal_to;
@@ -14,8 +15,8 @@ namespace Swift {
namespace Detail {
template<typename XIt, typename YIt, typename Length, typename Predicate>
void computeLeastCommonSubsequenceMatrix(XIt xBegin, XIt xEnd, YIt yBegin, YIt yEnd, std::vector<Length>& result) {
- size_t width = std::distance(xBegin, xEnd) + 1;
- size_t height = std::distance(yBegin, yEnd) + 1;
+ size_t width = static_cast<size_t>(std::distance(xBegin, xEnd) + 1);
+ size_t height = static_cast<size_t>(std::distance(yBegin, yEnd) + 1);
result.resize(width * height);
// Initialize first row & column
@@ -30,7 +31,7 @@ namespace Swift {
Predicate predicate;
for (size_t i = 1; i < width; ++i) {
for (size_t j = 1; j < height; ++j) {
- result[i + j*width] = (predicate(*(xBegin + i-1), *(yBegin + j-1)) ? result[(i-1) + (j-1)*width] + 1 : std::max(result[i + (j-1)*width], result[i-1 + (j*width)]));
+ result[i + j*width] = predicate(*(xBegin + boost::numeric_cast<long long>(i)-1), *(yBegin + boost::numeric_cast<long long >(j)-1)) ? result[(i-1) + (j-1)*width] + 1 : std::max(result[i + (j-1)*width], result[i-1 + (j*width)]);
}
}
}
@@ -46,29 +47,29 @@ namespace Swift {
typename std::vector<X>::const_iterator yBegin = y.begin();
while (xBegin < x.end() && yBegin < y.end() && insertRemovePredicate(*xBegin, *yBegin)) {
if (updatePredicate(*xBegin, *yBegin)) {
- updates.push_back(std::distance(x.begin(), xBegin));
- postUpdates.push_back(std::distance(y.begin(), yBegin));
+ updates.push_back(static_cast<size_t>(std::distance(x.begin(), xBegin)));
+ postUpdates.push_back(static_cast<size_t>(std::distance(y.begin(), yBegin)));
}
++xBegin;
++yBegin;
}
- size_t prefixLength = std::distance(x.begin(), xBegin);
+ size_t prefixLength = static_cast<size_t>(std::distance(x.begin(), xBegin));
// Find & handle common suffix (Optimization to reduce LCS matrix size)
typename std::vector<X>::const_reverse_iterator xEnd = x.rbegin();
typename std::vector<X>::const_reverse_iterator yEnd = y.rbegin();
while (xEnd.base() > xBegin && yEnd.base() > yBegin && insertRemovePredicate(*xEnd, *yEnd)) {
if (updatePredicate(*xEnd, *yEnd)) {
- updates.push_back(std::distance(x.begin(), xEnd.base()) - 1);
- postUpdates.push_back(std::distance(y.begin(), yEnd.base()) - 1);
+ updates.push_back(static_cast<size_t>(std::distance(x.begin(), xEnd.base()) - 1));
+ postUpdates.push_back(static_cast<size_t>(std::distance(y.begin(), yEnd.base()) - 1));
}
++xEnd;
++yEnd;
}
// Compute lengths
- size_t xLength = std::distance(xBegin, xEnd.base());
- size_t yLength = std::distance(yBegin, yEnd.base());
+ size_t xLength = static_cast<size_t>(std::distance(xBegin, xEnd.base()));
+ size_t yLength = static_cast<size_t>(std::distance(yBegin, yEnd.base()));
// Compute LCS matrix
std::vector<unsigned int> lcs;
@@ -77,7 +78,7 @@ namespace Swift {
// Process LCS matrix
size_t i = xLength;
size_t j = yLength;
- const size_t width = xLength + 1;
+ size_t width = xLength + 1;
while (true) {
if (i > 0 && j > 0 && insertRemovePredicate(x[prefixLength + i-1], y[prefixLength + j-1])) {
// x[i-1] same
diff --git a/Swift/Controllers/Roster/Roster.cpp b/Swift/Controllers/Roster/Roster.cpp
index 65cf4d2..9b45b63 100644
--- a/Swift/Controllers/Roster/Roster.cpp
+++ b/Swift/Controllers/Roster/Roster.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2013 Remko Tronçon
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -22,7 +22,7 @@
namespace Swift {
-Roster::Roster(bool sortByStatus, bool fullJIDMapping) {
+Roster::Roster(bool sortByStatus, bool fullJIDMapping) : blockingSupported_(false) {
sortByStatus_ = sortByStatus;
fullJIDMapping_ = fullJIDMapping;
root_ = new GroupRosterItem("Dummy-Root", NULL, sortByStatus_);
@@ -71,6 +71,28 @@ void Roster::setAvailableFeatures(const JID& jid, const std::set<ContactRosterIt
}
}
+void Roster::setBlockedState(const std::vector<JID> &jids, ContactRosterItem::BlockState state) {
+ if (!blockingSupported_ ) {
+ foreach(ItemMap::value_type i, itemMap_) {
+ foreach(ContactRosterItem* item, i.second) {
+ item->setBlockState(ContactRosterItem::IsUnblocked);
+ }
+ }
+ }
+
+ foreach(const JID& jid, jids) {
+ ItemMap::const_iterator i = itemMap_.find(fullJIDMapping_ ? jid : jid.toBare());
+ if (i == itemMap_.end()) {
+ continue;
+ }
+ foreach(ContactRosterItem* item, i->second) {
+ item->setBlockState(state);
+ }
+ }
+
+ blockingSupported_ = true;
+}
+
void Roster::removeGroup(const std::string& group) {
root_->removeGroupChild(group);
}
@@ -83,10 +105,13 @@ void Roster::handleChildrenChanged(GroupRosterItem* item) {
onChildrenChanged(item);
}
-void Roster::addContact(const JID& jid, const JID& displayJID, const std::string& name, const std::string& groupName, const std::string& avatarPath) {
+void Roster::addContact(const JID& jid, const JID& displayJID, const std::string& name, const std::string& groupName, const boost::filesystem::path& avatarPath) {
GroupRosterItem* group(getGroup(groupName));
ContactRosterItem *item = new ContactRosterItem(jid, displayJID, name, group);
item->setAvatarPath(avatarPath);
+ if (blockingSupported_) {
+ item->setBlockState(ContactRosterItem::IsUnblocked);
+ }
group->addChild(item);
ItemMap::iterator i = itemMap_.insert(std::make_pair(fullJIDMapping_ ? jid : jid.toBare(), std::vector<ContactRosterItem*>())).first;
if (!i->second.empty()) {
@@ -198,13 +223,13 @@ void Roster::removeFilter(RosterFilter *filter) {
}
void Roster::filterContact(ContactRosterItem* contact, GroupRosterItem* group) {
- int oldDisplayedSize = group->getDisplayedChildren().size();
+ size_t oldDisplayedSize = group->getDisplayedChildren().size();
bool hide = true;
foreach (RosterFilter *filter, filters_) {
hide &= (*filter)(contact);
}
group->setDisplayed(contact, filters_.empty() || !hide);
- int newDisplayedSize = group->getDisplayedChildren().size();
+ size_t newDisplayedSize = group->getDisplayedChildren().size();
if (oldDisplayedSize == 0 && newDisplayedSize > 0) {
onGroupAdded(group);
}
diff --git a/Swift/Controllers/Roster/Roster.h b/Swift/Controllers/Roster/Roster.h
index 2fcfba5..a4c8b99 100644
--- a/Swift/Controllers/Roster/Roster.h
+++ b/Swift/Controllers/Roster/Roster.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2013 Remko Tronçon
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -28,7 +28,7 @@ class Roster {
Roster(bool sortByStatus = true, bool fullJIDMapping = false);
~Roster();
- void addContact(const JID& jid, const JID& displayJID, const std::string& name, const std::string& group, const std::string& avatarPath);
+ void addContact(const JID& jid, const JID& displayJID, const std::string& name, const std::string& group, const boost::filesystem::path& avatarPath);
void removeContact(const JID& jid);
void removeContactFromGroup(const JID& jid, const std::string& group);
void removeGroup(const std::string& group);
@@ -36,15 +36,16 @@ class Roster {
void applyOnItems(const RosterItemOperation& operation);
void applyOnAllItems(const RosterItemOperation& operation);
void applyOnItem(const RosterItemOperation& operation, const JID& jid);
- void addFilter(RosterFilter *filter) {filters_.push_back(filter);filterAll();};
+ void addFilter(RosterFilter *filter) {filters_.push_back(filter);filterAll();}
void removeFilter(RosterFilter *filter);
GroupRosterItem* getRoot();
- std::vector<RosterFilter*> getFilters() {return filters_;};
+ std::vector<RosterFilter*> getFilters() {return filters_;}
boost::signal<void (GroupRosterItem*)> onChildrenChanged;
boost::signal<void (GroupRosterItem*)> onGroupAdded;
boost::signal<void (RosterItem*)> onDataChanged;
GroupRosterItem* getGroup(const std::string& groupName);
void setAvailableFeatures(const JID& jid, const std::set<ContactRosterItem::Feature>& features);
+ void setBlockedState(const std::vector<JID>& jids, ContactRosterItem::BlockState state);
private:
void handleDataChanged(RosterItem* item);
@@ -58,6 +59,7 @@ class Roster {
ItemMap itemMap_;
bool fullJIDMapping_;
bool sortByStatus_;
+ bool blockingSupported_;
};
}
diff --git a/Swift/Controllers/Roster/RosterController.cpp b/Swift/Controllers/Roster/RosterController.cpp
index ec52993..d277799 100644
--- a/Swift/Controllers/Roster/RosterController.cpp
+++ b/Swift/Controllers/Roster/RosterController.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2012 Kevin Smith
+ * Copyright (c) 2010-2013 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -40,18 +40,20 @@
#include <Swiften/Client/NickManager.h>
#include <Swift/Controllers/Intl.h>
#include <Swiften/Base/format.h>
+#include <Swiften/Base/Path.h>
#include <Swiften/Elements/DiscoInfo.h>
#include <Swiften/Disco/EntityCapsManager.h>
#include <Swiften/Jingle/JingleSessionManager.h>
#include <Swift/Controllers/SettingConstants.h>
+#include <Swiften/Client/ClientBlockListManager.h>
namespace Swift {
/**
* The controller does not gain ownership of these parameters.
*/
-RosterController::RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickManager* nickManager, NickResolver* nickResolver, PresenceOracle* presenceOracle, SubscriptionManager* subscriptionManager, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter, SettingsProvider* settings, EntityCapsProvider* entityCapsManager, FileTransferOverview* fileTransferOverview)
- : myJID_(jid), xmppRoster_(xmppRoster), mainWindowFactory_(mainWindowFactory), mainWindow_(mainWindowFactory_->createMainWindow(uiEventStream)), roster_(new Roster()), offlineFilter_(new OfflineRosterFilter()), nickManager_(nickManager), nickResolver_(nickResolver), uiEventStream_(uiEventStream), entityCapsManager_(entityCapsManager), ftOverview_(fileTransferOverview) {
+RosterController::RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickManager* nickManager, NickResolver* nickResolver, PresenceOracle* presenceOracle, SubscriptionManager* subscriptionManager, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter, SettingsProvider* settings, EntityCapsProvider* entityCapsManager, FileTransferOverview* fileTransferOverview, ClientBlockListManager* clientBlockListManager)
+ : myJID_(jid), xmppRoster_(xmppRoster), mainWindowFactory_(mainWindowFactory), mainWindow_(mainWindowFactory_->createMainWindow(uiEventStream)), roster_(new Roster()), offlineFilter_(new OfflineRosterFilter()), nickManager_(nickManager), nickResolver_(nickResolver), uiEventStream_(uiEventStream), entityCapsManager_(entityCapsManager), ftOverview_(fileTransferOverview), clientBlockListManager_(clientBlockListManager) {
assert(fileTransferOverview);
iqRouter_ = iqRouter;
presenceOracle_ = presenceOracle;
@@ -72,7 +74,7 @@ RosterController::RosterController(const JID& jid, XMPPRoster* xmppRoster, Avata
uiEventConnection_ = uiEventStream->onUIEvent.connect(boost::bind(&RosterController::handleUIEvent, this, _1));
avatarManager_ = avatarManager;
avatarManager_->onAvatarChanged.connect(boost::bind(&RosterController::handleAvatarChanged, this, _1));
- mainWindow_->setMyAvatarPath(avatarManager_->getAvatarPath(myJID_).string());
+ mainWindow_->setMyAvatarPath(pathToString(avatarManager_->getAvatarPath(myJID_)));
nickManager_->onOwnNickChanged.connect(boost::bind(&MainWindow::setMyNick, mainWindow_, _1));
mainWindow_->setMyJID(jid);
@@ -124,11 +126,11 @@ void RosterController::handleOnJIDAdded(const JID& jid) {
std::string name = nickResolver_->jidToNick(jid);
if (!groups.empty()) {
foreach(const std::string& group, groups) {
- roster_->addContact(jid, jid, name, group, avatarManager_->getAvatarPath(jid).string());
+ roster_->addContact(jid, jid, name, group, avatarManager_->getAvatarPath(jid));
}
}
else {
- roster_->addContact(jid, jid, name, QT_TRANSLATE_NOOP("", "Contacts"), avatarManager_->getAvatarPath(jid).string());
+ roster_->addContact(jid, jid, name, QT_TRANSLATE_NOOP("", "Contacts"), avatarManager_->getAvatarPath(jid));
}
applyAllPresenceTo(jid);
}
@@ -163,7 +165,7 @@ void RosterController::handleOnJIDUpdated(const JID& jid, const std::string& old
}
foreach(const std::string& group, groups) {
if (std::find(oldGroups.begin(), oldGroups.end(), group) == oldGroups.end()) {
- roster_->addContact(jid, jid, name, group, avatarManager_->getAvatarPath(jid).string());
+ roster_->addContact(jid, jid, name, group, avatarManager_->getAvatarPath(jid));
}
}
foreach(const std::string& group, oldGroups) {
@@ -183,6 +185,20 @@ void RosterController::handleSettingChanged(const std::string& settingPath) {
}
}
+void RosterController::handleBlockingStateChanged() {
+ if (clientBlockListManager_->getBlockList()->getState() == BlockList::Available) {
+ roster_->setBlockedState(clientBlockListManager_->getBlockList()->getItems(), ContactRosterItem::IsBlocked);
+ }
+}
+
+void RosterController::handleBlockingItemAdded(const JID& jid) {
+ roster_->setBlockedState(std::vector<JID>(1, jid), ContactRosterItem::IsBlocked);
+}
+
+void RosterController::handleBlockingItemRemoved(const JID& jid) {
+ roster_->setBlockedState(std::vector<JID>(1, jid), ContactRosterItem::IsUnblocked);
+}
+
void RosterController::handleUIEvent(boost::shared_ptr<UIEvent> event) {
if (boost::shared_ptr<AddContactUIEvent> addContactEvent = boost::dynamic_pointer_cast<AddContactUIEvent>(event)) {
RosterItemPayload item;
@@ -256,6 +272,18 @@ void RosterController::updateItem(const XMPPRosterItem& item) {
request->send();
}
+void RosterController::initBlockingCommand() {
+ boost::shared_ptr<BlockList> blockList = clientBlockListManager_->getBlockList();
+
+ blockingOnStateChangedConnection_ = blockList->onStateChanged.connect(boost::bind(&RosterController::handleBlockingStateChanged, this));
+ blockingOnItemAddedConnection_ = blockList->onItemAdded.connect(boost::bind(&RosterController::handleBlockingItemAdded, this, _1));
+ blockingOnItemRemovedConnection_ = blockList->onItemRemoved.connect(boost::bind(&RosterController::handleBlockingItemRemoved, this, _1));
+
+ if (blockList->getState() == BlockList::Available) {
+ roster_->setBlockedState(blockList->getItems(), ContactRosterItem::IsBlocked);
+ }
+}
+
void RosterController::handleRosterSetError(ErrorPayload::ref error, boost::shared_ptr<RosterPayload> rosterPayload) {
if (!error) {
return;
@@ -299,10 +327,10 @@ void RosterController::handleSubscriptionRequestDeclined(SubscriptionRequestEven
}
void RosterController::handleAvatarChanged(const JID& jid) {
- std::string path = avatarManager_->getAvatarPath(jid).string();
+ boost::filesystem::path path = avatarManager_->getAvatarPath(jid);
roster_->applyOnItems(SetAvatar(jid, path));
if (jid.equals(myJID_, JID::WithoutResource)) {
- mainWindow_->setMyAvatarPath(path);
+ mainWindow_->setMyAvatarPath(pathToString(path));
}
}
diff --git a/Swift/Controllers/Roster/RosterController.h b/Swift/Controllers/Roster/RosterController.h
index 5e40124..06b551e 100644
--- a/Swift/Controllers/Roster/RosterController.h
+++ b/Swift/Controllers/Roster/RosterController.h
@@ -39,13 +39,14 @@ namespace Swift {
class NickManager;
class EntityCapsProvider;
class FileTransferManager;
-
+ class ClientBlockListManager;
+
class RosterController {
public:
- RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickManager* nickManager, NickResolver* nickResolver, PresenceOracle* presenceOracle, SubscriptionManager* subscriptionManager, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter_, SettingsProvider* settings, EntityCapsProvider* entityCapsProvider, FileTransferOverview* fileTransferOverview);
+ RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickManager* nickManager, NickResolver* nickResolver, PresenceOracle* presenceOracle, SubscriptionManager* subscriptionManager, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter_, SettingsProvider* settings, EntityCapsProvider* entityCapsProvider, FileTransferOverview* fileTransferOverview, ClientBlockListManager* clientBlockListManager);
~RosterController();
void showRosterWindow();
- MainWindow* getWindow() {return mainWindow_;};
+ MainWindow* getWindow() {return mainWindow_;}
boost::signal<void (StatusShow::Type, const std::string&)> onChangeStatusRequest;
boost::signal<void ()> onSignOutRequest;
void handleAvatarChanged(const JID& jid);
@@ -57,6 +58,8 @@ namespace Swift {
void setContactGroups(const JID& jid, const std::vector<std::string>& groups);
void updateItem(const XMPPRosterItem&);
+ void initBlockingCommand();
+
private:
void handleOnJIDAdded(const JID &jid);
void handleRosterCleared();
@@ -76,6 +79,10 @@ namespace Swift {
void handleOnCapsChanged(const JID& jid);
void handleSettingChanged(const std::string& settingPath);
+ void handleBlockingStateChanged();
+ void handleBlockingItemAdded(const JID& jid);
+ void handleBlockingItemRemoved(const JID& jid);
+
JID myJID_;
XMPPRoster* xmppRoster_;
MainWindowFactory* mainWindowFactory_;
@@ -94,7 +101,11 @@ namespace Swift {
UIEventStream* uiEventStream_;
EntityCapsProvider* entityCapsManager_;
FileTransferOverview* ftOverview_;
+ ClientBlockListManager* clientBlockListManager_;
+ boost::bsignals::scoped_connection blockingOnStateChangedConnection_;
+ boost::bsignals::scoped_connection blockingOnItemAddedConnection_;
+ boost::bsignals::scoped_connection blockingOnItemRemovedConnection_;
boost::bsignals::scoped_connection changeStatusConnection_;
boost::bsignals::scoped_connection signOutConnection_;
boost::bsignals::scoped_connection uiEventConnection_;
diff --git a/Swift/Controllers/Roster/RosterItemOperation.h b/Swift/Controllers/Roster/RosterItemOperation.h
index 691c8ef..f1dff8d 100644
--- a/Swift/Controllers/Roster/RosterItemOperation.h
+++ b/Swift/Controllers/Roster/RosterItemOperation.h
@@ -12,10 +12,10 @@ namespace Swift {
class RosterItemOperation {
public:
- RosterItemOperation(bool requiresLookup = false, const JID& lookupJID = JID()) : requiresLookup_(requiresLookup), lookupJID_(lookupJID) {};
- virtual ~RosterItemOperation() {};
- bool requiresLookup() const {return requiresLookup_;};
- const JID& lookupJID() const {return lookupJID_;};
+ RosterItemOperation(bool requiresLookup = false, const JID& lookupJID = JID()) : requiresLookup_(requiresLookup), lookupJID_(lookupJID) {}
+ virtual ~RosterItemOperation() {}
+ bool requiresLookup() const {return requiresLookup_;}
+ const JID& lookupJID() const {return lookupJID_;}
/**
* This is called when iterating over possible subjects, so must check it's
* applying to the right items - even if requiresLookup() is true an item
diff --git a/Swift/Controllers/Roster/SetAvatar.h b/Swift/Controllers/Roster/SetAvatar.h
index 241b741..424f0b3 100644
--- a/Swift/Controllers/Roster/SetAvatar.h
+++ b/Swift/Controllers/Roster/SetAvatar.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2013 Remko Tronçon
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -10,6 +10,7 @@
#include "Swiften/JID/JID.h"
#include "Swift/Controllers/Roster/RosterItemOperation.h"
#include "Swift/Controllers/Roster/ContactRosterItem.h"
+#include <boost/filesystem/path.hpp>
namespace Swift {
@@ -17,7 +18,7 @@ class RosterItem;
class SetAvatar : public RosterItemOperation {
public:
- SetAvatar(const JID& jid, const std::string& path, JID::CompareType compareType = JID::WithoutResource) : RosterItemOperation(true, jid), jid_(jid), path_(path), compareType_(compareType) {
+ SetAvatar(const JID& jid, const boost::filesystem::path& path, JID::CompareType compareType = JID::WithoutResource) : RosterItemOperation(true, jid), jid_(jid), path_(path), compareType_(compareType) {
}
virtual void operator() (RosterItem* item) const {
@@ -29,7 +30,7 @@ class SetAvatar : public RosterItemOperation {
private:
JID jid_;
- std::string path_;
+ boost::filesystem::path path_;
JID::CompareType compareType_;
};
diff --git a/Swift/Controllers/Roster/TableRoster.cpp b/Swift/Controllers/Roster/TableRoster.cpp
index c00bf4f..eb036db 100644
--- a/Swift/Controllers/Roster/TableRoster.cpp
+++ b/Swift/Controllers/Roster/TableRoster.cpp
@@ -9,6 +9,7 @@
#include <boost/cast.hpp>
#include <cassert>
#include <algorithm>
+#include <boost/numeric/conversion/cast.hpp>
#include <Swiften/Base/foreach.h>
#include <Swiften/Network/TimerFactory.h>
@@ -132,13 +133,13 @@ void TableRoster::handleUpdateTimerTick() {
computeIndexDiff<Item, ItemEquals, ItemNeedsUpdate >(sections[sectionUpdates[i]].items, newSections[sectionPostUpdates[i]].items, itemUpdates, itemPostUpdates, itemRemoves, itemInserts);
size_t end = update.insertedRows.size();
update.insertedRows.resize(update.insertedRows.size() + itemInserts.size());
- std::transform(itemInserts.begin(), itemInserts.end(), update.insertedRows.begin() + end, CreateIndexForSection(sectionPostUpdates[i]));
+ std::transform(itemInserts.begin(), itemInserts.end(), update.insertedRows.begin() + boost::numeric_cast<long long>(end), CreateIndexForSection(sectionPostUpdates[i]));
end = update.deletedRows.size();
update.deletedRows.resize(update.deletedRows.size() + itemRemoves.size());
- std::transform(itemRemoves.begin(), itemRemoves.end(), update.deletedRows.begin() + end, CreateIndexForSection(sectionUpdates[i]));
+ std::transform(itemRemoves.begin(), itemRemoves.end(), update.deletedRows.begin() + boost::numeric_cast<long long>(end), CreateIndexForSection(sectionUpdates[i]));
end = update.updatedRows.size();
update.updatedRows.resize(update.updatedRows.size() + itemUpdates.size());
- std::transform(itemUpdates.begin(), itemUpdates.end(), update.updatedRows.begin() + end, CreateIndexForSection(sectionPostUpdates[i]));
+ std::transform(itemUpdates.begin(), itemUpdates.end(), update.updatedRows.begin() + boost::numeric_cast<long long>(end), CreateIndexForSection(sectionPostUpdates[i]));
}
// Switch the old model with the new
diff --git a/Swift/Controllers/Roster/TableRoster.h b/Swift/Controllers/Roster/TableRoster.h
index d4612ed..f447760 100644
--- a/Swift/Controllers/Roster/TableRoster.h
+++ b/Swift/Controllers/Roster/TableRoster.h
@@ -12,6 +12,7 @@
#include <Swiften/JID/JID.h>
#include <Swiften/Elements/StatusShow.h>
+#include <boost/filesystem/path.hpp>
namespace Swift {
class Roster;
@@ -21,13 +22,13 @@ namespace Swift {
class TableRoster {
public:
struct Item {
- Item(const std::string& name, const std::string& description, const JID& jid, StatusShow::Type status, const std::string& avatarPath) : name(name), description(description), jid(jid), status(status), avatarPath(avatarPath) {
+ Item(const std::string& name, const std::string& description, const JID& jid, StatusShow::Type status, const boost::filesystem::path& avatarPath) : name(name), description(description), jid(jid), status(status), avatarPath(avatarPath) {
}
std::string name;
std::string description;
JID jid;
StatusShow::Type status;
- std::string avatarPath;
+ boost::filesystem::path avatarPath;
};
struct Index {
diff --git a/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp b/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp
index fbee894..b0034e6 100644
--- a/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp
+++ b/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp
@@ -37,6 +37,7 @@
#include <Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h>
#include <Swiften/Base/Algorithm.h>
#include <Swiften/EventLoop/DummyEventLoop.h>
+#include <Swiften/Client/ClientBlockListManager.h>
using namespace Swift;
@@ -82,12 +83,14 @@ class RosterControllerTest : public CppUnit::TestFixture {
ftManager_ = new DummyFileTransferManager();
ftOverview_ = new FileTransferOverview(ftManager_);
- rosterController_ = new RosterController(jid_, xmppRoster_, avatarManager_, mainWindowFactory_, nickManager_, nickResolver_, presenceOracle_, subscriptionManager_, eventController_, uiEventStream_, router_, settings_, entityCapsManager_, ftOverview_);
+ clientBlockListManager_ = new ClientBlockListManager(router_);
+ rosterController_ = new RosterController(jid_, xmppRoster_, avatarManager_, mainWindowFactory_, nickManager_, nickResolver_, presenceOracle_, subscriptionManager_, eventController_, uiEventStream_, router_, settings_, entityCapsManager_, ftOverview_, clientBlockListManager_);
mainWindow_ = mainWindowFactory_->last;
- };
+ }
void tearDown() {
delete rosterController_;
+ delete clientBlockListManager_;
delete ftManager_;
delete jingleSessionManager_;
@@ -105,7 +108,7 @@ class RosterControllerTest : public CppUnit::TestFixture {
delete uiEventStream_;
delete settings_;
delete xmppRoster_;
- };
+ }
GroupRosterItem* groupChild(size_t i) {
return dynamic_cast<GroupRosterItem*>(CHILDREN[i]);
@@ -133,7 +136,7 @@ class RosterControllerTest : public CppUnit::TestFixture {
CPPUNIT_ASSERT(item2);
CPPUNIT_ASSERT_EQUAL(presence->getStatus(), item2->getStatusText());
- };
+ }
void testHighestPresence() {
std::vector<std::string> groups;
@@ -153,7 +156,7 @@ class RosterControllerTest : public CppUnit::TestFixture {
ContactRosterItem* item = dynamic_cast<ContactRosterItem*>(dynamic_cast<GroupRosterItem*>(CHILDREN[0])->getChildren()[0]);
CPPUNIT_ASSERT(item);
CPPUNIT_ASSERT_EQUAL(highPresence->getStatus(), item->getStatusText());
- };
+ }
void testNotHighestPresence() {
std::vector<std::string> groups;
@@ -173,7 +176,7 @@ class RosterControllerTest : public CppUnit::TestFixture {
ContactRosterItem* item = dynamic_cast<ContactRosterItem*>(dynamic_cast<GroupRosterItem*>(CHILDREN[0])->getChildren()[0]);
CPPUNIT_ASSERT(item);
CPPUNIT_ASSERT_EQUAL(highPresence->getStatus(), item->getStatusText());
- };
+ }
void testUnavailablePresence() {
std::vector<std::string> groups;
@@ -215,7 +218,7 @@ class RosterControllerTest : public CppUnit::TestFixture {
CPPUNIT_ASSERT_EQUAL(lowPresenceOffline->getStatus(), high->getStatus());
CPPUNIT_ASSERT_EQUAL(StatusShow::None, item->getStatusShow());
CPPUNIT_ASSERT_EQUAL(lowPresenceOffline->getStatus(), item->getStatusText());
- };
+ }
void testAdd() {
std::vector<std::string> groups;
@@ -225,7 +228,7 @@ class RosterControllerTest : public CppUnit::TestFixture {
CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(CHILDREN.size()));
//CPPUNIT_ASSERT_EQUAL(std::string("Bob"), xmppRoster_->getNameForJID(JID("foo@bar.com")));
- };
+ }
void testAddSubscription() {
std::vector<std::string> groups;
@@ -242,7 +245,7 @@ class RosterControllerTest : public CppUnit::TestFixture {
CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(CHILDREN.size()));
CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(groupChild(0)->getChildren().size()));
- };
+ }
void testReceiveRename() {
std::vector<std::string> groups;
@@ -256,7 +259,7 @@ class RosterControllerTest : public CppUnit::TestFixture {
CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(CHILDREN.size()));
CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(groupChild(0)->getChildren().size()));
CPPUNIT_ASSERT_EQUAL(std::string("NewName"), groupChild(0)->getChildren()[0]->getDisplayName());
- };
+ }
void testReceiveRegroup() {
std::vector<std::string> oldGroups;
@@ -282,7 +285,7 @@ class RosterControllerTest : public CppUnit::TestFixture {
CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(groupChild(0)->getChildren().size()));
CPPUNIT_ASSERT_EQUAL(std::string("new name"), groupChild(0)->getChildren()[0]->getDisplayName());
CPPUNIT_ASSERT_EQUAL(std::string("Best Group"), groupChild(0)->getDisplayName());
- };
+ }
void testSendRename() {
JID jid("testling@wonderland.lit");
@@ -337,6 +340,7 @@ class RosterControllerTest : public CppUnit::TestFixture {
JingleSessionManager* jingleSessionManager_;
FileTransferManager* ftManager_;
FileTransferOverview* ftOverview_;
+ ClientBlockListManager* clientBlockListManager_;
};
CPPUNIT_TEST_SUITE_REGISTRATION(RosterControllerTest);
diff --git a/Swift/Controllers/Roster/UnitTest/TableRosterTest.cpp b/Swift/Controllers/Roster/UnitTest/TableRosterTest.cpp
index e433b50..db8a2fd 100644
--- a/Swift/Controllers/Roster/UnitTest/TableRosterTest.cpp
+++ b/Swift/Controllers/Roster/UnitTest/TableRosterTest.cpp
@@ -6,6 +6,8 @@
#include <Swift/Controllers/Roster/TableRoster.h>
+std::ostream& operator<<(std::ostream& os, const Swift::TableRoster::Index& i);
+
std::ostream& operator<<(std::ostream& os, const Swift::TableRoster::Index& i) {
os << "(" << i.section << ", " << i.row << ")";
return os;
diff --git a/Swift/Controllers/SConscript b/Swift/Controllers/SConscript
index 7cd017b..ea52084 100644
--- a/Swift/Controllers/SConscript
+++ b/Swift/Controllers/SConscript
@@ -28,8 +28,11 @@ if env["SCONS_STAGE"] == "build" :
"Chat/MUCController.cpp",
"Chat/MUCSearchController.cpp",
"Chat/UserSearchController.cpp",
+ "Chat/ChatMessageParser.cpp",
+ "ContactSuggester.cpp",
"MainController.cpp",
"ProfileController.cpp",
+ "ShowProfileController.cpp",
"ContactEditController.cpp",
"FileTransfer/FileTransferController.cpp",
"FileTransfer/FileTransferOverview.cpp",
@@ -48,6 +51,7 @@ if env["SCONS_STAGE"] == "build" :
"HistoryViewController.cpp",
"HistoryController.cpp",
"FileTransferListController.cpp",
+ "BlockListController.cpp",
"StatusTracker.cpp",
"PresenceNotifier.cpp",
"EventNotifier.cpp",
@@ -74,7 +78,16 @@ if env["SCONS_STAGE"] == "build" :
"XMPPURIController.cpp",
"ChatMessageSummarizer.cpp",
"SettingConstants.cpp",
- "WhiteboardManager.cpp"
+ "WhiteboardManager.cpp",
+ "StatusCache.cpp",
+ "HighlightAction.cpp",
+ "HighlightEditorController.cpp",
+ "HighlightManager.cpp",
+ "HighlightRule.cpp",
+ "Highlighter.cpp",
+ "ContactsFromXMPPRoster.cpp",
+ "ContactProvider.cpp",
+ "Contact.cpp"
])
env.Append(UNITTEST_SOURCES = [
@@ -86,7 +99,9 @@ if env["SCONS_STAGE"] == "build" :
File("UnitTest/PresenceNotifierTest.cpp"),
File("Chat/UnitTest/ChatsManagerTest.cpp"),
File("Chat/UnitTest/MUCControllerTest.cpp"),
+ File("Chat/UnitTest/ChatMessageParserTest.cpp"),
File("UnitTest/MockChatWindow.cpp"),
File("UnitTest/ChatMessageSummarizerTest.cpp"),
File("Settings/UnitTest/SettingsProviderHierachyTest.cpp"),
+ File("UnitTest/HighlightRuleTest.cpp"),
])
diff --git a/Swift/Controllers/SettingConstants.cpp b/Swift/Controllers/SettingConstants.cpp
index 7ab4ac4..a5328a4 100644
--- a/Swift/Controllers/SettingConstants.cpp
+++ b/Swift/Controllers/SettingConstants.cpp
@@ -19,4 +19,10 @@ const SettingsProvider::Setting<bool> SettingConstants::LOGIN_AUTOMATICALLY = Se
const SettingsProvider::Setting<bool> SettingConstants::SHOW_OFFLINE("showOffline", false);
const SettingsProvider::Setting<std::string> SettingConstants::EXPANDED_ROSTER_GROUPS("GroupExpandiness", "");
const SettingsProvider::Setting<bool> SettingConstants::PLAY_SOUNDS("playSounds", true);
+const SettingsProvider::Setting<std::string> SettingConstants::HIGHLIGHT_RULES("highlightRules", "@");
+const SettingsProvider::Setting<bool> SettingConstants::SPELL_CHECKER("spellChecker", false);
+const SettingsProvider::Setting<std::string> SettingConstants::DICT_PATH("dictPath", "/usr/share/myspell/dicts/");
+const SettingsProvider::Setting<std::string> SettingConstants::PERSONAL_DICT_PATH("personaldictPath", "/home/");
+const SettingsProvider::Setting<std::string> SettingConstants::DICT_FILE("dictFile", "en_US.dic");
+const SettingsProvider::Setting<std::string> SettingConstants::INVITE_AUTO_ACCEPT_MODE("inviteAutoAcceptMode", "presence");
}
diff --git a/Swift/Controllers/SettingConstants.h b/Swift/Controllers/SettingConstants.h
index ff1ed72..4d25bde 100644
--- a/Swift/Controllers/SettingConstants.h
+++ b/Swift/Controllers/SettingConstants.h
@@ -22,5 +22,11 @@ namespace Swift {
static const SettingsProvider::Setting<bool> SHOW_OFFLINE;
static const SettingsProvider::Setting<std::string> EXPANDED_ROSTER_GROUPS;
static const SettingsProvider::Setting<bool> PLAY_SOUNDS;
+ static const SettingsProvider::Setting<std::string> HIGHLIGHT_RULES;
+ static const SettingsProvider::Setting<bool> SPELL_CHECKER;
+ static const SettingsProvider::Setting<std::string> DICT_PATH;
+ static const SettingsProvider::Setting<std::string> PERSONAL_DICT_PATH;
+ static const SettingsProvider::Setting<std::string> DICT_FILE;
+ static const SettingsProvider::Setting<std::string> INVITE_AUTO_ACCEPT_MODE;
};
}
diff --git a/Swift/Controllers/Settings/DummySettingsProvider.h b/Swift/Controllers/Settings/DummySettingsProvider.h
index 1d6059f..0183dd3 100644
--- a/Swift/Controllers/Settings/DummySettingsProvider.h
+++ b/Swift/Controllers/Settings/DummySettingsProvider.h
@@ -17,25 +17,25 @@ class DummySettingsProvider : public SettingsProvider {
virtual ~DummySettingsProvider() {}
virtual std::string getSetting(const Setting<std::string>& setting) {
return stringValues.find(setting.getKey()) != stringValues.end() ? stringValues[setting.getKey()] : setting.getDefaultValue();
- };
+ }
virtual void storeSetting(const Setting<std::string>& setting, const std::string& value) {
stringValues[setting.getKey()] = value;
onSettingChanged(setting.getKey());
- };
+ }
virtual bool getSetting(const Setting<bool>& setting) {
return boolValues.find(setting.getKey()) != boolValues.end() ? boolValues[setting.getKey()] : setting.getDefaultValue();
- };
+ }
virtual void storeSetting(const Setting<bool>& setting, const bool& value) {
boolValues[setting.getKey()] = value;
onSettingChanged(setting.getKey());
- };
+ }
virtual int getSetting(const Setting<int>& setting) {
return intValues.find(setting.getKey()) != intValues.end() ? intValues[setting.getKey()] : setting.getDefaultValue();
- };
+ }
virtual void storeSetting(const Setting<int>& setting, const int& value) {
intValues[setting.getKey()] = value;
onSettingChanged(setting.getKey());
- };
+ }
virtual std::vector<std::string> getAvailableProfiles() {return std::vector<std::string>();}
virtual void createProfile(const std::string& ) {}
virtual void removeProfile(const std::string& ) {}
diff --git a/Swift/Controllers/Settings/UnitTest/SettingsProviderHierachyTest.cpp b/Swift/Controllers/Settings/UnitTest/SettingsProviderHierachyTest.cpp
index aa4d14f..2b637a0 100644
--- a/Swift/Controllers/Settings/UnitTest/SettingsProviderHierachyTest.cpp
+++ b/Swift/Controllers/Settings/UnitTest/SettingsProviderHierachyTest.cpp
@@ -26,7 +26,7 @@ class SettingsProviderHierachyTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE_END();
public:
- SettingsProviderHierachyTest() : setting1("somekey", 42) {};
+ SettingsProviderHierachyTest() : setting1("somekey", 42) {}
void setUp() {
bottom = new DummySettingsProvider();
diff --git a/Swift/Controllers/ShowProfileController.cpp b/Swift/Controllers/ShowProfileController.cpp
new file mode 100644
index 0000000..15b7b26
--- /dev/null
+++ b/Swift/Controllers/ShowProfileController.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include "ShowProfileController.h"
+
+#include <boost/bind.hpp>
+
+#include <Swiften/Base/foreach.h>
+#include <Swiften/VCards/VCardManager.h>
+
+#include <Swift/Controllers/UIEvents/ShowProfileForRosterItemUIEvent.h>
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
+#include <Swift/Controllers/UIInterfaces/ProfileWindowFactory.h>
+
+namespace Swift {
+
+ShowProfileController::ShowProfileController(VCardManager* vcardManager, ProfileWindowFactory* profileWindowFactory, UIEventStream* uiEventStream) : vcardManager(vcardManager), profileWindowFactory(profileWindowFactory), uiEventStream(uiEventStream) {
+ uiEventStream->onUIEvent.connect(boost::bind(&ShowProfileController::handleUIEvent, this, _1));
+ vcardManager->onVCardChanged.connect(boost::bind(&ShowProfileController::handleVCardChanged, this, _1, _2));
+}
+
+ShowProfileController::~ShowProfileController() {
+ typedef std::pair<JID, ProfileWindow*> JIDProfileWindowPair;
+ foreach(const JIDProfileWindowPair& jidWndPair, openedProfileWindows) {
+ jidWndPair.second->onWindowAboutToBeClosed.disconnect(boost::bind(&ShowProfileController::handleProfileWindowAboutToBeClosed, this, _1));
+ delete jidWndPair.second;
+ }
+
+ vcardManager->onVCardChanged.disconnect(boost::bind(&ShowProfileController::handleVCardChanged, this, _1, _2));
+ uiEventStream->onUIEvent.disconnect(boost::bind(&ShowProfileController::handleUIEvent, this, _1));
+}
+
+void ShowProfileController::handleUIEvent(UIEvent::ref event) {
+ ShowProfileForRosterItemUIEvent::ref showProfileEvent = boost::dynamic_pointer_cast<ShowProfileForRosterItemUIEvent>(event);
+ if (!showProfileEvent) {
+ return;
+ }
+
+ if (openedProfileWindows.find(showProfileEvent->getJID()) == openedProfileWindows.end()) {
+ ProfileWindow* newProfileWindow = profileWindowFactory->createProfileWindow();
+ newProfileWindow->setJID(showProfileEvent->getJID());
+ newProfileWindow->onWindowAboutToBeClosed.connect(boost::bind(&ShowProfileController::handleProfileWindowAboutToBeClosed, this, _1));
+ openedProfileWindows[showProfileEvent->getJID()] = newProfileWindow;
+ VCard::ref vcard = vcardManager->getVCardAndRequestWhenNeeded(showProfileEvent->getJID());
+ if (vcard) {
+ newProfileWindow->setVCard(vcard);
+ } else {
+ newProfileWindow->setProcessing(true);
+ }
+ newProfileWindow->show();
+ } else {
+ openedProfileWindows[showProfileEvent->getJID()]->show();
+ }
+}
+
+void ShowProfileController::handleVCardChanged(const JID& jid, VCard::ref vcard) {
+ if (openedProfileWindows.find(jid) == openedProfileWindows.end()) {
+ return;
+ }
+
+ ProfileWindow* profileWindow = openedProfileWindows[jid];
+ profileWindow->setVCard(vcard);
+ profileWindow->setProcessing(false);
+ profileWindow->show();
+}
+
+void ShowProfileController::handleProfileWindowAboutToBeClosed(const JID& profileJid) {
+ openedProfileWindows.erase(profileJid);
+}
+
+}
diff --git a/Swift/Controllers/ShowProfileController.h b/Swift/Controllers/ShowProfileController.h
new file mode 100644
index 0000000..27a0cf4
--- /dev/null
+++ b/Swift/Controllers/ShowProfileController.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/JID/JID.h>
+#include <Swiften/Elements/VCard.h>
+
+#include <Swift/Controllers/UIEvents/UIEvent.h>
+
+namespace Swift {
+ class VCardManager;
+ class ProfileWindow;
+ class ProfileWindowFactory;
+ class UIEventStream;
+
+ class ShowProfileController {
+ public:
+ ShowProfileController(VCardManager* vcardManager, ProfileWindowFactory* profileWindowFactory, UIEventStream* uiEventStream);
+ ~ShowProfileController();
+
+ private:
+ void handleUIEvent(UIEvent::ref event);
+ void handleVCardChanged(const JID&, VCard::ref);
+ void handleProfileWindowAboutToBeClosed(const JID& profileJid);
+
+ private:
+ VCardManager* vcardManager;
+ ProfileWindowFactory* profileWindowFactory;
+ UIEventStream* uiEventStream;
+ std::map<JID, ProfileWindow*> openedProfileWindows;
+ };
+}
diff --git a/Swift/Controllers/SoundEventController.cpp b/Swift/Controllers/SoundEventController.cpp
index d056990..a5171e2 100644
--- a/Swift/Controllers/SoundEventController.cpp
+++ b/Swift/Controllers/SoundEventController.cpp
@@ -12,22 +12,33 @@
#include <Swift/Controllers/SoundPlayer.h>
#include <Swift/Controllers/UIEvents/UIEventStream.h>
#include <Swift/Controllers/SettingConstants.h>
+#include <Swift/Controllers/HighlightManager.h>
namespace Swift {
-SoundEventController::SoundEventController(EventController* eventController, SoundPlayer* soundPlayer, SettingsProvider* settings) {
+SoundEventController::SoundEventController(EventController* eventController, SoundPlayer* soundPlayer, SettingsProvider* settings, HighlightManager* highlightManager) {
settings_ = settings;
eventController_ = eventController;
soundPlayer_ = soundPlayer;
eventController_->onEventQueueEventAdded.connect(boost::bind(&SoundEventController::handleEventQueueEventAdded, this, _1));
+ highlightManager_ = highlightManager;
+ highlightManager_->onHighlight.connect(boost::bind(&SoundEventController::handleHighlight, this, _1));
+
settings_->onSettingChanged.connect(boost::bind(&SoundEventController::handleSettingChanged, this, _1));
playSounds_ = settings->getSetting(SettingConstants::PLAY_SOUNDS);
}
-void SoundEventController::handleEventQueueEventAdded(boost::shared_ptr<StanzaEvent> event) {
- if (playSounds_ && !event->getConcluded()) {
- soundPlayer_->playSound(SoundPlayer::MessageReceived);
+void SoundEventController::handleEventQueueEventAdded(boost::shared_ptr<StanzaEvent> /*event*/) {
+ // message received sound is now played via highlighting
+ //if (playSounds_ && !event->getConcluded()) {
+ // soundPlayer_->playSound(SoundPlayer::MessageReceived);
+ //}
+}
+
+void SoundEventController::handleHighlight(const HighlightAction& action) {
+ if (playSounds_ && action.playSound()) {
+ soundPlayer_->playSound(SoundPlayer::MessageReceived, action.getSoundFile());
}
}
diff --git a/Swift/Controllers/SoundEventController.h b/Swift/Controllers/SoundEventController.h
index c6dec6f..c9dcab4 100644
--- a/Swift/Controllers/SoundEventController.h
+++ b/Swift/Controllers/SoundEventController.h
@@ -10,21 +10,25 @@
#include <Swift/Controllers/XMPPEvents/StanzaEvent.h>
#include <Swift/Controllers/Settings/SettingsProvider.h>
+#include <Swift/Controllers/HighlightAction.h>
namespace Swift {
class EventController;
class SoundPlayer;
+ class HighlightManager;
class SoundEventController {
public:
- SoundEventController(EventController* eventController, SoundPlayer* soundPlayer, SettingsProvider* settings);
+ SoundEventController(EventController* eventController, SoundPlayer* soundPlayer, SettingsProvider* settings, HighlightManager* highlightManager);
void setPlaySounds(bool playSounds);
- bool getSoundEnabled() {return playSounds_;};
+ bool getSoundEnabled() {return playSounds_;}
private:
void handleSettingChanged(const std::string& settingPath);
void handleEventQueueEventAdded(boost::shared_ptr<StanzaEvent> event);
+ void handleHighlight(const HighlightAction& action);
EventController* eventController_;
SoundPlayer* soundPlayer_;
bool playSounds_;
SettingsProvider* settings_;
+ HighlightManager* highlightManager_;
};
}
diff --git a/Swift/Controllers/SoundPlayer.h b/Swift/Controllers/SoundPlayer.h
index b71d759..f18a2c0 100644
--- a/Swift/Controllers/SoundPlayer.h
+++ b/Swift/Controllers/SoundPlayer.h
@@ -6,11 +6,13 @@
#pragma once
+#include <string>
+
namespace Swift {
class SoundPlayer {
public:
- virtual ~SoundPlayer() {};
+ virtual ~SoundPlayer() {}
enum SoundEffect{MessageReceived};
- virtual void playSound(SoundEffect sound) = 0;
+ virtual void playSound(SoundEffect sound, const std::string& soundResource) = 0;
};
}
diff --git a/Swift/Controllers/StatusCache.cpp b/Swift/Controllers/StatusCache.cpp
new file mode 100644
index 0000000..3444189
--- /dev/null
+++ b/Swift/Controllers/StatusCache.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2012 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swift/Controllers/StatusCache.h>
+
+#include <boost/algorithm/string.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/filesystem/fstream.hpp>
+#include <boost/lambda/lambda.hpp>
+#include <boost/lambda/bind.hpp>
+
+#include <Swiften/Base/foreach.h>
+#include <Swiften/Base/ByteArray.h>
+#include <SwifTools/Application/ApplicationPathProvider.h>
+
+namespace lambda = boost::lambda;
+
+namespace Swift {
+
+static const size_t MAX_ENTRIES = 200;
+
+StatusCache::StatusCache(ApplicationPathProvider* paths) {
+ paths_ = paths;
+ path_ = paths_->getDataDir() / "StatusCache";
+ loadRecents();
+}
+
+StatusCache::~StatusCache() {
+
+}
+
+std::vector<StatusCache::PreviousStatus> StatusCache::getMatches(const std::string& substring, size_t maxCount) const {
+ std::vector<PreviousStatus> matches;
+ foreach (const PreviousStatus& status, previousStatuses_) {
+ if (substring.empty() || (boost::algorithm::ifind_first(status.first, substring) && substring != status.first)) {
+ matches.push_back(status);
+ if (matches.size() == maxCount) {
+ break;
+ }
+ }
+ }
+ return matches;
+}
+
+void StatusCache::addRecent(const std::string& text, StatusShow::Type type) {
+ if (text.empty()) {
+ return;
+ }
+ previousStatuses_.remove_if(lambda::bind(&PreviousStatus::first, lambda::_1) == text && lambda::bind(&PreviousStatus::second, lambda::_1) == type);
+ previousStatuses_.push_front(PreviousStatus(text, type));
+ for (size_t i = previousStatuses_.size(); i > MAX_ENTRIES; i--) {
+ previousStatuses_.pop_back();
+ }
+ saveRecents();
+}
+
+void StatusCache::loadRecents() {
+ try {
+ if (boost::filesystem::exists(path_)) {
+ ByteArray data;
+ readByteArrayFromFile(data, path_);
+ std::string stringData = byteArrayToString(data);
+ std::vector<std::string> lines;
+ boost::split(lines, stringData, boost::is_any_of("\n"));
+ foreach (const std::string& line, lines) {
+ std::vector<std::string> bits;
+ boost::split(bits, line, boost::is_any_of("\t"));
+ if (bits.size() < 2) {
+ continue;
+ }
+ StatusShow::Type type;
+ type = static_cast<StatusShow::Type>(boost::lexical_cast<size_t>(bits[0]));
+ previousStatuses_.push_back(PreviousStatus(boost::trim_copy(bits[1]), type));
+ }
+ }
+ }
+ catch (const boost::filesystem::filesystem_error& e) {
+ std::cerr << "ERROR: " << e.what() << std::endl;
+ }
+}
+
+void StatusCache::saveRecents() {
+ try {
+ if (!boost::filesystem::exists(path_.parent_path())) {
+ boost::filesystem::create_directories(path_.parent_path());
+ }
+ boost::filesystem::ofstream file(path_);
+ foreach (const PreviousStatus& recent, previousStatuses_) {
+ std::string message = recent.first;
+ boost::replace_all(message, "\t", " ");
+ file << recent.second << "\t" << message << std::endl;
+ }
+ file.close();
+ }
+ catch (const boost::filesystem::filesystem_error& e) {
+ std::cerr << "ERROR: " << e.what() << std::endl;
+ }
+}
+
+}
+
+
+
+
diff --git a/Swift/Controllers/StatusCache.h b/Swift/Controllers/StatusCache.h
new file mode 100644
index 0000000..35b3674
--- /dev/null
+++ b/Swift/Controllers/StatusCache.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2012 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <string>
+#include <utility>
+#include <vector>
+#include <list>
+#include <iostream>
+
+#include <boost/filesystem/path.hpp>
+
+#include <Swiften/Elements/StatusShow.h>
+
+namespace Swift {
+ class ApplicationPathProvider;
+ class StatusCache {
+ public:
+ typedef std::pair<std::string, StatusShow::Type> PreviousStatus;
+ public:
+ StatusCache(ApplicationPathProvider* paths);
+ ~StatusCache();
+
+ std::vector<PreviousStatus> getMatches(const std::string& substring, size_t maxCount) const;
+ void addRecent(const std::string& text, StatusShow::Type type);
+ private:
+ void saveRecents();
+ void loadRecents();
+ private:
+ boost::filesystem::path path_;
+ std::list<PreviousStatus> previousStatuses_;
+ ApplicationPathProvider* paths_;
+ };
+}
+
+
diff --git a/Swift/Controllers/StatusTracker.cpp b/Swift/Controllers/StatusTracker.cpp
index 0c88f4d..6766c2e 100644
--- a/Swift/Controllers/StatusTracker.cpp
+++ b/Swift/Controllers/StatusTracker.cpp
@@ -8,6 +8,8 @@
#include <boost/smart_ptr/make_shared.hpp>
+#include <Swiften/Elements/Idle.h>
+
namespace Swift {
StatusTracker::StatusTracker() {
@@ -21,6 +23,7 @@ boost::shared_ptr<Presence> StatusTracker::getNextPresence() {
presence = boost::make_shared<Presence>();
presence->setShow(StatusShow::Away);
presence->setStatus(queuedPresence_->getStatus());
+ presence->addPayload(boost::make_shared<Idle>(isAutoAwaySince_));
} else {
presence = queuedPresence_;
}
@@ -35,11 +38,12 @@ void StatusTracker::setRequestedPresence(boost::shared_ptr<Presence> presence) {
// }
}
-bool StatusTracker::goAutoAway() {
+bool StatusTracker::goAutoAway(const int& seconds) {
if (queuedPresence_->getShow() != StatusShow::Online) {
return false;
}
isAutoAway_ = true;
+ isAutoAwaySince_ = boost::posix_time::second_clock::universal_time() - boost::posix_time::seconds(seconds);
return true;
}
diff --git a/Swift/Controllers/StatusTracker.h b/Swift/Controllers/StatusTracker.h
index 4f4e880..10a5c0c 100644
--- a/Swift/Controllers/StatusTracker.h
+++ b/Swift/Controllers/StatusTracker.h
@@ -10,6 +10,8 @@
#include "Swiften/Elements/Presence.h"
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
namespace Swift {
class StatusTracker {
@@ -17,10 +19,11 @@ namespace Swift {
StatusTracker();
boost::shared_ptr<Presence> getNextPresence();
void setRequestedPresence(boost::shared_ptr<Presence> presence);
- bool goAutoAway();
+ bool goAutoAway(const int& seconds);
bool goAutoUnAway();
private:
boost::shared_ptr<Presence> queuedPresence_;
bool isAutoAway_;
+ boost::posix_time::ptime isAutoAwaySince_;
};
}
diff --git a/Swift/Controllers/StatusUtil.cpp b/Swift/Controllers/StatusUtil.cpp
index fd1fea3..a72f340 100644
--- a/Swift/Controllers/StatusUtil.cpp
+++ b/Swift/Controllers/StatusUtil.cpp
@@ -6,6 +6,7 @@
#include <Swift/Controllers/StatusUtil.h>
+#include <cassert>
#include <Swift/Controllers/Intl.h>
namespace Swift {
@@ -19,6 +20,7 @@ std::string statusShowTypeToFriendlyName(StatusShow::Type type) {
case StatusShow::DND: return QT_TRANSLATE_NOOP("", "Busy");
case StatusShow::None: return QT_TRANSLATE_NOOP("", "Offline");
}
+ assert(false);
return "";
}
diff --git a/Swift/Controllers/Storages/AvatarFileStorage.cpp b/Swift/Controllers/Storages/AvatarFileStorage.cpp
index b39e586..671e0cb 100644
--- a/Swift/Controllers/Storages/AvatarFileStorage.cpp
+++ b/Swift/Controllers/Storages/AvatarFileStorage.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2013 Remko Tronçon
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -12,12 +12,12 @@
#include <Swiften/Base/foreach.h>
#include <Swiften/Base/String.h>
-#include <Swiften/StringCodecs/SHA1.h>
#include <Swiften/StringCodecs/Hexify.h>
+#include <Swiften/Crypto/CryptoProvider.h>
namespace Swift {
-AvatarFileStorage::AvatarFileStorage(const boost::filesystem::path& avatarsDir, const boost::filesystem::path& avatarsFile) : avatarsDir(avatarsDir), avatarsFile(avatarsFile) {
+AvatarFileStorage::AvatarFileStorage(const boost::filesystem::path& avatarsDir, const boost::filesystem::path& avatarsFile, CryptoProvider* crypto) : avatarsDir(avatarsDir), avatarsFile(avatarsFile), crypto(crypto) {
if (boost::filesystem::exists(avatarsFile)) {
try {
boost::filesystem::ifstream file(avatarsFile);
@@ -47,7 +47,7 @@ bool AvatarFileStorage::hasAvatar(const std::string& hash) const {
}
void AvatarFileStorage::addAvatar(const std::string& hash, const ByteArray& avatar) {
- assert(Hexify::hexify(SHA1::getHash(avatar)) == hash);
+ assert(Hexify::hexify(crypto->getSHA1Hash(avatar)) == hash);
boost::filesystem::path avatarPath = getAvatarPath(hash);
if (!boost::filesystem::exists(avatarPath.parent_path())) {
@@ -69,7 +69,7 @@ boost::filesystem::path AvatarFileStorage::getAvatarPath(const std::string& hash
ByteArray AvatarFileStorage::getAvatar(const std::string& hash) const {
ByteArray data;
- readByteArrayFromFile(data, getAvatarPath(hash).string());
+ readByteArrayFromFile(data, getAvatarPath(hash));
return data;
}
diff --git a/Swift/Controllers/Storages/AvatarFileStorage.h b/Swift/Controllers/Storages/AvatarFileStorage.h
index b7e73f5..85a6463 100644
--- a/Swift/Controllers/Storages/AvatarFileStorage.h
+++ b/Swift/Controllers/Storages/AvatarFileStorage.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2013 Remko Tronçon
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -15,9 +15,11 @@
#include "Swiften/Avatars/AvatarStorage.h"
namespace Swift {
+ class CryptoProvider;
+
class AvatarFileStorage : public AvatarStorage {
public:
- AvatarFileStorage(const boost::filesystem::path& avatarsDir, const boost::filesystem::path& avatarsFile);
+ AvatarFileStorage(const boost::filesystem::path& avatarsDir, const boost::filesystem::path& avatarsFile, CryptoProvider* crypto);
virtual bool hasAvatar(const std::string& hash) const;
virtual void addAvatar(const std::string& hash, const ByteArray& avatar);
@@ -34,6 +36,7 @@ namespace Swift {
private:
boost::filesystem::path avatarsDir;
boost::filesystem::path avatarsFile;
+ CryptoProvider* crypto;
typedef std::map<JID, std::string> JIDAvatarMap;
JIDAvatarMap jidAvatars;
};
diff --git a/Swift/Controllers/Storages/CertificateFileStorage.cpp b/Swift/Controllers/Storages/CertificateFileStorage.cpp
index a4a95c7..34d1f76 100644
--- a/Swift/Controllers/Storages/CertificateFileStorage.cpp
+++ b/Swift/Controllers/Storages/CertificateFileStorage.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2013 Remko Tronçon
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -8,22 +8,23 @@
#include <iostream>
#include <boost/filesystem/fstream.hpp>
+#include <boost/numeric/conversion/cast.hpp>
-#include <Swiften/StringCodecs/SHA1.h>
#include <Swiften/StringCodecs/Hexify.h>
#include <Swiften/TLS/CertificateFactory.h>
#include <Swiften/Base/Log.h>
+#include <Swiften/Crypto/CryptoProvider.h>
namespace Swift {
-CertificateFileStorage::CertificateFileStorage(const boost::filesystem::path& path, CertificateFactory* certificateFactory) : path(path), certificateFactory(certificateFactory) {
+CertificateFileStorage::CertificateFileStorage(const boost::filesystem::path& path, CertificateFactory* certificateFactory, CryptoProvider* crypto) : path(path), certificateFactory(certificateFactory), crypto(crypto) {
}
bool CertificateFileStorage::hasCertificate(Certificate::ref certificate) const {
boost::filesystem::path certificatePath = getCertificatePath(certificate);
if (boost::filesystem::exists(certificatePath)) {
ByteArray data;
- readByteArrayFromFile(data, certificatePath.string());
+ readByteArrayFromFile(data, certificatePath);
Certificate::ref storedCertificate = certificateFactory->createCertificateFromDER(data);
if (storedCertificate && storedCertificate->toDER() == certificate->toDER()) {
return true;
@@ -50,12 +51,12 @@ void CertificateFileStorage::addCertificate(Certificate::ref certificate) {
}
boost::filesystem::ofstream file(certificatePath, boost::filesystem::ofstream::binary|boost::filesystem::ofstream::out);
ByteArray data = certificate->toDER();
- file.write(reinterpret_cast<const char*>(vecptr(data)), data.size());
+ file.write(reinterpret_cast<const char*>(vecptr(data)), boost::numeric_cast<std::streamsize>(data.size()));
file.close();
}
boost::filesystem::path CertificateFileStorage::getCertificatePath(Certificate::ref certificate) const {
- return path / Hexify::hexify(SHA1::getHash(certificate->toDER()));
+ return path / Hexify::hexify(crypto->getSHA1Hash(certificate->toDER()));
}
}
diff --git a/Swift/Controllers/Storages/CertificateFileStorage.h b/Swift/Controllers/Storages/CertificateFileStorage.h
index f7a60b9..12151d0 100644
--- a/Swift/Controllers/Storages/CertificateFileStorage.h
+++ b/Swift/Controllers/Storages/CertificateFileStorage.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2013 Remko Tronçon
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -12,10 +12,11 @@
namespace Swift {
class CertificateFactory;
+ class CryptoProvider;
class CertificateFileStorage : public CertificateStorage {
public:
- CertificateFileStorage(const boost::filesystem::path& path, CertificateFactory* certificateFactory);
+ CertificateFileStorage(const boost::filesystem::path& path, CertificateFactory* certificateFactory, CryptoProvider* crypto);
virtual bool hasCertificate(Certificate::ref certificate) const;
virtual void addCertificate(Certificate::ref certificate);
@@ -26,6 +27,7 @@ namespace Swift {
private:
boost::filesystem::path path;
CertificateFactory* certificateFactory;
+ CryptoProvider* crypto;
};
}
diff --git a/Swift/Controllers/Storages/CertificateFileStorageFactory.h b/Swift/Controllers/Storages/CertificateFileStorageFactory.h
index b215165..6834619 100644
--- a/Swift/Controllers/Storages/CertificateFileStorageFactory.h
+++ b/Swift/Controllers/Storages/CertificateFileStorageFactory.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2013 Remko Tronçon
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -11,18 +11,20 @@
namespace Swift {
class CertificateFactory;
+ class CryptoProvider;
class CertificateFileStorageFactory : public CertificateStorageFactory {
public:
- CertificateFileStorageFactory(const boost::filesystem::path& basePath, CertificateFactory* certificateFactory) : basePath(basePath), certificateFactory(certificateFactory) {}
+ CertificateFileStorageFactory(const boost::filesystem::path& basePath, CertificateFactory* certificateFactory, CryptoProvider* crypto) : basePath(basePath), certificateFactory(certificateFactory), crypto(crypto) {}
virtual CertificateStorage* createCertificateStorage(const JID& profile) const {
boost::filesystem::path profilePath = basePath / profile.toString();
- return new CertificateFileStorage(profilePath / "certificates", certificateFactory);
+ return new CertificateFileStorage(profilePath / "certificates", certificateFactory, crypto);
}
private:
boost::filesystem::path basePath;
CertificateFactory* certificateFactory;
+ CryptoProvider* crypto;
};
}
diff --git a/Swift/Controllers/Storages/FileStorages.cpp b/Swift/Controllers/Storages/FileStorages.cpp
index cff87d3..52a5e00 100644
--- a/Swift/Controllers/Storages/FileStorages.cpp
+++ b/Swift/Controllers/Storages/FileStorages.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2013 Remko Tronçon
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -10,17 +10,18 @@
#include "Swift/Controllers/Storages/CapsFileStorage.h"
#include "Swift/Controllers/Storages/RosterFileStorage.h"
#include <Swiften/History/SQLiteHistoryStorage.h>
+#include <Swiften/Base/Path.h>
namespace Swift {
-FileStorages::FileStorages(const boost::filesystem::path& baseDir, const JID& jid) {
- std::string profile = jid.toBare();
- vcardStorage = new VCardFileStorage(baseDir / profile / "vcards");
+FileStorages::FileStorages(const boost::filesystem::path& baseDir, const JID& jid, CryptoProvider* crypto) {
+ boost::filesystem::path profile = stringToPath(jid.toBare());
+ vcardStorage = new VCardFileStorage(baseDir / profile / "vcards", crypto);
capsStorage = new CapsFileStorage(baseDir / "caps");
- avatarStorage = new AvatarFileStorage(baseDir / "avatars", baseDir / profile / "avatars");
+ avatarStorage = new AvatarFileStorage(baseDir / "avatars", baseDir / profile / "avatars", crypto);
rosterStorage = new RosterFileStorage(baseDir / profile / "roster.xml");
#ifdef SWIFT_EXPERIMENTAL_HISTORY
- historyStorage = new SQLiteHistoryStorage((baseDir / "history.db").string());
+ historyStorage = new SQLiteHistoryStorage(baseDir / "history.db");
#endif
}
diff --git a/Swift/Controllers/Storages/FileStorages.h b/Swift/Controllers/Storages/FileStorages.h
index 5e89db8..1e914b9 100644
--- a/Swift/Controllers/Storages/FileStorages.h
+++ b/Swift/Controllers/Storages/FileStorages.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2013 Remko Tronçon
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -8,7 +8,7 @@
#include <boost/filesystem/path.hpp>
-#include "Swiften/Client/Storages.h"
+#include <Swiften/Client/Storages.h>
namespace Swift {
class VCardFileStorage;
@@ -17,6 +17,7 @@ namespace Swift {
class RosterFileStorage;
class HistoryStorage;
class JID;
+ class CryptoProvider;
/**
* A storages implementation that stores all controller data on disk.
@@ -37,7 +38,7 @@ namespace Swift {
* \param jid the subdir in which profile-specific data will be stored.
* The bare JID will be used as the subdir name.
*/
- FileStorages(const boost::filesystem::path& baseDir, const JID& jid);
+ FileStorages(const boost::filesystem::path& baseDir, const JID& jid, CryptoProvider*);
~FileStorages();
virtual VCardStorage* getVCardStorage() const;
diff --git a/Swift/Controllers/Storages/FileStoragesFactory.h b/Swift/Controllers/Storages/FileStoragesFactory.h
index 0676bc3..c119dcf 100644
--- a/Swift/Controllers/Storages/FileStoragesFactory.h
+++ b/Swift/Controllers/Storages/FileStoragesFactory.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2013 Remko Tronçon
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -10,15 +10,18 @@
#include "Swift/Controllers/Storages/FileStorages.h"
namespace Swift {
+ class CryptoProvider;
+
class FileStoragesFactory : public StoragesFactory {
public:
- FileStoragesFactory(const boost::filesystem::path& basePath) : basePath(basePath) {}
+ FileStoragesFactory(const boost::filesystem::path& basePath, CryptoProvider* crypto) : basePath(basePath), crypto(crypto) {}
virtual Storages* createStorages(const JID& profile) const {
- return new FileStorages(basePath, profile);
+ return new FileStorages(basePath, profile, crypto);
}
private:
boost::filesystem::path basePath;
+ CryptoProvider* crypto;
};
}
diff --git a/Swift/Controllers/Storages/VCardFileStorage.cpp b/Swift/Controllers/Storages/VCardFileStorage.cpp
index d799a90..b22e235 100644
--- a/Swift/Controllers/Storages/VCardFileStorage.cpp
+++ b/Swift/Controllers/Storages/VCardFileStorage.cpp
@@ -13,8 +13,9 @@
#include <Swiften/Entity/GenericPayloadPersister.h>
#include <Swiften/Base/String.h>
#include <Swiften/StringCodecs/Hexify.h>
-#include <Swiften/StringCodecs/SHA1.h>
#include <Swiften/Base/foreach.h>
+#include <Swiften/Base/Path.h>
+#include <Swiften/Crypto/CryptoProvider.h>
#include "Swiften/JID/JID.h"
#include "Swiften/Elements/VCard.h"
#include "Swiften/Serializer/PayloadSerializers/VCardSerializer.h"
@@ -25,7 +26,7 @@ using namespace Swift;
typedef GenericPayloadPersister<VCard, VCardParser, VCardSerializer> VCardPersister;
-VCardFileStorage::VCardFileStorage(boost::filesystem::path dir) : vcardsPath(dir) {
+VCardFileStorage::VCardFileStorage(boost::filesystem::path dir, CryptoProvider* crypto) : VCardStorage(crypto), vcardsPath(dir), crypto(crypto) {
cacheFile = vcardsPath / "phashes";
if (boost::filesystem::exists(cacheFile)) {
try {
@@ -66,7 +67,7 @@ boost::filesystem::path VCardFileStorage::getVCardPath(const JID& jid) const {
try {
std::string file(jid.toString());
String::replaceAll(file, '/', "%2f");
- return boost::filesystem::path(vcardsPath / (file + ".xml"));
+ return boost::filesystem::path(vcardsPath / stringToPath(file + ".xml"));
}
catch (const boost::filesystem::filesystem_error& e) {
std::cerr << "ERROR: " << e.what() << std::endl;
@@ -88,7 +89,7 @@ std::string VCardFileStorage::getPhotoHash(const JID& jid) const {
std::string VCardFileStorage::getAndUpdatePhotoHash(const JID& jid, VCard::ref vCard) const {
std::string hash;
if (vCard && !vCard->getPhoto().empty()) {
- hash = Hexify::hexify(SHA1::getHash(vCard->getPhoto()));
+ hash = Hexify::hexify(crypto->getSHA1Hash(vCard->getPhoto()));
}
std::pair<PhotoHashMap::iterator, bool> r = photoHashes.insert(std::make_pair(jid, hash));
if (r.second) {
diff --git a/Swift/Controllers/Storages/VCardFileStorage.h b/Swift/Controllers/Storages/VCardFileStorage.h
index ba422f4..2c3af3d 100644
--- a/Swift/Controllers/Storages/VCardFileStorage.h
+++ b/Swift/Controllers/Storages/VCardFileStorage.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2013 Remko Tronçon
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -14,9 +14,11 @@
#include "Swiften/VCards/VCardStorage.h"
namespace Swift {
+ class CryptoProvider;
+
class VCardFileStorage : public VCardStorage {
public:
- VCardFileStorage(boost::filesystem::path dir);
+ VCardFileStorage(boost::filesystem::path dir, CryptoProvider* crypto);
virtual VCard::ref getVCard(const JID& jid) const;
virtual void setVCard(const JID& jid, VCard::ref v);
@@ -31,6 +33,7 @@ namespace Swift {
private:
boost::filesystem::path vcardsPath;
+ CryptoProvider* crypto;
boost::filesystem::path cacheFile;
typedef std::map<JID, std::string> PhotoHashMap;
mutable PhotoHashMap photoHashes;
diff --git a/Swift/Controllers/SystemTray.h b/Swift/Controllers/SystemTray.h
index 736b1fa..b71a783 100644
--- a/Swift/Controllers/SystemTray.h
+++ b/Swift/Controllers/SystemTray.h
@@ -11,7 +11,7 @@
namespace Swift {
class SystemTray {
public:
- virtual ~SystemTray(){};
+ virtual ~SystemTray(){}
virtual void setUnreadMessages(bool some) = 0;
virtual void setStatusType(StatusShow::Type type) = 0;
virtual void setConnecting() = 0;
diff --git a/Swift/Controllers/Translator.cpp b/Swift/Controllers/Translator.cpp
index 82fc46e..b7766ca 100644
--- a/Swift/Controllers/Translator.cpp
+++ b/Swift/Controllers/Translator.cpp
@@ -10,7 +10,7 @@
namespace Swift {
-struct DefaultTranslator : public Translator {
+static struct DefaultTranslator : public Translator {
virtual std::string translate(const std::string& text, const std::string&) {
return text;
}
diff --git a/Swift/Controllers/UIEvents/AddContactUIEvent.h b/Swift/Controllers/UIEvents/AddContactUIEvent.h
index d92d3af..6b70b76 100644
--- a/Swift/Controllers/UIEvents/AddContactUIEvent.h
+++ b/Swift/Controllers/UIEvents/AddContactUIEvent.h
@@ -14,15 +14,15 @@
namespace Swift {
class AddContactUIEvent : public UIEvent {
public:
- AddContactUIEvent(const JID& jid, const std::string& name, const std::set<std::string>& groups) : jid_(jid), name_(name), groups_(groups) {};
+ AddContactUIEvent(const JID& jid, const std::string& name, const std::set<std::string>& groups) : jid_(jid), name_(name), groups_(groups) {}
const std::string& getName() const {
return name_;
- };
+ }
const JID& getJID() const {
return jid_;
- };
+ }
const std::set<std::string>& getGroups() const {
return groups_;
diff --git a/Swift/Controllers/UIEvents/AddMUCBookmarkUIEvent.h b/Swift/Controllers/UIEvents/AddMUCBookmarkUIEvent.h
index 210da3e..df01d6c 100644
--- a/Swift/Controllers/UIEvents/AddMUCBookmarkUIEvent.h
+++ b/Swift/Controllers/UIEvents/AddMUCBookmarkUIEvent.h
@@ -14,7 +14,7 @@
namespace Swift {
class AddMUCBookmarkUIEvent : public UIEvent {
public:
- AddMUCBookmarkUIEvent(const MUCBookmark& bookmark) : bookmark(bookmark) {};
+ AddMUCBookmarkUIEvent(const MUCBookmark& bookmark) : bookmark(bookmark) {}
const MUCBookmark& getBookmark() { return bookmark; }
private:
diff --git a/Swift/Controllers/UIEvents/CreateImpromptuMUCUIEvent.h b/Swift/Controllers/UIEvents/CreateImpromptuMUCUIEvent.h
new file mode 100644
index 0000000..57e181d
--- /dev/null
+++ b/Swift/Controllers/UIEvents/CreateImpromptuMUCUIEvent.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swift/Controllers/UIEvents/UIEvent.h>
+
+namespace Swift {
+
+class CreateImpromptuMUCUIEvent : public UIEvent {
+ public:
+ CreateImpromptuMUCUIEvent(const std::vector<JID>& jids, const JID& roomJID = JID(), const std::string reason = "") : jids_(jids), roomJID_(roomJID), reason_(reason) { }
+
+ std::vector<JID> getJIDs() const { return jids_; }
+ JID getRoomJID() const { return roomJID_; }
+ std::string getReason() const { return reason_; }
+ private:
+ std::vector<JID> jids_;
+ JID roomJID_;
+ std::string reason_;
+};
+
+}
diff --git a/Swift/Controllers/UIEvents/EditMUCBookmarkUIEvent.h b/Swift/Controllers/UIEvents/EditMUCBookmarkUIEvent.h
index 2b10f09..7723d89 100644
--- a/Swift/Controllers/UIEvents/EditMUCBookmarkUIEvent.h
+++ b/Swift/Controllers/UIEvents/EditMUCBookmarkUIEvent.h
@@ -14,10 +14,10 @@
namespace Swift {
class EditMUCBookmarkUIEvent : public UIEvent {
public:
- EditMUCBookmarkUIEvent(const MUCBookmark& oldBookmark, const MUCBookmark& newBookmark) : oldBookmark(oldBookmark) , newBookmark(newBookmark) {};
+ EditMUCBookmarkUIEvent(const MUCBookmark& oldBookmark, const MUCBookmark& newBookmark) : oldBookmark(oldBookmark) , newBookmark(newBookmark) {}
- const MUCBookmark& getOldBookmark() {return oldBookmark;};
- const MUCBookmark& getNewBookmark() {return newBookmark;};
+ const MUCBookmark& getOldBookmark() {return oldBookmark;}
+ const MUCBookmark& getNewBookmark() {return newBookmark;}
private:
MUCBookmark oldBookmark;
diff --git a/Swift/Controllers/UIEvents/InviteToMUCUIEvent.h b/Swift/Controllers/UIEvents/InviteToMUCUIEvent.h
new file mode 100644
index 0000000..cb9d20b
--- /dev/null
+++ b/Swift/Controllers/UIEvents/InviteToMUCUIEvent.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+#include <vector>
+
+#include <Swift/Controllers/UIEvents/UIEvent.h>
+#include <Swiften/JID/JID.h>
+
+namespace Swift {
+ class InviteToMUCUIEvent : public UIEvent {
+ public:
+ typedef boost::shared_ptr<InviteToMUCUIEvent> ref;
+
+ InviteToMUCUIEvent(const JID& room, const std::vector<JID>& JIDsToInvite, const std::string& reason) : room_(room), invite_(JIDsToInvite), reason_(reason) {
+ }
+
+ const JID& getRoom() const {
+ return room_;
+ }
+
+ const std::vector<JID> getInvites() const {
+ return invite_;
+ }
+
+ const std::string getReason() const {
+ return reason_;
+ }
+
+ private:
+ JID room_;
+ std::vector<JID> invite_;
+ std::string reason_;
+ };
+}
diff --git a/Swift/Controllers/UIEvents/JoinMUCUIEvent.h b/Swift/Controllers/UIEvents/JoinMUCUIEvent.h
index b3ff8c7..e046942 100644
--- a/Swift/Controllers/UIEvents/JoinMUCUIEvent.h
+++ b/Swift/Controllers/UIEvents/JoinMUCUIEvent.h
@@ -18,17 +18,22 @@ namespace Swift {
class JoinMUCUIEvent : public UIEvent {
public:
typedef boost::shared_ptr<JoinMUCUIEvent> ref;
- JoinMUCUIEvent(const JID& jid, const boost::optional<std::string>& password = boost::optional<std::string>(), const boost::optional<std::string>& nick = boost::optional<std::string>(), bool joinAutomaticallyInFuture = false, bool createAsReservedRoomIfNew = false) : jid_(jid), nick_(nick), joinAutomatically_(joinAutomaticallyInFuture), createAsReservedRoomIfNew_(createAsReservedRoomIfNew), password_(password) {};
+ JoinMUCUIEvent(const JID& jid, const boost::optional<std::string>& password = boost::optional<std::string>(), const boost::optional<std::string>& nick = boost::optional<std::string>(), bool joinAutomaticallyInFuture = false, bool createAsReservedRoomIfNew = false, bool isImpromptu = false, bool isContinuation = false) : jid_(jid), nick_(nick), joinAutomatically_(joinAutomaticallyInFuture), createAsReservedRoomIfNew_(createAsReservedRoomIfNew), password_(password), isImpromptuMUC_(isImpromptu), isContinuation_(isContinuation) {}
const boost::optional<std::string>& getNick() const {return nick_;}
const JID& getJID() const {return jid_;}
bool getShouldJoinAutomatically() const {return joinAutomatically_;}
bool getCreateAsReservedRoomIfNew() const {return createAsReservedRoomIfNew_;}
const boost::optional<std::string>& getPassword() const {return password_;}
+ bool isImpromptu() const {return isImpromptuMUC_;}
+ bool isContinuation() const {return isContinuation_;}
+
private:
JID jid_;
boost::optional<std::string> nick_;
bool joinAutomatically_;
bool createAsReservedRoomIfNew_;
boost::optional<std::string> password_;
+ bool isImpromptuMUC_;
+ bool isContinuation_;
};
}
diff --git a/Swift/Controllers/UIEvents/RemoveMUCBookmarkUIEvent.h b/Swift/Controllers/UIEvents/RemoveMUCBookmarkUIEvent.h
index ea2e609..0df40f9 100644
--- a/Swift/Controllers/UIEvents/RemoveMUCBookmarkUIEvent.h
+++ b/Swift/Controllers/UIEvents/RemoveMUCBookmarkUIEvent.h
@@ -14,7 +14,7 @@
namespace Swift {
class RemoveMUCBookmarkUIEvent : public UIEvent {
public:
- RemoveMUCBookmarkUIEvent(const MUCBookmark& bookmark) : bookmark(bookmark) {};
+ RemoveMUCBookmarkUIEvent(const MUCBookmark& bookmark) : bookmark(bookmark) {}
const MUCBookmark& getBookmark() { return bookmark; }
private:
diff --git a/Swift/Controllers/UIEvents/RemoveRosterItemUIEvent.h b/Swift/Controllers/UIEvents/RemoveRosterItemUIEvent.h
index 7e5236a..617daf3 100644
--- a/Swift/Controllers/UIEvents/RemoveRosterItemUIEvent.h
+++ b/Swift/Controllers/UIEvents/RemoveRosterItemUIEvent.h
@@ -13,9 +13,9 @@ namespace Swift {
class RemoveRosterItemUIEvent : public UIEvent {
public:
- RemoveRosterItemUIEvent(const JID& jid) : jid_(jid) {};
- virtual ~RemoveRosterItemUIEvent() {};
- JID getJID() {return jid_;};
+ RemoveRosterItemUIEvent(const JID& jid) : jid_(jid) {}
+ virtual ~RemoveRosterItemUIEvent() {}
+ JID getJID() {return jid_;}
private:
JID jid_;
diff --git a/Swift/Controllers/UIEvents/RequestAdHocUIEvent.h b/Swift/Controllers/UIEvents/RequestAdHocUIEvent.h
index c3b4b49..a0b51f2 100644
--- a/Swift/Controllers/UIEvents/RequestAdHocUIEvent.h
+++ b/Swift/Controllers/UIEvents/RequestAdHocUIEvent.h
@@ -13,7 +13,7 @@
namespace Swift {
class RequestAdHocUIEvent : public UIEvent {
public:
- RequestAdHocUIEvent(const DiscoItems::Item& command) : command_(command) {};
+ RequestAdHocUIEvent(const DiscoItems::Item& command) : command_(command) {}
const DiscoItems::Item& getCommand() const {return command_;}
private:
DiscoItems::Item command_;
diff --git a/Swift/Controllers/UIEvents/RequestAddUserDialogUIEvent.h b/Swift/Controllers/UIEvents/RequestAddUserDialogUIEvent.h
index 5a071cf..7fe1926 100644
--- a/Swift/Controllers/UIEvents/RequestAddUserDialogUIEvent.h
+++ b/Swift/Controllers/UIEvents/RequestAddUserDialogUIEvent.h
@@ -15,11 +15,11 @@ namespace Swift {
class RequestAddUserDialogUIEvent : public UIEvent {
public:
- RequestAddUserDialogUIEvent(const JID& predefinedJID, const std::string& predefinedName) : preJID_(predefinedJID), preName_(predefinedName) {};
- RequestAddUserDialogUIEvent() : preJID_(), preName_() {};
+ RequestAddUserDialogUIEvent(const JID& predefinedJID, const std::string& predefinedName) : preJID_(predefinedJID), preName_(predefinedName) {}
+ RequestAddUserDialogUIEvent() : preJID_(), preName_() {}
- const JID& getPredefinedJID() const { return preJID_; };
- const std::string& getPredefinedName() const { return preName_; };
+ const JID& getPredefinedJID() const { return preJID_; }
+ const std::string& getPredefinedName() const { return preName_; }
private:
JID preJID_;
diff --git a/Swift/Controllers/UIEvents/RequestBlockListDialogUIEvent.h b/Swift/Controllers/UIEvents/RequestBlockListDialogUIEvent.h
new file mode 100644
index 0000000..d29cb4f
--- /dev/null
+++ b/Swift/Controllers/UIEvents/RequestBlockListDialogUIEvent.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swift/Controllers/UIEvents/UIEvent.h>
+
+namespace Swift {
+
+class RequestBlockListDialogUIEvent : public UIEvent {
+};
+
+}
diff --git a/Swift/Controllers/UIEvents/RequestChangeBlockStateUIEvent.h b/Swift/Controllers/UIEvents/RequestChangeBlockStateUIEvent.h
new file mode 100644
index 0000000..9b7abcb
--- /dev/null
+++ b/Swift/Controllers/UIEvents/RequestChangeBlockStateUIEvent.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swift/Controllers/UIEvents/UIEvent.h>
+
+#include <Swiften/JID/JID.h>
+
+namespace Swift {
+
+class RequestChangeBlockStateUIEvent : public UIEvent {
+ public:
+ enum BlockState {
+ Blocked,
+ Unblocked
+ };
+
+ public:
+ RequestChangeBlockStateUIEvent(BlockState newState, const JID& contact) : state_(newState), contact_(contact) {}
+
+ BlockState getBlockState() const {
+ return state_;
+ }
+
+ JID getContact() const {
+ return contact_;
+ }
+ private:
+ BlockState state_;
+ JID contact_;
+};
+
+}
diff --git a/Swift/Controllers/UIEvents/RequestChatUIEvent.h b/Swift/Controllers/UIEvents/RequestChatUIEvent.h
index b1e86ed..4ef954f 100644
--- a/Swift/Controllers/UIEvents/RequestChatUIEvent.h
+++ b/Swift/Controllers/UIEvents/RequestChatUIEvent.h
@@ -13,7 +13,7 @@
namespace Swift {
class RequestChatUIEvent : public UIEvent {
public:
- RequestChatUIEvent(const JID& contact) : contact_(contact) {};
+ RequestChatUIEvent(const JID& contact) : contact_(contact) {}
JID getContact() {return contact_;}
private:
JID contact_;
diff --git a/Swift/Controllers/UIEvents/RequestHighlightEditorUIEvent.h b/Swift/Controllers/UIEvents/RequestHighlightEditorUIEvent.h
new file mode 100644
index 0000000..42e22a2
--- /dev/null
+++ b/Swift/Controllers/UIEvents/RequestHighlightEditorUIEvent.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2012 Maciej Niedzielski
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swift/Controllers/UIEvents/UIEvent.h>
+
+namespace Swift {
+
+ class RequestHighlightEditorUIEvent : public UIEvent {
+ };
+
+}
diff --git a/Swift/Controllers/UIEvents/RequestInviteToMUCUIEvent.h b/Swift/Controllers/UIEvents/RequestInviteToMUCUIEvent.h
new file mode 100644
index 0000000..69aa0cd
--- /dev/null
+++ b/Swift/Controllers/UIEvents/RequestInviteToMUCUIEvent.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+#include <vector>
+
+#include <Swift/Controllers/UIEvents/UIEvent.h>
+#include <Swiften/JID/JID.h>
+
+namespace Swift {
+ class RequestInviteToMUCUIEvent : public UIEvent {
+ public:
+ typedef boost::shared_ptr<RequestInviteToMUCUIEvent> ref;
+
+ RequestInviteToMUCUIEvent(const JID& room, const std::vector<JID>& JIDsToInvite) : room_(room), invite_(JIDsToInvite) {
+ }
+
+ const JID& getRoom() const {
+ return room_;
+ }
+
+ const std::vector<JID> getInvites() const {
+ return invite_;
+ }
+
+ private:
+ JID room_;
+ std::vector<JID> invite_;
+ };
+}
diff --git a/Swift/Controllers/UIEvents/RequestWhiteboardUIEvent.h b/Swift/Controllers/UIEvents/RequestWhiteboardUIEvent.h
index f5b995b..5c44da7 100644
--- a/Swift/Controllers/UIEvents/RequestWhiteboardUIEvent.h
+++ b/Swift/Controllers/UIEvents/RequestWhiteboardUIEvent.h
@@ -13,7 +13,7 @@
namespace Swift {
class RequestWhiteboardUIEvent : public UIEvent {
public:
- RequestWhiteboardUIEvent(const JID& contact) : contact_(contact) {};
+ RequestWhiteboardUIEvent(const JID& contact) : contact_(contact) {}
const JID& getContact() const {return contact_;}
private:
JID contact_;
diff --git a/Swift/Controllers/UIEvents/ShowProfileForRosterItemUIEvent.h b/Swift/Controllers/UIEvents/ShowProfileForRosterItemUIEvent.h
new file mode 100644
index 0000000..4a603ea
--- /dev/null
+++ b/Swift/Controllers/UIEvents/ShowProfileForRosterItemUIEvent.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/JID/JID.h>
+#include <Swift/Controllers/UIEvents/UIEvent.h>
+
+namespace Swift {
+
+class ShowProfileForRosterItemUIEvent : public UIEvent {
+ public:
+ typedef boost::shared_ptr<ShowProfileForRosterItemUIEvent> ref;
+ public:
+ ShowProfileForRosterItemUIEvent(const JID& jid) : jid_(jid) {}
+ virtual ~ShowProfileForRosterItemUIEvent() {}
+ JID getJID() const {return jid_;}
+ private:
+ JID jid_;
+};
+
+}
diff --git a/Swift/Controllers/UIEvents/ShowWhiteboardUIEvent.h b/Swift/Controllers/UIEvents/ShowWhiteboardUIEvent.h
index 265bf7d..bb72d9b 100644
--- a/Swift/Controllers/UIEvents/ShowWhiteboardUIEvent.h
+++ b/Swift/Controllers/UIEvents/ShowWhiteboardUIEvent.h
@@ -13,7 +13,7 @@
namespace Swift {
class ShowWhiteboardUIEvent : public UIEvent {
public:
- ShowWhiteboardUIEvent(const JID& contact) : contact_(contact) {};
+ ShowWhiteboardUIEvent(const JID& contact) : contact_(contact) {}
const JID& getContact() const {return contact_;}
private:
JID contact_;
diff --git a/Swift/Controllers/UIEvents/UIEventStream.h b/Swift/Controllers/UIEvents/UIEventStream.h
index e174029..b1337a2 100644
--- a/Swift/Controllers/UIEvents/UIEventStream.h
+++ b/Swift/Controllers/UIEvents/UIEventStream.h
@@ -18,6 +18,6 @@ namespace Swift {
void send(boost::shared_ptr<UIEvent> event) {
onUIEvent(event);
- };
+ }
};
}
diff --git a/Swift/Controllers/UIInterfaces/AdHocCommandWindow.h b/Swift/Controllers/UIInterfaces/AdHocCommandWindow.h
index f7a5d39..835defe 100644
--- a/Swift/Controllers/UIInterfaces/AdHocCommandWindow.h
+++ b/Swift/Controllers/UIInterfaces/AdHocCommandWindow.h
@@ -9,6 +9,6 @@
namespace Swift {
class AdHocCommandWindow {
public:
- virtual ~AdHocCommandWindow() {};
+ virtual ~AdHocCommandWindow() {}
};
}
diff --git a/Swift/Controllers/UIInterfaces/BlockListEditorWidget.h b/Swift/Controllers/UIInterfaces/BlockListEditorWidget.h
new file mode 100644
index 0000000..60a1c11
--- /dev/null
+++ b/Swift/Controllers/UIInterfaces/BlockListEditorWidget.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <vector>
+
+#include <Swiften/JID/JID.h>
+#include <Swiften/Base/boost_bsignals.h>
+
+namespace Swift {
+
+ class ClientBlockListManager;
+
+ class BlockListEditorWidget {
+ public:
+ virtual ~BlockListEditorWidget() {}
+
+ virtual void show() = 0;
+
+ virtual void setCurrentBlockList(const std::vector<JID>& blockedJIDs) = 0;
+ virtual void setBusy(bool isBusy) = 0;
+
+ virtual std::vector<JID> getCurrentBlockList() const = 0;
+
+ boost::signal<void (const std::vector<JID>& /* blockedJID */)> onSetNewBlockList;
+ };
+
+}
diff --git a/Swift/Controllers/UIInterfaces/BlockListEditorWidgetFactory.h b/Swift/Controllers/UIInterfaces/BlockListEditorWidgetFactory.h
new file mode 100644
index 0000000..eb91ac1
--- /dev/null
+++ b/Swift/Controllers/UIInterfaces/BlockListEditorWidgetFactory.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+namespace Swift {
+
+ class BlockListEditorWidget;
+
+ class BlockListEditorWidgetFactory {
+ public:
+ virtual ~BlockListEditorWidgetFactory() {}
+
+ virtual BlockListEditorWidget* createBlockListEditorWidget() = 0;
+ };
+
+}
diff --git a/Swift/Controllers/UIInterfaces/ChatListWindow.h b/Swift/Controllers/UIInterfaces/ChatListWindow.h
index cb55bb3..b189e72 100644
--- a/Swift/Controllers/UIInterfaces/ChatListWindow.h
+++ b/Swift/Controllers/UIInterfaces/ChatListWindow.h
@@ -7,11 +7,13 @@
#pragma once
#include <list>
+#include <set>
+#include <map>
#include <boost/shared_ptr.hpp>
#include <Swiften/MUC/MUCBookmark.h>
#include <Swiften/Elements/StatusShow.h>
#include <boost/filesystem/path.hpp>
-
+#include <Swiften/Base/foreach.h>
#include <Swiften/Base/boost_bsignals.h>
namespace Swift {
@@ -19,13 +21,14 @@ namespace Swift {
public:
class Chat {
public:
+ Chat() : statusType(StatusShow::None), isMUC(false), unreadCount(0) {}
Chat(const JID& jid, const std::string& chatName, const std::string& activity, int unreadCount, StatusShow::Type statusType, const boost::filesystem::path& avatarPath, bool isMUC, const std::string& nick = "")
: jid(jid), chatName(chatName), activity(activity), statusType(statusType), isMUC(isMUC), nick(nick), unreadCount(unreadCount), avatarPath(avatarPath) {}
/** Assume that nicks and other transient features aren't important for equality */
bool operator==(const Chat& other) const {
return jid.toBare() == other.jid.toBare()
&& isMUC == other.isMUC;
- };
+ }
void setUnreadCount(int unread) {
unreadCount = unread;
}
@@ -35,6 +38,18 @@ namespace Swift {
void setAvatarPath(const boost::filesystem::path& path) {
avatarPath = path;
}
+ std::string getImpromptuTitle() const {
+ typedef std::pair<std::string, JID> StringJIDPair;
+ std::string title;
+ foreach(StringJIDPair pair, impromptuJIDs) {
+ if (title.empty()) {
+ title += pair.first;
+ } else {
+ title += ", " + pair.first;
+ }
+ }
+ return title;
+ }
JID jid;
std::string chatName;
std::string activity;
@@ -43,6 +58,7 @@ namespace Swift {
std::string nick;
int unreadCount;
boost::filesystem::path avatarPath;
+ std::map<std::string, JID> impromptuJIDs;
};
virtual ~ChatListWindow();
diff --git a/Swift/Controllers/UIInterfaces/ChatWindow.h b/Swift/Controllers/UIInterfaces/ChatWindow.h
index 5db1a54..e6f61ca 100644
--- a/Swift/Controllers/UIInterfaces/ChatWindow.h
+++ b/Swift/Controllers/UIInterfaces/ChatWindow.h
@@ -6,17 +6,20 @@
#pragma once
+#include <vector>
+#include <string>
+
#include <boost/optional.hpp>
-#include <Swiften/Base/boost_bsignals.h>
#include <boost/shared_ptr.hpp>
+#include <boost/make_shared.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
-#include <vector>
-#include <string>
+#include <Swiften/Base/boost_bsignals.h>
#include <Swiften/Elements/SecurityLabelsCatalog.h>
#include <Swiften/Elements/ChatState.h>
#include <Swiften/Elements/Form.h>
#include <Swiften/Elements/MUCOccupant.h>
+#include <Swift/Controllers/HighlightManager.h>
namespace Swift {
@@ -27,39 +30,93 @@ namespace Swift {
class RosterItem;
class ContactRosterItem;
class FileTransferController;
- class InviteToChatWindow;
+ class UserSearchWindow;
+
class ChatWindow {
public:
+ class ChatMessagePart {
+ public:
+ virtual ~ChatMessagePart() {}
+ };
+
+ class ChatMessage {
+ public:
+ ChatMessage() {}
+ ChatMessage(const std::string& text) {
+ append(boost::make_shared<ChatTextMessagePart>(text));
+ }
+ void append(const boost::shared_ptr<ChatMessagePart>& part) {
+ parts_.push_back(part);
+ }
+
+ const std::vector<boost::shared_ptr<ChatMessagePart> >& getParts() const {
+ return parts_;
+ }
+ private:
+ std::vector<boost::shared_ptr<ChatMessagePart> > parts_;
+ };
+
+ class ChatTextMessagePart : public ChatMessagePart {
+ public:
+ ChatTextMessagePart(const std::string& text) : text(text) {}
+ std::string text;
+ };
+
+ class ChatURIMessagePart : public ChatMessagePart {
+ public:
+ ChatURIMessagePart(const std::string& target) : target(target) {}
+ std::string target;
+ };
+
+ class ChatEmoticonMessagePart : public ChatMessagePart {
+ public:
+ std::string imagePath;
+ std::string alternativeText;
+ };
+
+ class ChatHighlightingMessagePart : public ChatMessagePart {
+ public:
+ std::string foregroundColor;
+ std::string backgroundColor;
+ std::string text;
+ };
+
+
enum AckState {Pending, Received, Failed};
enum ReceiptState {ReceiptRequested, ReceiptReceived};
enum Tristate {Yes, No, Maybe};
- enum OccupantAction {Kick, Ban, MakeModerator, MakeParticipant, MakeVisitor, AddContact};
+ enum OccupantAction {Kick, Ban, MakeModerator, MakeParticipant, MakeVisitor, AddContact, ShowProfile};
enum RoomAction {ChangeSubject, Configure, Affiliations, Destroy, Invite};
enum FileTransferState {WaitingForAccept, Negotiating, Transferring, Canceled, Finished, FTFailed};
enum WhiteboardSessionState {WhiteboardAccepted, WhiteboardTerminated, WhiteboardRejected};
+ enum BlockingState {BlockingUnsupported, IsBlocked, IsUnblocked};
+ enum Direction { UnknownDirection, DefaultDirection };
+
ChatWindow() {}
- virtual ~ChatWindow() {};
+ virtual ~ChatWindow() {}
/** Add message to window.
* @return id of added message (for acks).
*/
- virtual std::string addMessage(const std::string& message, const std::string& senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time) = 0;
+ virtual std::string addMessage(const ChatMessage& message, const std::string& senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time, const HighlightAction& highlight) = 0;
/** Adds action to window.
* @return id of added message (for acks);
*/
- virtual std::string addAction(const std::string& message, const std::string& senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time) = 0;
- virtual void addSystemMessage(const std::string& message) = 0;
- virtual void addPresenceMessage(const std::string& message) = 0;
- virtual void addErrorMessage(const std::string& message) = 0;
- virtual void replaceMessage(const std::string& message, const std::string& id, const boost::posix_time::ptime& time) = 0;
- virtual void replaceWithAction(const std::string& message, const std::string& id, const boost::posix_time::ptime& time) = 0;
+ virtual std::string addAction(const ChatMessage& message, const std::string& senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time, const HighlightAction& highlight) = 0;
+
+ virtual void addSystemMessage(const ChatMessage& message, Direction direction) = 0;
+ virtual void addPresenceMessage(const ChatMessage& message, Direction direction) = 0;
+
+ virtual void addErrorMessage(const ChatMessage& message) = 0;
+ virtual void replaceMessage(const ChatMessage& message, const std::string& id, const boost::posix_time::ptime& time, const HighlightAction& highlight) = 0;
+ virtual void replaceWithAction(const ChatMessage& message, const std::string& id, const boost::posix_time::ptime& time, const HighlightAction& highlight) = 0;
// File transfer related stuff
virtual std::string addFileTransfer(const std::string& senderName, bool senderIsSelf, const std::string& filename, const boost::uintmax_t sizeInBytes) = 0;
virtual void setFileTransferProgress(std::string, const int percentageDone) = 0;
virtual void setFileTransferStatus(std::string, const FileTransferState state, const std::string& msg = "") = 0;
- virtual void addMUCInvitation(const std::string& senderName, const JID& jid, const std::string& reason, const std::string& password, bool direct = true) = 0;
+ virtual void addMUCInvitation(const std::string& senderName, const JID& jid, const std::string& reason, const std::string& password, bool direct = true, bool isImpromptu = false, bool isContinuation = false) = 0;
virtual std::string addWhiteboardRequest(bool senderIsSelf) = 0;
virtual void setWhiteboardSessionStatus(std::string id, const ChatWindow::WhiteboardSessionState state) = 0;
@@ -75,19 +132,21 @@ namespace Swift {
virtual void setSecurityLabelsEnabled(bool enabled) = 0;
virtual void setCorrectionEnabled(Tristate enabled) = 0;
virtual void setUnreadMessageCount(int count) = 0;
- virtual void convertToMUC() = 0;
+ virtual void convertToMUC(bool impromptuMUC = false) = 0;
// virtual TreeWidget *getTreeWidget() = 0;
virtual void setSecurityLabelsError() = 0;
virtual SecurityLabelsCatalog::Item getSelectedSecurityLabel() = 0;
virtual void setInputEnabled(bool enabled) = 0;
virtual void setRosterModel(Roster* model) = 0;
virtual void setTabComplete(TabComplete* completer) = 0;
- virtual void replaceLastMessage(const std::string& message) = 0;
+ virtual void replaceLastMessage(const ChatMessage& message) = 0;
virtual void setAckState(const std::string& id, AckState state) = 0;
virtual void flash() = 0;
virtual void setSubject(const std::string& subject) = 0;
virtual void setAffiliations(MUCOccupant::Affiliation, const std::vector<JID>&) = 0;
virtual void setAvailableRoomActions(const std::vector<RoomAction> &actions) = 0;
+ virtual void setBlockingState(BlockingState state) = 0;
+ virtual void setCanInitiateImpromptuChats(bool supportsImpromptu) = 0;
/**
* Set an alert on the window.
* @param alertText Description of alert (required).
@@ -110,8 +169,6 @@ namespace Swift {
*/
virtual void showRoomConfigurationForm(Form::ref) = 0;
- virtual InviteToChatWindow* createInviteToChatWindow() = 0;
-
boost::signal<void ()> onClosed;
boost::signal<void ()> onAllMessagesRead;
boost::signal<void (const std::string&, bool isCorrection)> onSendMessageRequest;
@@ -124,7 +181,7 @@ namespace Swift {
boost::signal<void (const std::string&)> onChangeSubjectRequest;
boost::signal<void (Form::ref)> onConfigureRequest;
boost::signal<void ()> onDestroyRequest;
- boost::signal<void ()> onInvitePersonToThisMUCRequest;
+ boost::signal<void (const std::vector<JID>&)> onInviteToChat;
boost::signal<void ()> onConfigurationFormCancelled;
boost::signal<void ()> onGetAffiliationsRequest;
boost::signal<void (MUCOccupant::Affiliation, const JID&)> onSetAffiliationRequest;
@@ -141,6 +198,10 @@ namespace Swift {
boost::signal<void ()> onWhiteboardSessionAccept;
boost::signal<void ()> onWhiteboardSessionCancel;
boost::signal<void ()> onWhiteboardWindowShow;
+
+ // Blocking Command related
+ boost::signal<void ()> onBlockUserRequest;
+ boost::signal<void ()> onUnblockUserRequest;
};
}
diff --git a/Swift/Controllers/UIInterfaces/ChatWindowFactory.h b/Swift/Controllers/UIInterfaces/ChatWindowFactory.h
index b7b4479..62e6621 100644
--- a/Swift/Controllers/UIInterfaces/ChatWindowFactory.h
+++ b/Swift/Controllers/UIInterfaces/ChatWindowFactory.h
@@ -14,7 +14,7 @@ namespace Swift {
class UIEventStream;
class ChatWindowFactory {
public:
- virtual ~ChatWindowFactory() {};
+ virtual ~ChatWindowFactory() {}
/**
* Transfers ownership of result.
*/
diff --git a/Swift/Controllers/UIInterfaces/ContactEditWindowFactory.h b/Swift/Controllers/UIInterfaces/ContactEditWindowFactory.h
index 8ad56c0..9d47aef 100644
--- a/Swift/Controllers/UIInterfaces/ContactEditWindowFactory.h
+++ b/Swift/Controllers/UIInterfaces/ContactEditWindowFactory.h
@@ -11,7 +11,7 @@
namespace Swift {
class ContactEditWindowFactory {
public:
- virtual ~ContactEditWindowFactory() {};
+ virtual ~ContactEditWindowFactory() {}
virtual ContactEditWindow* createContactEditWindow() = 0;
};
diff --git a/Swift/Controllers/UIInterfaces/EventWindow.h b/Swift/Controllers/UIInterfaces/EventWindow.h
index 3ca2c82..b3af3d3 100644
--- a/Swift/Controllers/UIInterfaces/EventWindow.h
+++ b/Swift/Controllers/UIInterfaces/EventWindow.h
@@ -19,7 +19,7 @@ namespace Swift {
return canDelete_;
}
- virtual ~EventWindow() {};
+ virtual ~EventWindow() {}
virtual void addEvent(boost::shared_ptr<StanzaEvent> event, bool active) = 0;
virtual void removeEvent(boost::shared_ptr<StanzaEvent> event) = 0;
diff --git a/Swift/Controllers/UIInterfaces/EventWindowFactory.h b/Swift/Controllers/UIInterfaces/EventWindowFactory.h
index 1ff3ada..0b9c28e 100644
--- a/Swift/Controllers/UIInterfaces/EventWindowFactory.h
+++ b/Swift/Controllers/UIInterfaces/EventWindowFactory.h
@@ -11,7 +11,7 @@ namespace Swift {
class EventWindowFactory {
public:
- virtual ~EventWindowFactory() {};
+ virtual ~EventWindowFactory() {}
/**
* Transfers ownership of result.
*/
diff --git a/Swift/Controllers/UIInterfaces/HighlightEditorWidget.h b/Swift/Controllers/UIInterfaces/HighlightEditorWidget.h
new file mode 100644
index 0000000..4745035
--- /dev/null
+++ b/Swift/Controllers/UIInterfaces/HighlightEditorWidget.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2012 Maciej Niedzielski
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+namespace Swift {
+
+ class HighlightManager;
+
+ class HighlightEditorWidget {
+ public:
+ virtual ~HighlightEditorWidget() {}
+
+ virtual void show() = 0;
+
+ virtual void setHighlightManager(HighlightManager* highlightManager) = 0;
+ };
+
+}
diff --git a/Swift/Controllers/UIInterfaces/HighlightEditorWidgetFactory.h b/Swift/Controllers/UIInterfaces/HighlightEditorWidgetFactory.h
new file mode 100644
index 0000000..ade575b
--- /dev/null
+++ b/Swift/Controllers/UIInterfaces/HighlightEditorWidgetFactory.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2012 Maciej Niedzielski
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+namespace Swift {
+
+ class HighlightEditorWidget;
+
+ class HighlightEditorWidgetFactory {
+ public:
+ virtual ~HighlightEditorWidgetFactory() {}
+
+ virtual HighlightEditorWidget* createHighlightEditorWidget() = 0;
+ };
+
+}
diff --git a/Swift/Controllers/UIInterfaces/HistoryWindow.h b/Swift/Controllers/UIInterfaces/HistoryWindow.h
index ffb0ad5..6d50f4b 100644
--- a/Swift/Controllers/UIInterfaces/HistoryWindow.h
+++ b/Swift/Controllers/UIInterfaces/HistoryWindow.h
@@ -11,7 +11,7 @@
namespace Swift {
class HistoryWindow {
public:
- virtual ~HistoryWindow() {};
+ virtual ~HistoryWindow() {}
virtual void activate() = 0;
virtual void setRosterModel(Roster*) = 0;
diff --git a/Swift/Controllers/UIInterfaces/HistoryWindowFactory.h b/Swift/Controllers/UIInterfaces/HistoryWindowFactory.h
index e91bc37..807fec5 100644
--- a/Swift/Controllers/UIInterfaces/HistoryWindowFactory.h
+++ b/Swift/Controllers/UIInterfaces/HistoryWindowFactory.h
@@ -12,7 +12,7 @@ namespace Swift {
class UIEventStream;
class HistoryWindowFactory {
public:
- virtual ~HistoryWindowFactory() {};
+ virtual ~HistoryWindowFactory() {}
virtual HistoryWindow* createHistoryWindow(UIEventStream* eventStream) = 0;
};
}
diff --git a/Swift/Controllers/UIInterfaces/InviteToChatWindow.h b/Swift/Controllers/UIInterfaces/InviteToChatWindow.h
deleted file mode 100644
index 4070e01..0000000
--- a/Swift/Controllers/UIInterfaces/InviteToChatWindow.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (c) 2012 Kevin Smith
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
- */
-
-#pragma once
-
-#include <vector>
-#include <utility>
-#include <string>
-#include <Swiften/Base/boost_bsignals.h>
-#include <Swiften/JID/JID.h>
-
-namespace Swift {
- class InviteToChatWindow {
- public:
- virtual ~InviteToChatWindow() {};
-
- virtual void setAutoCompletions(std::vector<std::pair<JID, std::string> > completions) = 0;
-
- virtual std::string getReason() const = 0;
-
- virtual std::vector<JID> getJIDs() const = 0;
-
- boost::signal<void ()> onCompleted;
- boost::signal<void ()> onDismissed;
- };
-}
-
diff --git a/Swift/Controllers/UIInterfaces/JoinMUCWindow.h b/Swift/Controllers/UIInterfaces/JoinMUCWindow.h
index 4873c9b..56a9587 100644
--- a/Swift/Controllers/UIInterfaces/JoinMUCWindow.h
+++ b/Swift/Controllers/UIInterfaces/JoinMUCWindow.h
@@ -15,7 +15,7 @@
namespace Swift {
class JoinMUCWindow {
public:
- virtual ~JoinMUCWindow() {};
+ virtual ~JoinMUCWindow() {}
virtual void setNick(const std::string& nick) = 0;
virtual void setMUC(const std::string& nick) = 0;
diff --git a/Swift/Controllers/UIInterfaces/JoinMUCWindowFactory.h b/Swift/Controllers/UIInterfaces/JoinMUCWindowFactory.h
index cd8021b..494b418 100644
--- a/Swift/Controllers/UIInterfaces/JoinMUCWindowFactory.h
+++ b/Swift/Controllers/UIInterfaces/JoinMUCWindowFactory.h
@@ -12,7 +12,7 @@ namespace Swift {
class UIEventStream;
class JoinMUCWindowFactory {
public:
- virtual ~JoinMUCWindowFactory() {};
+ virtual ~JoinMUCWindowFactory() {}
virtual JoinMUCWindow* createJoinMUCWindow(UIEventStream* uiEventStream) = 0;
};
diff --git a/Swift/Controllers/UIInterfaces/LoginWindow.h b/Swift/Controllers/UIInterfaces/LoginWindow.h
index dbc77c4..e27c385 100644
--- a/Swift/Controllers/UIInterfaces/LoginWindow.h
+++ b/Swift/Controllers/UIInterfaces/LoginWindow.h
@@ -18,7 +18,7 @@ namespace Swift {
class MainWindow;
class LoginWindow {
public:
- virtual ~LoginWindow() {};
+ virtual ~LoginWindow() {}
virtual void selectUser(const std::string&) = 0;
virtual void morphInto(MainWindow *mainWindow) = 0;
virtual void loggedOut() = 0;
diff --git a/Swift/Controllers/UIInterfaces/LoginWindowFactory.h b/Swift/Controllers/UIInterfaces/LoginWindowFactory.h
index 1cead2a..7b8b7ec 100644
--- a/Swift/Controllers/UIInterfaces/LoginWindowFactory.h
+++ b/Swift/Controllers/UIInterfaces/LoginWindowFactory.h
@@ -16,7 +16,7 @@ namespace Swift {
class LoginWindowFactory {
public:
- virtual ~LoginWindowFactory() {};
+ virtual ~LoginWindowFactory() {}
/**
* Transfers ownership of result.
diff --git a/Swift/Controllers/UIInterfaces/MUCSearchWindow.h b/Swift/Controllers/UIInterfaces/MUCSearchWindow.h
index 5814b06..43a61a1 100644
--- a/Swift/Controllers/UIInterfaces/MUCSearchWindow.h
+++ b/Swift/Controllers/UIInterfaces/MUCSearchWindow.h
@@ -19,7 +19,7 @@ namespace Swift {
class MUCSearchWindow {
public:
- virtual ~MUCSearchWindow() {};
+ virtual ~MUCSearchWindow() {}
virtual void clearList() = 0;
virtual void addService(const MUCService& service) = 0;
diff --git a/Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h b/Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h
index d334dff..46488eb 100644
--- a/Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h
+++ b/Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h
@@ -12,7 +12,7 @@ namespace Swift {
class UIEventStream;
class MUCSearchWindowFactory {
public:
- virtual ~MUCSearchWindowFactory() {};
+ virtual ~MUCSearchWindowFactory() {}
virtual MUCSearchWindow* createMUCSearchWindow() = 0;
};
diff --git a/Swift/Controllers/UIInterfaces/MainWindow.h b/Swift/Controllers/UIInterfaces/MainWindow.h
index 23328b4..3b10041 100644
--- a/Swift/Controllers/UIInterfaces/MainWindow.h
+++ b/Swift/Controllers/UIInterfaces/MainWindow.h
@@ -20,7 +20,7 @@ namespace Swift {
class MainWindow {
public:
MainWindow(bool candelete = true) : canDelete_(candelete) {}
- virtual ~MainWindow() {};
+ virtual ~MainWindow() {}
bool canDelete() const {
return canDelete_;
@@ -34,6 +34,7 @@ namespace Swift {
/** Must be able to cope with NULL to clear the roster */
virtual void setRosterModel(Roster* roster) = 0;
virtual void setConnecting() = 0;
+ virtual void setBlockingCommandAvailable(bool isAvailable) = 0;
virtual void setAvailableAdHocCommands(const std::vector<DiscoItems::Item>& commands) = 0;
virtual void setStreamEncryptionStatus(bool tlsInPlaceAndValid) = 0;
virtual void openCertificateDialog(const std::vector<Certificate::ref>& chain) = 0;
diff --git a/Swift/Controllers/UIInterfaces/MainWindowFactory.h b/Swift/Controllers/UIInterfaces/MainWindowFactory.h
index c5cdfef..6bd34b4 100644
--- a/Swift/Controllers/UIInterfaces/MainWindowFactory.h
+++ b/Swift/Controllers/UIInterfaces/MainWindowFactory.h
@@ -15,7 +15,7 @@ namespace Swift {
class MainWindowFactory {
public:
- virtual ~MainWindowFactory() {};
+ virtual ~MainWindowFactory() {}
/**
* Transfers ownership of result.
*/
diff --git a/Swift/Controllers/UIInterfaces/ProfileWindow.h b/Swift/Controllers/UIInterfaces/ProfileWindow.h
index 5d5c754..5c158e1 100644
--- a/Swift/Controllers/UIInterfaces/ProfileWindow.h
+++ b/Swift/Controllers/UIInterfaces/ProfileWindow.h
@@ -12,19 +12,24 @@
#include <Swiften/Elements/VCard.h>
namespace Swift {
+ class JID;
+
class ProfileWindow {
public:
- virtual ~ProfileWindow() {};
+ virtual ~ProfileWindow() {}
+ virtual void setJID(const JID& jid) = 0;
virtual void setVCard(VCard::ref vcard) = 0;
virtual void setEnabled(bool b) = 0;
virtual void setProcessing(bool b) = 0;
virtual void setError(const std::string&) = 0;
+ virtual void setEditable(bool b) = 0;
virtual void show() = 0;
virtual void hide() = 0;
boost::signal<void (VCard::ref)> onVCardChangeRequest;
+ boost::signal<void (const JID&)> onWindowAboutToBeClosed;
};
}
diff --git a/Swift/Controllers/UIInterfaces/ProfileWindowFactory.h b/Swift/Controllers/UIInterfaces/ProfileWindowFactory.h
index 022c3eb..45a340a 100644
--- a/Swift/Controllers/UIInterfaces/ProfileWindowFactory.h
+++ b/Swift/Controllers/UIInterfaces/ProfileWindowFactory.h
@@ -11,7 +11,7 @@
namespace Swift {
class ProfileWindowFactory {
public:
- virtual ~ProfileWindowFactory() {};
+ virtual ~ProfileWindowFactory() {}
virtual ProfileWindow* createProfileWindow() = 0;
};
diff --git a/Swift/Controllers/UIInterfaces/UIFactory.h b/Swift/Controllers/UIInterfaces/UIFactory.h
index 6b4efd8..990dc98 100644
--- a/Swift/Controllers/UIInterfaces/UIFactory.h
+++ b/Swift/Controllers/UIInterfaces/UIFactory.h
@@ -21,6 +21,8 @@
#include <Swift/Controllers/UIInterfaces/AdHocCommandWindowFactory.h>
#include <Swift/Controllers/UIInterfaces/FileTransferListWidgetFactory.h>
#include <Swift/Controllers/UIInterfaces/WhiteboardWindowFactory.h>
+#include <Swift/Controllers/UIInterfaces/HighlightEditorWidgetFactory.h>
+#include <Swift/Controllers/UIInterfaces/BlockListEditorWidgetFactory.h>
namespace Swift {
class UIFactory :
@@ -38,7 +40,9 @@ namespace Swift {
public ContactEditWindowFactory,
public AdHocCommandWindowFactory,
public FileTransferListWidgetFactory,
- public WhiteboardWindowFactory {
+ public WhiteboardWindowFactory,
+ public HighlightEditorWidgetFactory,
+ public BlockListEditorWidgetFactory {
public:
virtual ~UIFactory() {}
};
diff --git a/Swift/Controllers/UIInterfaces/UserSearchWindow.h b/Swift/Controllers/UIInterfaces/UserSearchWindow.h
index a3d69d6..9dd1811 100644
--- a/Swift/Controllers/UIInterfaces/UserSearchWindow.h
+++ b/Swift/Controllers/UIInterfaces/UserSearchWindow.h
@@ -6,19 +6,20 @@
#pragma once
-#include "Swiften/Base/boost_bsignals.h"
+#include <Swiften/Base/boost_bsignals.h>
#include <vector>
#include <string>
-#include "Swiften/JID/JID.h"
-#include "Swift/Controllers/Chat/UserSearchController.h"
+#include <Swiften/JID/JID.h>
+#include <Swift/Controllers/Chat/UserSearchController.h>
+#include <Swift/Controllers/Contact.h>
namespace Swift {
class UserSearchWindow {
public:
- enum Type {AddContact, ChatToContact};
+ enum Type {AddContact, ChatToContact, InviteToChat};
virtual ~UserSearchWindow() {}
virtual void clear() = 0;
@@ -31,10 +32,20 @@ namespace Swift {
virtual void setSearchFields(boost::shared_ptr<SearchPayload> fields) = 0;
virtual void setNameSuggestions(const std::vector<std::string>& suggestions) = 0;
virtual void prepopulateJIDAndName(const JID& jid, const std::string& name) = 0;
+ virtual void setContactSuggestions(const std::vector<Contact>& suggestions) = 0;
+ virtual void setJIDs(const std::vector<JID>&) = 0;
+ virtual void setRoomJID(const JID& roomJID) = 0;
+ virtual std::string getReason() const = 0;
+ virtual std::vector<JID> getJIDs() const = 0;
+ virtual void setCanStartImpromptuChats(bool supportsImpromptu) = 0;
+ virtual void updateContacts(const std::vector<Contact>& contacts) = 0;
+
virtual void show() = 0;
boost::signal<void (const JID&)> onFormRequested;
boost::signal<void (boost::shared_ptr<SearchPayload>, const JID&)> onSearchRequested;
boost::signal<void (const JID&)> onNameSuggestionRequested;
+ boost::signal<void (const std::string&)> onContactSuggestionsRequested;
+ boost::signal<void (const std::vector<JID>&)> onJIDUpdateRequested;
};
}
diff --git a/Swift/Controllers/UIInterfaces/UserSearchWindowFactory.h b/Swift/Controllers/UIInterfaces/UserSearchWindowFactory.h
index 2a15806..331d6dd 100644
--- a/Swift/Controllers/UIInterfaces/UserSearchWindowFactory.h
+++ b/Swift/Controllers/UIInterfaces/UserSearchWindowFactory.h
@@ -14,7 +14,7 @@ namespace Swift {
class UIEventStream;
class UserSearchWindowFactory {
public:
- virtual ~UserSearchWindowFactory() {};
+ virtual ~UserSearchWindowFactory() {}
virtual UserSearchWindow* createUserSearchWindow(UserSearchWindow::Type type, UIEventStream* eventStream, const std::set<std::string>& groups) = 0;
};
diff --git a/Swift/Controllers/UIInterfaces/WhiteboardWindowFactory.h b/Swift/Controllers/UIInterfaces/WhiteboardWindowFactory.h
index c2d2f6c..2be0f9c 100644
--- a/Swift/Controllers/UIInterfaces/WhiteboardWindowFactory.h
+++ b/Swift/Controllers/UIInterfaces/WhiteboardWindowFactory.h
@@ -12,7 +12,7 @@ namespace Swift {
class WhiteboardWindowFactory {
public :
- virtual ~WhiteboardWindowFactory() {};
+ virtual ~WhiteboardWindowFactory() {}
virtual WhiteboardWindow* createWhiteboardWindow(boost::shared_ptr<WhiteboardSession> whiteboardSession) = 0;
};
diff --git a/Swift/Controllers/UIInterfaces/XMLConsoleWidgetFactory.h b/Swift/Controllers/UIInterfaces/XMLConsoleWidgetFactory.h
index e27fe2e..3cba597 100644
--- a/Swift/Controllers/UIInterfaces/XMLConsoleWidgetFactory.h
+++ b/Swift/Controllers/UIInterfaces/XMLConsoleWidgetFactory.h
@@ -12,7 +12,7 @@ namespace Swift {
class UIEventStream;
class XMLConsoleWidgetFactory {
public:
- virtual ~XMLConsoleWidgetFactory() {};
+ virtual ~XMLConsoleWidgetFactory() {}
virtual XMLConsoleWidget* createXMLConsoleWidget() = 0;
};
diff --git a/Swift/Controllers/UnitTest/ChatMessageSummarizerTest.cpp b/Swift/Controllers/UnitTest/ChatMessageSummarizerTest.cpp
index ee0ee9f..dd2a8e5 100644
--- a/Swift/Controllers/UnitTest/ChatMessageSummarizerTest.cpp
+++ b/Swift/Controllers/UnitTest/ChatMessageSummarizerTest.cpp
@@ -26,7 +26,7 @@ class ChatMessageSummarizerTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE_END();
public:
- ChatMessageSummarizerTest() {};
+ ChatMessageSummarizerTest() {}
void setUp() {
@@ -72,7 +72,7 @@ public:
unreads.push_back(UnreadPair("Bob", 3));
unreads.push_back(UnreadPair("Betty", 7));
ChatMessageSummarizer summary;
- CPPUNIT_ASSERT_EQUAL(string("Bob (3), Betty (7)"), summary.getSummary(current, unreads));
+ CPPUNIT_ASSERT_EQUAL(string("Bob (3); Betty (7)"), summary.getSummary(current, unreads));
}
void testCurrentNoneOtherCount() {
@@ -82,7 +82,7 @@ public:
unreads.push_back(UnreadPair("Bob", 0));
unreads.push_back(UnreadPair("Betty", 7));
ChatMessageSummarizer summary;
- CPPUNIT_ASSERT_EQUAL(string("Bob, Betty (7)"), summary.getSummary(current, unreads));
+ CPPUNIT_ASSERT_EQUAL(string("Bob; Betty (7)"), summary.getSummary(current, unreads));
}
void testCurrentNoneOthersCount() {
diff --git a/Swift/Controllers/UnitTest/HighlightRuleTest.cpp b/Swift/Controllers/UnitTest/HighlightRuleTest.cpp
new file mode 100644
index 0000000..ec81227
--- /dev/null
+++ b/Swift/Controllers/UnitTest/HighlightRuleTest.cpp
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2012 Maciej Niedzielski
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <vector>
+#include <string>
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
+#include <Swift/Controllers/HighlightRule.h>
+
+using namespace Swift;
+
+class HighlightRuleTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(HighlightRuleTest);
+ CPPUNIT_TEST(testEmptyRuleNeverMatches);
+ CPPUNIT_TEST(testKeyword);
+ CPPUNIT_TEST(testNickKeyword);
+ CPPUNIT_TEST(testNickWithoutOtherKeywords);
+ CPPUNIT_TEST(testSender);
+ CPPUNIT_TEST(testSenderAndKeyword);
+ CPPUNIT_TEST(testWholeWords);
+ CPPUNIT_TEST(testCase);
+ CPPUNIT_TEST(testWholeWordsAndCase);
+ CPPUNIT_TEST(testMUC);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ void setUp() {
+ std::vector<std::string> keywords;
+ keywords.push_back("keyword1");
+ keywords.push_back("KEYWORD2");
+
+ std::vector<std::string>senders;
+ senders.push_back("sender1");
+ senders.push_back("SENDER2");
+
+ emptyRule = new HighlightRule();
+
+ keywordRule = new HighlightRule();
+ keywordRule->setKeywords(keywords);
+
+ keywordChatRule = new HighlightRule();
+ keywordChatRule->setKeywords(keywords);
+ keywordChatRule->setMatchChat(true);
+
+ keywordNickChatRule = new HighlightRule();
+ keywordNickChatRule->setKeywords(keywords);
+ keywordNickChatRule->setNickIsKeyword(true);
+ keywordNickChatRule->setMatchChat(true);
+
+ nickChatRule = new HighlightRule();
+ nickChatRule->setNickIsKeyword(true);
+ nickChatRule->setMatchChat(true);
+
+ nickRule = new HighlightRule();
+ nickRule->setNickIsKeyword(true);
+
+ senderRule = new HighlightRule();
+ senderRule->setSenders(senders);
+
+ senderChatRule = new HighlightRule();
+ senderChatRule->setSenders(senders);
+ senderChatRule->setMatchChat(true);
+
+ senderKeywordChatRule = new HighlightRule();
+ senderKeywordChatRule->setSenders(senders);
+ senderKeywordChatRule->setKeywords(keywords);
+ senderKeywordChatRule->setMatchChat(true);
+
+ senderKeywordNickChatRule = new HighlightRule();
+ senderKeywordNickChatRule->setSenders(senders);
+ senderKeywordNickChatRule->setKeywords(keywords);
+ senderKeywordNickChatRule->setNickIsKeyword(true);
+ senderKeywordNickChatRule->setMatchChat(true);
+
+ senderKeywordNickWordChatRule = new HighlightRule();
+ senderKeywordNickWordChatRule->setSenders(senders);
+ senderKeywordNickWordChatRule->setKeywords(keywords);
+ senderKeywordNickWordChatRule->setNickIsKeyword(true);
+ senderKeywordNickWordChatRule->setMatchWholeWords(true);
+ senderKeywordNickWordChatRule->setMatchChat(true);
+
+ senderKeywordNickCaseChatRule = new HighlightRule();
+ senderKeywordNickCaseChatRule->setSenders(senders);
+ senderKeywordNickCaseChatRule->setKeywords(keywords);
+ senderKeywordNickCaseChatRule->setNickIsKeyword(true);
+ senderKeywordNickCaseChatRule->setMatchCase(true);
+ senderKeywordNickCaseChatRule->setMatchChat(true);
+
+ senderKeywordNickCaseWordChatRule = new HighlightRule();
+ senderKeywordNickCaseWordChatRule->setSenders(senders);
+ senderKeywordNickCaseWordChatRule->setKeywords(keywords);
+ senderKeywordNickCaseWordChatRule->setNickIsKeyword(true);
+ senderKeywordNickCaseWordChatRule->setMatchCase(true);
+ senderKeywordNickCaseWordChatRule->setMatchWholeWords(true);
+ senderKeywordNickCaseWordChatRule->setMatchChat(true);
+
+ senderKeywordNickMUCRule = new HighlightRule();
+ senderKeywordNickMUCRule->setSenders(senders);
+ senderKeywordNickMUCRule->setKeywords(keywords);
+ senderKeywordNickMUCRule->setNickIsKeyword(true);
+ senderKeywordNickMUCRule->setMatchMUC(true);
+ }
+
+ void tearDown() {
+ delete emptyRule;
+
+ delete keywordRule;
+ delete keywordChatRule;
+ delete keywordNickChatRule;
+ delete nickChatRule;
+ delete nickRule;
+
+ delete senderRule;
+ delete senderChatRule;
+ delete senderKeywordChatRule;
+ delete senderKeywordNickChatRule;
+
+ delete senderKeywordNickWordChatRule;
+ delete senderKeywordNickCaseChatRule;
+ delete senderKeywordNickCaseWordChatRule;
+
+ delete senderKeywordNickMUCRule;
+ }
+
+ void testEmptyRuleNeverMatches() {
+ CPPUNIT_ASSERT_EQUAL(emptyRule->isMatch("body", "from", "nick", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(emptyRule->isMatch("body", "from", "nick", HighlightRule::MUCMessage), false);
+
+ CPPUNIT_ASSERT_EQUAL(emptyRule->isMatch("body", "from", "", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(emptyRule->isMatch("body", "from", "", HighlightRule::MUCMessage), false);
+
+ CPPUNIT_ASSERT_EQUAL(emptyRule->isMatch("body", "", "nick", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(emptyRule->isMatch("body", "", "nick", HighlightRule::MUCMessage), false);
+
+ CPPUNIT_ASSERT_EQUAL(emptyRule->isMatch("", "from", "nick", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(emptyRule->isMatch("", "from", "nick", HighlightRule::MUCMessage), false);
+
+ CPPUNIT_ASSERT_EQUAL(emptyRule->isMatch("body", "", "", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(emptyRule->isMatch("body", "", "", HighlightRule::MUCMessage), false);
+
+ CPPUNIT_ASSERT_EQUAL(emptyRule->isMatch("", "from", "", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(emptyRule->isMatch("", "from", "", HighlightRule::MUCMessage), false);
+
+ CPPUNIT_ASSERT_EQUAL(emptyRule->isMatch("", "", "nick", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(emptyRule->isMatch("", "", "nick", HighlightRule::MUCMessage), false);
+
+ CPPUNIT_ASSERT_EQUAL(emptyRule->isMatch("", "", "", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(emptyRule->isMatch("", "", "", HighlightRule::MUCMessage), false);
+ }
+
+ void testKeyword() {
+ CPPUNIT_ASSERT_EQUAL(keywordChatRule->isMatch("body", "from", "nick", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(keywordChatRule->isMatch("body", "from", "nick", HighlightRule::MUCMessage), false);
+
+ CPPUNIT_ASSERT_EQUAL(keywordChatRule->isMatch("keyword1", "from", "nick", HighlightRule::ChatMessage), true);
+ CPPUNIT_ASSERT_EQUAL(keywordChatRule->isMatch("keyword1", "from", "nick", HighlightRule::MUCMessage), false);
+ CPPUNIT_ASSERT_EQUAL(keywordRule->isMatch("keyword1", "from", "nick", HighlightRule::ChatMessage), false);
+
+ CPPUNIT_ASSERT_EQUAL(keywordChatRule->isMatch("body", "sender contains keyword1", "nick", HighlightRule::ChatMessage), false);
+
+ CPPUNIT_ASSERT_EQUAL(keywordChatRule->isMatch("abc keyword1 xyz", "from", "nick", HighlightRule::ChatMessage), true);
+ CPPUNIT_ASSERT_EQUAL(keywordChatRule->isMatch("abckeyword1xyz", "from", "nick", HighlightRule::ChatMessage), true);
+
+ CPPUNIT_ASSERT_EQUAL(keywordChatRule->isMatch("KEYword1", "from", "nick", HighlightRule::ChatMessage), true);
+ CPPUNIT_ASSERT_EQUAL(keywordChatRule->isMatch("abc KEYword1 xyz", "from", "nick", HighlightRule::ChatMessage), true);
+ CPPUNIT_ASSERT_EQUAL(keywordChatRule->isMatch("abcKEYword1xyz", "from", "nick", HighlightRule::ChatMessage), true);
+
+ CPPUNIT_ASSERT_EQUAL(keywordChatRule->isMatch("keyword2", "from", "nick", HighlightRule::ChatMessage), true);
+ }
+
+ void testNickKeyword() {
+ CPPUNIT_ASSERT_EQUAL(keywordNickChatRule->isMatch("body contains nick", "from", "nick", HighlightRule::ChatMessage), true);
+ CPPUNIT_ASSERT_EQUAL(keywordNickChatRule->isMatch("body contains nick", "from", "nick", HighlightRule::MUCMessage), false);
+ CPPUNIT_ASSERT_EQUAL(keywordChatRule->isMatch("body contains nick", "from", "nick", HighlightRule::ChatMessage), false);
+
+ CPPUNIT_ASSERT_EQUAL(keywordNickChatRule->isMatch("keyword1", "from", "nick", HighlightRule::ChatMessage), true);
+
+ CPPUNIT_ASSERT_EQUAL(keywordNickChatRule->isMatch("body", "sender contains nick", "nick", HighlightRule::ChatMessage), false);
+
+ CPPUNIT_ASSERT_EQUAL(keywordNickChatRule->isMatch("body contains mixed-case NiCk", "sender", "nick", HighlightRule::ChatMessage), true);
+
+ CPPUNIT_ASSERT_EQUAL(keywordNickChatRule->isMatch("nickname", "from", "nick", HighlightRule::ChatMessage), true);
+ CPPUNIT_ASSERT_EQUAL(keywordNickChatRule->isMatch("NIckNAME", "from", "nick", HighlightRule::ChatMessage), true);
+
+ CPPUNIT_ASSERT_EQUAL(keywordNickChatRule->isMatch("body", "from", "", HighlightRule::ChatMessage), false);
+ }
+
+ void testNickWithoutOtherKeywords() {
+ CPPUNIT_ASSERT_EQUAL(nickChatRule->isMatch("body contains nick", "from", "nick", HighlightRule::ChatMessage), true);
+ CPPUNIT_ASSERT_EQUAL(nickChatRule->isMatch("body contains nick", "from", "nick", HighlightRule::MUCMessage), false);
+ CPPUNIT_ASSERT_EQUAL(nickRule->isMatch("body contains nick", "from", "nick", HighlightRule::ChatMessage), false);
+
+ CPPUNIT_ASSERT_EQUAL(nickChatRule->isMatch("keyword1", "from", "nick", HighlightRule::ChatMessage), false);
+
+ CPPUNIT_ASSERT_EQUAL(nickChatRule->isMatch("body", "sender contains nick but it does't matter", "nick", HighlightRule::ChatMessage), false);
+
+ CPPUNIT_ASSERT_EQUAL(nickChatRule->isMatch("body contains mixed-case NiCk", "from", "nick", HighlightRule::ChatMessage), true);
+
+ CPPUNIT_ASSERT_EQUAL(nickChatRule->isMatch("nickname", "from", "nick", HighlightRule::ChatMessage), true);
+ CPPUNIT_ASSERT_EQUAL(nickChatRule->isMatch("NIckNAME", "from", "nick", HighlightRule::ChatMessage), true);
+
+ // there are no keywords in this rule and empty nick is not treated as a keyword, so we don't check for keywords to get a match
+ CPPUNIT_ASSERT_EQUAL(nickChatRule->isMatch("body", "from", "", HighlightRule::ChatMessage), true);
+ }
+
+ void testSender() {
+ CPPUNIT_ASSERT_EQUAL(senderChatRule->isMatch("body", "from", "nick", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(senderChatRule->isMatch("body", "from", "nick", HighlightRule::MUCMessage), false);
+
+ CPPUNIT_ASSERT_EQUAL(senderChatRule->isMatch("body", "sender1", "nick", HighlightRule::ChatMessage), true);
+ CPPUNIT_ASSERT_EQUAL(senderChatRule->isMatch("body", "sender1", "nick", HighlightRule::MUCMessage), false);
+ CPPUNIT_ASSERT_EQUAL(senderRule->isMatch("body", "sender1", "nick", HighlightRule::ChatMessage), false);
+
+ CPPUNIT_ASSERT_EQUAL(senderRule->isMatch("body contains sender1", "from", "nick", HighlightRule::ChatMessage), false);
+
+ CPPUNIT_ASSERT_EQUAL(senderChatRule->isMatch("body", "abc sender1 xyz", "nick", HighlightRule::ChatMessage), true);
+ CPPUNIT_ASSERT_EQUAL(senderChatRule->isMatch("body", "abcsender1xyz", "nick", HighlightRule::ChatMessage), true);
+
+ CPPUNIT_ASSERT_EQUAL(senderChatRule->isMatch("body", "SENDer1", "nick", HighlightRule::ChatMessage), true);
+ CPPUNIT_ASSERT_EQUAL(senderChatRule->isMatch("body", "abc SENDer1 xyz", "nick", HighlightRule::ChatMessage), true);
+ CPPUNIT_ASSERT_EQUAL(senderChatRule->isMatch("body", "abcSENDer1xyz", "nick", HighlightRule::ChatMessage), true);
+
+ CPPUNIT_ASSERT_EQUAL(senderChatRule->isMatch("body", "sender2", "nick", HighlightRule::ChatMessage), true);
+ }
+
+ void testSenderAndKeyword() {
+ CPPUNIT_ASSERT_EQUAL(senderKeywordChatRule->isMatch("body", "from", "nick", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordChatRule->isMatch("keyword1", "from", "nick", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordChatRule->isMatch("body", "sender1", "nick", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordChatRule->isMatch("keyword1", "sender1", "nick", HighlightRule::ChatMessage), true);
+ }
+
+ void testWholeWords() {
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickWordChatRule->isMatch("body", "from", "nick", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickWordChatRule->isMatch("keyword1", "from", "nick", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickWordChatRule->isMatch("body", "sender1", "nick", HighlightRule::ChatMessage), false);
+
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickWordChatRule->isMatch("keyword1", "sender1", "nick", HighlightRule::ChatMessage), true);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickWordChatRule->isMatch("xkeyword1", "sender1", "nick", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickWordChatRule->isMatch("keyword1", "xsender1", "nick", HighlightRule::ChatMessage), false);
+
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickWordChatRule->isMatch("body contains nick", "sender1", "nick", HighlightRule::ChatMessage), true);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickWordChatRule->isMatch("body contains xnick", "sender1", "nick", HighlightRule::ChatMessage), false);
+
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickWordChatRule->isMatch("KEYword1", "SENDer1", "nick", HighlightRule::ChatMessage), true);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickWordChatRule->isMatch("body contains NiCk", "sender1", "nick", HighlightRule::ChatMessage), true);
+ }
+
+ void testCase() {
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseChatRule->isMatch("body", "from", "nick", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseChatRule->isMatch("keyword1", "from", "nick", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseChatRule->isMatch("body", "sender1", "nick", HighlightRule::ChatMessage), false);
+
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseChatRule->isMatch("keyword1", "sender1", "nick", HighlightRule::ChatMessage), true);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseChatRule->isMatch("xkeyword1", "xsender1", "nick", HighlightRule::ChatMessage), true);
+
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseChatRule->isMatch("body contains nick", "sender1", "nick", HighlightRule::ChatMessage), true);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseChatRule->isMatch("body contains xnick", "sender1", "nick", HighlightRule::ChatMessage), true);
+
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseChatRule->isMatch("KEYword1", "SENDer1", "nick", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseChatRule->isMatch("keyword1", "SENDer1", "nick", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseChatRule->isMatch("KEYword1", "sender1", "nick", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseChatRule->isMatch("body contains NiCk", "sender1", "nick", HighlightRule::ChatMessage), false);
+ }
+
+ void testWholeWordsAndCase() {
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseWordChatRule->isMatch("body", "from", "nick", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseWordChatRule->isMatch("keyword1", "from", "nick", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseWordChatRule->isMatch("body", "sender1", "nick", HighlightRule::ChatMessage), false);
+
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseWordChatRule->isMatch("keyword1", "sender1", "nick", HighlightRule::ChatMessage), true);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseWordChatRule->isMatch("xkeyword1", "sender1", "nick", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseWordChatRule->isMatch("keyword1", "xsender1", "nick", HighlightRule::ChatMessage), false);
+
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseWordChatRule->isMatch("body contains nick", "sender1", "nick", HighlightRule::ChatMessage), true);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseWordChatRule->isMatch("body contains xnick", "sender1", "nick", HighlightRule::ChatMessage), false);
+
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseWordChatRule->isMatch("KEYword1", "SENDer1", "nick", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseWordChatRule->isMatch("keyword1", "SENDer1", "nick", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseWordChatRule->isMatch("KEYword1", "sender1", "nick", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseWordChatRule->isMatch("body contains NiCk", "sender1", "nick", HighlightRule::ChatMessage), false);
+ }
+
+ void testMUC() {
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickMUCRule->isMatch("body", "from", "nick", HighlightRule::ChatMessage), false);
+
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickMUCRule->isMatch("keyword1", "sender1", "nick", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickMUCRule->isMatch("keyword1", "sender1", "nick", HighlightRule::MUCMessage), true);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickMUCRule->isMatch("body contains nick", "sender1", "nick", HighlightRule::MUCMessage), true);
+ }
+
+ private:
+ HighlightRule* emptyRule;
+
+ HighlightRule* keywordRule;
+ HighlightRule* keywordChatRule;
+ HighlightRule* keywordNickChatRule;
+ HighlightRule* nickChatRule;
+ HighlightRule* nickRule;
+
+ HighlightRule* senderRule;
+ HighlightRule* senderChatRule;
+ HighlightRule* senderKeywordChatRule;
+ HighlightRule* senderKeywordNickChatRule;
+
+ HighlightRule* senderKeywordNickWordChatRule;
+ HighlightRule* senderKeywordNickCaseChatRule;
+ HighlightRule* senderKeywordNickCaseWordChatRule;
+
+ HighlightRule* senderKeywordNickMUCRule;
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(HighlightRuleTest);
diff --git a/Swift/Controllers/UnitTest/MockChatWindow.h b/Swift/Controllers/UnitTest/MockChatWindow.h
index 998a4eb..43779c5 100644
--- a/Swift/Controllers/UnitTest/MockChatWindow.h
+++ b/Swift/Controllers/UnitTest/MockChatWindow.h
@@ -6,59 +6,80 @@
#pragma once
-#include "Swift/Controllers/UIInterfaces/ChatWindow.h"
+#include <boost/shared_ptr.hpp>
+
+#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
+#include <Swiften/Base/foreach.h>
+
namespace Swift {
class MockChatWindow : public ChatWindow {
public:
- MockChatWindow() : labelsEnabled_(false) {};
+ MockChatWindow() : labelsEnabled_(false) {}
virtual ~MockChatWindow();
- virtual std::string addMessage(const std::string& message, const std::string& /*senderName*/, bool /*senderIsSelf*/, boost::shared_ptr<SecurityLabel> /*label*/, const std::string& /*avatarPath*/, const boost::posix_time::ptime&) {lastMessageBody_ = message; return "";};
- virtual std::string addAction(const std::string& message, const std::string& /*senderName*/, bool /*senderIsSelf*/, boost::shared_ptr<SecurityLabel> /*label*/, const std::string& /*avatarPath*/, const boost::posix_time::ptime&) {lastMessageBody_ = message; return "";};
- virtual void addSystemMessage(const std::string& /*message*/) {};
- virtual void addErrorMessage(const std::string& /*message*/) {};
- virtual void addPresenceMessage(const std::string& /*message*/) {};
+ virtual std::string addMessage(const ChatMessage& message, const std::string& /*senderName*/, bool /*senderIsSelf*/, boost::shared_ptr<SecurityLabel> /*label*/, const std::string& /*avatarPath*/, const boost::posix_time::ptime& /*time*/, const HighlightAction& /*highlight*/) {
+ lastMessageBody_ = bodyFromMessage(message); return "id";}
+
+ virtual std::string addAction(const ChatMessage& /*message*/, const std::string& /*senderName*/, bool /*senderIsSelf*/, boost::shared_ptr<SecurityLabel> /*label*/, const std::string& /*avatarPath*/, const boost::posix_time::ptime& /*time*/, const HighlightAction& /*highlight*/) {return "id";}
+
+ virtual void addSystemMessage(const ChatMessage& /*message*/, Direction /*direction*/) {}
+ virtual void addPresenceMessage(const ChatMessage& /*message*/, Direction /*direction*/) {}
+
+ virtual void addErrorMessage(const ChatMessage& /*message*/) {}
+ virtual void replaceMessage(const ChatMessage& /*message*/, const std::string& /*id*/, const boost::posix_time::ptime& /*time*/, const HighlightAction& /*highlight*/) {}
+ virtual void replaceWithAction(const ChatMessage& /*message*/, const std::string& /*id*/, const boost::posix_time::ptime& /*time*/, const HighlightAction& /*highlight*/) {}
+ virtual void replaceLastMessage(const ChatMessage& /*message*/) {}
// File transfer related stuff
- virtual std::string addFileTransfer(const std::string& /*senderName*/, bool /*senderIsSelf*/,const std::string& /*filename*/, const boost::uintmax_t /*sizeInBytes*/) { return 0; };
- virtual void setFileTransferProgress(std::string /*id*/, const int /*alreadyTransferedBytes*/) { };
- virtual void setFileTransferStatus(std::string /*id*/, const FileTransferState /*state*/, const std::string& /*msg*/) { };
+ virtual std::string addFileTransfer(const std::string& /*senderName*/, bool /*senderIsSelf*/,const std::string& /*filename*/, const boost::uintmax_t /*sizeInBytes*/) { return 0; }
+ virtual void setFileTransferProgress(std::string /*id*/, const int /*alreadyTransferedBytes*/) { }
+ virtual void setFileTransferStatus(std::string /*id*/, const FileTransferState /*state*/, const std::string& /*msg*/) { }
virtual void setMessageReceiptState(const std::string &/* id */, ReceiptState /* state */) { }
- virtual void setContactChatState(ChatState::ChatStateType /*state*/) {};
- virtual void setName(const std::string& name) {name_ = name;};
- virtual void show() {};
- virtual void activate() {};
- virtual void setAvailableSecurityLabels(const std::vector<SecurityLabelsCatalog::Item>& labels) {labels_ = labels;};
- virtual void setSecurityLabelsEnabled(bool enabled) {labelsEnabled_ = enabled;};
- virtual void setUnreadMessageCount(int /*count*/) {};
- virtual void convertToMUC() {};
- virtual void setSecurityLabelsError() {};
+ virtual void setContactChatState(ChatState::ChatStateType /*state*/) {}
+ virtual void setName(const std::string& name) {name_ = name;}
+ virtual void show() {}
+ virtual void activate() {}
+ virtual void setAvailableSecurityLabels(const std::vector<SecurityLabelsCatalog::Item>& labels) {labels_ = labels;}
+ virtual void setSecurityLabelsEnabled(bool enabled) {labelsEnabled_ = enabled;}
+ virtual void setUnreadMessageCount(int /*count*/) {}
+ virtual void convertToMUC(bool /*impromptuMUC*/) {}
+ virtual void setSecurityLabelsError() {}
virtual SecurityLabelsCatalog::Item getSelectedSecurityLabel() {return label_;}
- virtual void setInputEnabled(bool /*enabled*/) {};
- virtual void setRosterModel(Roster* /*roster*/) {};
- virtual void setTabComplete(TabComplete*) {};
- virtual void replaceLastMessage(const std::string&) {};
- virtual void replaceMessage(const std::string&, const std::string&, const boost::posix_time::ptime&) {};
- virtual void replaceWithAction(const std::string& /*message*/, const std::string& /*id*/, const boost::posix_time::ptime& /*time*/) {};
- void setAckState(const std::string& /*id*/, AckState /*state*/) {};
- virtual void flash() {};
- virtual void setAlert(const std::string& /*alertText*/, const std::string& /*buttonText*/) {};
- virtual void cancelAlert() {};
+ virtual void setInputEnabled(bool /*enabled*/) {}
+ virtual void setRosterModel(Roster* /*roster*/) {}
+ virtual void setTabComplete(TabComplete*) {}
+
+ void setAckState(const std::string& /*id*/, AckState /*state*/) {}
+ virtual void flash() {}
+ virtual void setAlert(const std::string& /*alertText*/, const std::string& /*buttonText*/) {}
+ virtual void cancelAlert() {}
virtual void setCorrectionEnabled(Tristate /*enabled*/) {}
void setAvailableOccupantActions(const std::vector<OccupantAction>&/* actions*/) {}
void setSubject(const std::string& /*subject*/) {}
virtual void showRoomConfigurationForm(Form::ref) {}
- virtual void addMUCInvitation(const std::string& /*senderName*/, const JID& /*jid*/, const std::string& /*reason*/, const std::string& /*password*/, bool = true) {};
+ virtual void addMUCInvitation(const std::string& /*senderName*/, const JID& /*jid*/, const std::string& /*reason*/, const std::string& /*password*/, bool = true, bool = false, bool = false) {}
- virtual std::string addWhiteboardRequest(bool) {return "";};
- virtual void setWhiteboardSessionStatus(std::string, const ChatWindow::WhiteboardSessionState){};
+ virtual std::string addWhiteboardRequest(bool) {return "";}
+ virtual void setWhiteboardSessionStatus(std::string, const ChatWindow::WhiteboardSessionState){}
virtual void setAffiliations(MUCOccupant::Affiliation, const std::vector<JID>&) {}
- virtual void setAvailableRoomActions(const std::vector<RoomAction> &) {};
- virtual InviteToChatWindow* createInviteToChatWindow() {return NULL;}
+ virtual void setAvailableRoomActions(const std::vector<RoomAction> &) {}
+
+ virtual void setBlockingState(BlockingState) {}
+ virtual void setCanInitiateImpromptuChats(bool /*supportsImpromptu*/) {}
+
+ std::string bodyFromMessage(const ChatMessage& message) {
+ boost::shared_ptr<ChatTextMessagePart> text;
+ foreach (boost::shared_ptr<ChatMessagePart> part, message.getParts()) {
+ if ((text = boost::dynamic_pointer_cast<ChatTextMessagePart>(part))) {
+ return text->text;
+ }
+ }
+ return "";
+ }
std::string name_;
std::string lastMessageBody_;
diff --git a/Swift/Controllers/UnitTest/MockMainWindow.h b/Swift/Controllers/UnitTest/MockMainWindow.h
index be1a932..69a4e25 100644
--- a/Swift/Controllers/UnitTest/MockMainWindow.h
+++ b/Swift/Controllers/UnitTest/MockMainWindow.h
@@ -12,18 +12,19 @@ namespace Swift {
class Roster;
class MockMainWindow : public MainWindow {
public:
- MockMainWindow() : roster(NULL) {};
- virtual ~MockMainWindow() {};
- virtual void setRosterModel(Roster* roster) {this->roster = roster;};
- virtual void setMyNick(const std::string& /*name*/) {};;
- virtual void setMyJID(const JID& /*jid*/) {};;
- virtual void setMyAvatarPath(const std::string& /*path*/) {};
- virtual void setMyStatusText(const std::string& /*status*/) {};
- virtual void setMyStatusType(StatusShow::Type /*type*/) {};
- virtual void setAvailableAdHocCommands(const std::vector<DiscoItems::Item>& /*commands*/) {};
- virtual void setConnecting() {};
+ MockMainWindow() : roster(NULL) {}
+ virtual ~MockMainWindow() {}
+ virtual void setRosterModel(Roster* roster) {this->roster = roster;}
+ virtual void setMyNick(const std::string& /*name*/) {}
+ virtual void setMyJID(const JID& /*jid*/) {}
+ virtual void setMyAvatarPath(const std::string& /*path*/) {}
+ virtual void setMyStatusText(const std::string& /*status*/) {}
+ virtual void setMyStatusType(StatusShow::Type /*type*/) {}
+ virtual void setAvailableAdHocCommands(const std::vector<DiscoItems::Item>& /*commands*/) {}
+ virtual void setConnecting() {}
virtual void setStreamEncryptionStatus(bool /*tlsInPlaceAndValid*/) {}
virtual void openCertificateDialog(const std::vector<Certificate::ref>& /*chain*/) {}
+ virtual void setBlockingCommandAvailable(bool /*isAvailable*/) {}
Roster* roster;
};
diff --git a/Swift/Controllers/UnitTest/MockMainWindowFactory.h b/Swift/Controllers/UnitTest/MockMainWindowFactory.h
index d130b39..279a6dd 100644
--- a/Swift/Controllers/UnitTest/MockMainWindowFactory.h
+++ b/Swift/Controllers/UnitTest/MockMainWindowFactory.h
@@ -13,14 +13,14 @@ namespace Swift {
class MockMainWindowFactory : public MainWindowFactory {
public:
- MockMainWindowFactory() : last(NULL) {};
+ MockMainWindowFactory() : last(NULL) {}
- virtual ~MockMainWindowFactory() {};
+ virtual ~MockMainWindowFactory() {}
/**
* Transfers ownership of result.
*/
- virtual MainWindow* createMainWindow(UIEventStream*) {last = new MockMainWindow();return last;};
+ virtual MainWindow* createMainWindow(UIEventStream*) {last = new MockMainWindow();return last;}
MockMainWindow* last;
};
}
diff --git a/Swift/Controllers/XMPPEvents/ErrorEvent.h b/Swift/Controllers/XMPPEvents/ErrorEvent.h
index cbfc471..ac09de9 100644
--- a/Swift/Controllers/XMPPEvents/ErrorEvent.h
+++ b/Swift/Controllers/XMPPEvents/ErrorEvent.h
@@ -18,10 +18,10 @@
namespace Swift {
class ErrorEvent : public StanzaEvent {
public:
- ErrorEvent(const JID& jid, const std::string& text) : jid_(jid), text_(text){};
- virtual ~ErrorEvent(){};
- const JID& getJID() const {return jid_;};
- const std::string& getText() const {return text_;};
+ ErrorEvent(const JID& jid, const std::string& text) : jid_(jid), text_(text){}
+ virtual ~ErrorEvent(){}
+ const JID& getJID() const {return jid_;}
+ const std::string& getText() const {return text_;}
private:
JID jid_;
diff --git a/Swift/Controllers/XMPPEvents/EventController.cpp b/Swift/Controllers/XMPPEvents/EventController.cpp
index d84dfe3..8cb259b 100644
--- a/Swift/Controllers/XMPPEvents/EventController.cpp
+++ b/Swift/Controllers/XMPPEvents/EventController.cpp
@@ -7,6 +7,7 @@
#include <Swift/Controllers/XMPPEvents/EventController.h>
#include <boost/bind.hpp>
+#include <boost/numeric/conversion/cast.hpp>
#include <algorithm>
#include <Swiften/Base/foreach.h>
@@ -48,7 +49,7 @@ void EventController::handleIncomingEvent(boost::shared_ptr<StanzaEvent> sourceE
if ((messageEvent && messageEvent->isReadable()) || subscriptionEvent || errorEvent || mucInviteEvent) {
events_.push_back(sourceEvent);
sourceEvent->onConclusion.connect(boost::bind(&EventController::handleEventConcluded, this, sourceEvent));
- onEventQueueLengthChange(events_.size());
+ onEventQueueLengthChange(boost::numeric_cast<int>(events_.size()));
onEventQueueEventAdded(sourceEvent);
if (sourceEvent->getConcluded()) {
handleEventConcluded(sourceEvent);
@@ -59,7 +60,7 @@ void EventController::handleIncomingEvent(boost::shared_ptr<StanzaEvent> sourceE
void EventController::handleEventConcluded(boost::shared_ptr<StanzaEvent> event) {
event->onConclusion.disconnect(boost::bind(&EventController::handleEventConcluded, this, event));
events_.erase(std::remove(events_.begin(), events_.end(), event), events_.end());
- onEventQueueLengthChange(events_.size());
+ onEventQueueLengthChange(boost::numeric_cast<int>(events_.size()));
}
void EventController::disconnectAll() {
diff --git a/Swift/Controllers/XMPPEvents/MUCInviteEvent.h b/Swift/Controllers/XMPPEvents/MUCInviteEvent.h
index 0b430cd..65ecece 100644
--- a/Swift/Controllers/XMPPEvents/MUCInviteEvent.h
+++ b/Swift/Controllers/XMPPEvents/MUCInviteEvent.h
@@ -13,13 +13,14 @@ namespace Swift {
typedef boost::shared_ptr<MUCInviteEvent> ref;
public:
- MUCInviteEvent(const JID& inviter, const JID& roomJID, const std::string& reason, const std::string& password, bool direct) : inviter_(inviter), roomJID_(roomJID), reason_(reason), password_(password), direct_(direct) {}
+ MUCInviteEvent(const JID& inviter, const JID& roomJID, const std::string& reason, const std::string& password, bool direct, bool impromptu) : inviter_(inviter), roomJID_(roomJID), reason_(reason), password_(password), direct_(direct), impromptu_(impromptu) {}
const JID& getInviter() const { return inviter_; }
const JID& getRoomJID() const { return roomJID_; }
const std::string& getReason() const { return reason_; }
const std::string& getPassword() const { return password_; }
bool getDirect() const { return direct_; }
+ bool getImpromptu() const { return impromptu_; }
private:
JID inviter_;
@@ -27,5 +28,6 @@ namespace Swift {
std::string reason_;
std::string password_;
bool direct_;
+ bool impromptu_;
};
}
diff --git a/Swift/Controllers/XMPPEvents/MessageEvent.h b/Swift/Controllers/XMPPEvents/MessageEvent.h
index 1093470..a9214f5 100644
--- a/Swift/Controllers/XMPPEvents/MessageEvent.h
+++ b/Swift/Controllers/XMPPEvents/MessageEvent.h
@@ -17,7 +17,7 @@ namespace Swift {
public:
typedef boost::shared_ptr<MessageEvent> ref;
- MessageEvent(boost::shared_ptr<Message> stanza) : stanza_(stanza), targetsMe_(true) {};
+ MessageEvent(boost::shared_ptr<Message> stanza) : stanza_(stanza), targetsMe_(true) {}
boost::shared_ptr<Message> getStanza() {return stanza_;}
diff --git a/Swift/Controllers/XMPPEvents/StanzaEvent.h b/Swift/Controllers/XMPPEvents/StanzaEvent.h
index 321d23d..a15afc1 100644
--- a/Swift/Controllers/XMPPEvents/StanzaEvent.h
+++ b/Swift/Controllers/XMPPEvents/StanzaEvent.h
@@ -14,13 +14,13 @@
namespace Swift {
class StanzaEvent {
public:
- StanzaEvent() : time_(boost::posix_time::microsec_clock::universal_time()) {concluded_ = false;};
- virtual ~StanzaEvent() {};
- void conclude() {concluded_ = true; onConclusion();};
+ StanzaEvent() : time_(boost::posix_time::microsec_clock::universal_time()) {concluded_ = false;}
+ virtual ~StanzaEvent() {}
+ void conclude() {concluded_ = true; onConclusion();}
/** Do not call this directly from outside the class.
* If you connect to this signal, you *must* disconnect from it manually. */
boost::signal<void()> onConclusion;
- bool getConcluded() {return concluded_;};
+ bool getConcluded() {return concluded_;}
boost::posix_time::ptime getTime() {return time_;}
private:
bool concluded_;
diff --git a/Swift/Controllers/XMPPEvents/SubscriptionRequestEvent.h b/Swift/Controllers/XMPPEvents/SubscriptionRequestEvent.h
index 1f7812e..fb7a05e 100644
--- a/Swift/Controllers/XMPPEvents/SubscriptionRequestEvent.h
+++ b/Swift/Controllers/XMPPEvents/SubscriptionRequestEvent.h
@@ -18,21 +18,21 @@
namespace Swift {
class SubscriptionRequestEvent : public StanzaEvent {
public:
- SubscriptionRequestEvent(const JID& jid, const std::string& reason) : jid_(jid), reason_(reason){};
- virtual ~SubscriptionRequestEvent(){};
- const JID& getJID() const {return jid_;};
- const std::string& getReason() const {return reason_;};
+ SubscriptionRequestEvent(const JID& jid, const std::string& reason) : jid_(jid), reason_(reason){}
+ virtual ~SubscriptionRequestEvent(){}
+ const JID& getJID() const {return jid_;}
+ const std::string& getReason() const {return reason_;}
boost::signal<void()> onAccept;
boost::signal<void()> onDecline;
void accept() {
onAccept();
conclude();
- };
+ }
void decline() {
onDecline();
conclude();
- };
+ }
void defer() {
conclude();