summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swift/Controllers')
-rw-r--r--Swift/Controllers/AccountController.cpp (renamed from Swift/Controllers/MainController.cpp)205
-rw-r--r--Swift/Controllers/AccountController.h (renamed from Swift/Controllers/MainController.h)18
-rw-r--r--Swift/Controllers/Chat/ChatController.cpp7
-rw-r--r--Swift/Controllers/Chat/ChatController.h57
-rw-r--r--Swift/Controllers/Chat/ChatControllerBase.cpp69
-rw-r--r--Swift/Controllers/Chat/ChatControllerBase.h19
-rw-r--r--Swift/Controllers/Chat/ChatsManager.cpp166
-rw-r--r--Swift/Controllers/Chat/ChatsManager.h78
-rw-r--r--Swift/Controllers/Chat/Chattables.cpp43
-rw-r--r--Swift/Controllers/Chat/Chattables.h47
-rw-r--r--Swift/Controllers/Chat/MUCController.cpp95
-rw-r--r--Swift/Controllers/Chat/MUCController.h44
-rw-r--r--Swift/Controllers/Chat/UnitTest/ChatControllerTest.cpp162
-rw-r--r--Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp206
-rw-r--r--Swift/Controllers/Chat/UnitTest/ChattablesTest.cpp140
-rw-r--r--Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp1382
-rw-r--r--Swift/Controllers/Chat/UnitTest/MockChatListWindow.h2
-rw-r--r--Swift/Controllers/ContactSuggester.cpp11
-rw-r--r--Swift/Controllers/FdpFormSubmitController.cpp145
-rw-r--r--Swift/Controllers/FdpFormSubmitController.h47
-rw-r--r--Swift/Controllers/FileTransfer/FileTransferProgressInfo.cpp8
-rw-r--r--Swift/Controllers/FileTransfer/FileTransferProgressInfo.h13
-rw-r--r--Swift/Controllers/Roster/LeastCommonSubsequence.h4
-rw-r--r--Swift/Controllers/Roster/Roster.cpp2
-rw-r--r--Swift/Controllers/Roster/RosterController.cpp23
-rw-r--r--Swift/Controllers/Roster/RosterController.h6
-rw-r--r--Swift/Controllers/Roster/TableRoster.cpp25
-rw-r--r--Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp16
-rw-r--r--Swift/Controllers/Roster/UnitTest/RosterTest.cpp2
-rw-r--r--Swift/Controllers/Roster/UnitTest/TableRosterTest.cpp4
-rw-r--r--Swift/Controllers/SConscript8
-rw-r--r--Swift/Controllers/SettingConstants.cpp7
-rw-r--r--Swift/Controllers/SettingConstants.h24
-rw-r--r--Swift/Controllers/Storages/CertificateFileStorage.cpp15
-rw-r--r--Swift/Controllers/UIEvents/FdpFormSubmitWindowOpenUIEvent.h17
-rw-r--r--Swift/Controllers/UIEvents/JoinMUCUIEvent.h2
-rw-r--r--Swift/Controllers/UIInterfaces/ChatListWindow.h8
-rw-r--r--Swift/Controllers/UIInterfaces/ChatWindow.h13
-rw-r--r--Swift/Controllers/UIInterfaces/FdpFormSubmitWindow.cpp32
-rw-r--r--Swift/Controllers/UIInterfaces/FdpFormSubmitWindow.h54
-rw-r--r--Swift/Controllers/UIInterfaces/FdpFormSubmitWindowFactory.h19
-rw-r--r--Swift/Controllers/UIInterfaces/MainWindow.h4
-rw-r--r--Swift/Controllers/UIInterfaces/MainWindowFactory.h14
-rw-r--r--Swift/Controllers/UIInterfaces/UIFactory.h6
-rw-r--r--Swift/Controllers/UnitTest/FdpFormSubmitControllerTest.cpp269
-rw-r--r--Swift/Controllers/UnitTest/MockChatWindow.h17
-rw-r--r--Swift/Controllers/UnitTest/MockFdpFormSubmitWindow.h37
-rw-r--r--Swift/Controllers/UnitTest/MockFdpFormSubmitWindowFactory.h31
-rw-r--r--Swift/Controllers/UnitTest/MockMainWindow.h3
-rw-r--r--Swift/Controllers/UnitTest/MockMainWindowFactory.h4
-rw-r--r--Swift/Controllers/XMPPEvents/EventController.cpp6
-rw-r--r--Swift/Controllers/XMPPEvents/EventController.h5
52 files changed, 2681 insertions, 960 deletions
diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/AccountController.cpp
index b22e467..27655c0 100644
--- a/Swift/Controllers/MainController.cpp
+++ b/Swift/Controllers/AccountController.cpp
@@ -1,10 +1,10 @@
/*
- * Copyright (c) 2010-2017 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
-#include <Swift/Controllers/MainController.h>
+#include <Swift/Controllers/AccountController.h>
#include <cstdlib>
#include <memory>
@@ -47,6 +47,7 @@
#include <Swift/Controllers/AdHocManager.h>
#include <Swift/Controllers/BlockListController.h>
#include <Swift/Controllers/BuildVersion.h>
+#include <Swift/Controllers/Chat/Chattables.h>
#include <Swift/Controllers/Chat/ChatsManager.h>
#include <Swift/Controllers/Chat/MUCController.h>
#include <Swift/Controllers/Chat/UserSearchController.h>
@@ -55,6 +56,7 @@
#include <Swift/Controllers/ContactsFromXMPPRoster.h>
#include <Swift/Controllers/EventNotifier.h>
#include <Swift/Controllers/EventWindowController.h>
+#include <Swift/Controllers/FdpFormSubmitController.h>
#include <Swift/Controllers/FileTransfer/FileTransferOverview.h>
#include <Swift/Controllers/FileTransferListController.h>
#include <Swift/Controllers/Highlighting/HighlightEditorController.h>
@@ -98,7 +100,7 @@ static const std::string CLIENT_NAME = "Swift";
static const std::string CLIENT_NODE = "http://swift.im";
-MainController::MainController(
+AccountController::AccountController(
EventLoop* eventLoop,
NetworkFactories* networkFactories,
UIFactory* uiFactories,
@@ -124,7 +126,8 @@ MainController::MainController(
loginWindow_(nullptr) ,
useDelayForLatency_(useDelayForLatency),
ftOverview_(nullptr),
- emoticons_(emoticons) {
+ emoticons_(emoticons),
+ fdpFormSubmitController_(nullptr) {
storages_ = nullptr;
certificateStorage_ = nullptr;
certificateTrustChecker_ = nullptr;
@@ -159,7 +162,7 @@ MainController::MainController(
notifier_ = new TogglableNotifier(notifier);
notifier_->setPersistentEnabled(settings_->getSetting(SettingConstants::SHOW_NOTIFICATIONS));
eventController_ = new EventController();
- eventController_->onEventQueueLengthChange.connect(boost::bind(&MainController::handleEventQueueLengthChange, this, _1));
+ eventController_->onEventQueueLengthChange.connect(boost::bind(&AccountController::handleEventQueueLengthChange, this, _1));
systemTrayController_ = new SystemTrayController(eventController_, systemTray);
loginWindow_ = uiFactory_->createLoginWindow(uiEventStream_);
@@ -172,61 +175,24 @@ MainController::MainController(
xmppURIController_ = new XMPPURIController(uriHandler_, uiEventStream_);
- std::string selectedLoginJID = settings_->getSetting(SettingConstants::LAST_LOGIN_JID);
- bool loginAutomatically = settings_->getSetting(SettingConstants::LOGIN_AUTOMATICALLY);
- std::string cachedPassword;
- std::string cachedCertificate;
- ClientOptions cachedOptions;
- bool eagle = settings_->getSetting(SettingConstants::FORGET_PASSWORDS);
- if (!eagle) {
- for (auto&& profile : settings->getAvailableProfiles()) {
- ProfileSettingsProvider profileSettings(profile, settings);
- std::string password = profileSettings.getStringSetting("pass");
- std::string certificate = profileSettings.getStringSetting("certificate");
- std::string jid = profileSettings.getStringSetting("jid");
- ClientOptions clientOptions = parseClientOptions(profileSettings.getStringSetting("options"));
-
-#ifdef SWIFTEN_PLATFORM_WIN32
- clientOptions.singleSignOn = settings_->getSetting(SettingConstants::SINGLE_SIGN_ON);
-#endif
-
- loginWindow_->addAvailableAccount(jid, password, certificate, clientOptions);
- if (jid == selectedLoginJID) {
- cachedPassword = password;
- cachedCertificate = certificate;
- cachedOptions = clientOptions;
- }
- }
- loginWindow_->selectUser(selectedLoginJID);
- loginWindow_->setLoginAutomatically(loginAutomatically);
- }
-
-
- loginWindow_->onLoginRequest.connect(boost::bind(&MainController::handleLoginRequest, this, _1, _2, _3, _4, _5, _6, _7));
- loginWindow_->onPurgeSavedLoginRequest.connect(boost::bind(&MainController::handlePurgeSavedLoginRequest, this, _1));
- loginWindow_->onCancelLoginRequest.connect(boost::bind(&MainController::handleCancelLoginRequest, this));
- loginWindow_->onQuitRequest.connect(boost::bind(&MainController::handleQuitRequest, this));
+ loginWindow_->onLoginRequest.connect(boost::bind(&AccountController::handleLoginRequest, this, _1, _2, _3, _4, _5, _6, _7));
+ loginWindow_->onPurgeSavedLoginRequest.connect(boost::bind(&AccountController::handlePurgeSavedLoginRequest, this, _1));
+ loginWindow_->onCancelLoginRequest.connect(boost::bind(&AccountController::handleCancelLoginRequest, this));
+ loginWindow_->onQuitRequest.connect(boost::bind(&AccountController::handleQuitRequest, this));
idleDetector_->setIdleTimeSeconds(settings->getSetting(SettingConstants::IDLE_TIMEOUT));
- idleDetector_->onIdleChanged.connect(boost::bind(&MainController::handleInputIdleChanged, this, _1));
+ idleDetector_->onIdleChanged.connect(boost::bind(&AccountController::handleInputIdleChanged, this, _1));
xmlConsoleController_ = new XMLConsoleController(uiEventStream_, uiFactory_);
fileTransferListController_ = new FileTransferListController(uiEventStream_, uiFactory_);
- settings_->onSettingChanged.connect(boost::bind(&MainController::handleSettingChanged, this, _1));
+ settings_->onSettingChanged.connect(boost::bind(&AccountController::handleSettingChanged, this, _1));
- if (loginAutomatically) {
- profileSettings_ = new ProfileSettingsProvider(selectedLoginJID, settings_);
- /* FIXME: deal with autologin with a cert*/
- handleLoginRequest(selectedLoginJID, cachedPassword, cachedCertificate, CertificateWithKey::ref(), cachedOptions, true, true);
- } else {
- profileSettings_ = nullptr;
- }
}
-MainController::~MainController() {
- idleDetector_->onIdleChanged.disconnect(boost::bind(&MainController::handleInputIdleChanged, this, _1));
+AccountController::~AccountController() {
+ idleDetector_->onIdleChanged.disconnect(boost::bind(&AccountController::handleInputIdleChanged, this, _1));
purgeCachedCredentials();
//setManagersOffline();
@@ -245,11 +211,11 @@ MainController::~MainController() {
delete uiEventStream_;
}
-void MainController::purgeCachedCredentials() {
+void AccountController::purgeCachedCredentials() {
safeClear(password_);
}
-void MainController::resetClient() {
+void AccountController::resetClient() {
purgeCachedCredentials();
resetCurrentError();
resetPendingReconnects();
@@ -277,6 +243,7 @@ void MainController::resetClient() {
blockListController_ = nullptr;
delete rosterController_;
rosterController_ = nullptr;
+ chattables_.reset();
delete eventNotifier_;
eventNotifier_ = nullptr;
delete presenceNotifier_;
@@ -310,13 +277,13 @@ void MainController::resetClient() {
clientInitialized_ = false;
}
-void MainController::handleSettingChanged(const std::string& settingPath) {
+void AccountController::handleSettingChanged(const std::string& settingPath) {
if (settingPath == SettingConstants::SHOW_NOTIFICATIONS.getKey()) {
notifier_->setPersistentEnabled(settings_->getSetting(SettingConstants::SHOW_NOTIFICATIONS));
}
}
-void MainController::resetPendingReconnects() {
+void AccountController::resetPendingReconnects() {
timeBeforeNextReconnect_ = -1;
if (reconnectTimer_) {
reconnectTimer_->stop();
@@ -325,14 +292,14 @@ void MainController::resetPendingReconnects() {
resetCurrentError();
}
-void MainController::resetCurrentError() {
+void AccountController::resetCurrentError() {
if (lastDisconnectError_) {
lastDisconnectError_->conclude();
lastDisconnectError_ = std::shared_ptr<ErrorEvent>();
}
}
-void MainController::handleConnected() {
+void AccountController::handleConnected() {
boundJID_ = client_->getJID();
resetCurrentError();
resetPendingReconnects();
@@ -348,10 +315,11 @@ void MainController::handleConnected() {
showProfileController_ = new ShowProfileController(client_->getVCardManager(), uiFactory_, uiEventStream_);
ftOverview_ = new FileTransferOverview(client_->getFileTransferManager());
fileTransferListController_->setFileTransferOverview(ftOverview_);
- rosterController_ = new RosterController(boundJID_, client_->getRoster(), client_->getAvatarManager(), uiFactory_, client_->getNickManager(), client_->getNickResolver(), client_->getPresenceOracle(), client_->getSubscriptionManager(), eventController_, uiEventStream_, client_->getIQRouter(), settings_, client_->getEntityCapsProvider(), client_->getClientBlockListManager(), client_->getVCardManager());
- 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));
+ chattables_ = std::make_unique<Chattables>();
+ rosterController_ = new RosterController(boundJID_, client_->getRoster(), client_->getAvatarManager(), uiFactory_, client_->getNickManager(), client_->getNickResolver(), client_->getPresenceOracle(), client_->getSubscriptionManager(), eventController_, uiEventStream_, client_->getIQRouter(), settings_, client_->getEntityCapsProvider(), client_->getClientBlockListManager(), client_->getVCardManager(), *chattables_);
+ rosterController_->onChangeStatusRequest.connect(boost::bind(&AccountController::handleChangeStatusRequest, this, _1, _2));
+ rosterController_->onSignOutRequest.connect(boost::bind(&AccountController::signOut, this));
+ rosterController_->getWindow()->onShowCertificateRequest.connect(boost::bind(&AccountController::handleShowCertificateRequest, this));
blockListController_ = new BlockListController(client_->getClientBlockListManager(), uiEventStream_, uiFactory_, eventController_);
@@ -372,7 +340,7 @@ void MainController::handleConnected() {
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_, highlightManager_, client_->getClientBlockListManager(), emoticons_, client_->getVCardManager());
#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_, nullptr, whiteboardManager_, highlightManager_, client_->getClientBlockListManager(), emoticons_, client_->getVCardManager());
+ 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_, nullptr, whiteboardManager_, highlightManager_, client_->getClientBlockListManager(), emoticons_, client_->getVCardManager(), *chattables_);
#endif
contactsFromRosterProvider_ = new ContactsFromXMPPRoster(client_->getRoster(), client_->getAvatarManager(), client_->getPresenceOracle());
contactSuggesterWithoutRoster_->addContactProvider(chatsManager_);
@@ -416,7 +384,7 @@ void MainController::handleConnected() {
client_->requestRoster();
GetDiscoInfoRequest::ref discoInfoRequest = GetDiscoInfoRequest::create(JID(boundJID_.getDomain()), client_->getIQRouter());
- discoInfoRequest->onResponse.connect(boost::bind(&MainController::handleServerDiscoInfoResponse, this, _1, _2));
+ discoInfoRequest->onResponse.connect(boost::bind(&AccountController::handleServerDiscoInfoResponse, this, _1, _2));
discoInfoRequest->send();
client_->getVCardManager()->requestOwnVCard();
@@ -435,18 +403,18 @@ void MainController::handleConnected() {
adHocManager_->setOnline(true);
}
-void MainController::handleEventQueueLengthChange(int count) {
+void AccountController::handleEventQueueLengthChange(size_t count) {
dock_->setNumberOfPendingMessages(count);
}
-void MainController::reconnectAfterError() {
+void AccountController::reconnectAfterError() {
if (reconnectTimer_) {
reconnectTimer_->stop();
}
performLoginFromCachedCredentials();
}
-void MainController::handleChangeStatusRequest(StatusShow::Type show, const std::string &statusText) {
+void AccountController::handleChangeStatusRequest(StatusShow::Type show, const std::string &statusText) {
std::shared_ptr<Presence> presence(new Presence());
if (show == StatusShow::None) {
// Note: this is misleading, None doesn't mean unavailable on the wire.
@@ -472,7 +440,7 @@ void MainController::handleChangeStatusRequest(StatusShow::Type show, const std:
}
}
-void MainController::sendPresence(std::shared_ptr<Presence> presence) {
+void AccountController::sendPresence(std::shared_ptr<Presence> presence) {
rosterController_->getWindow()->setMyStatusType(presence->getShow());
rosterController_->getWindow()->setMyStatusText(presence->getStatus());
systemTrayController_->setMyStatusType(presence->getShow());
@@ -486,7 +454,7 @@ void MainController::sendPresence(std::shared_ptr<Presence> presence) {
}
}
-void MainController::handleInputIdleChanged(bool idle) {
+void AccountController::handleInputIdleChanged(bool idle) {
if (!statusTracker_) {
//Haven't logged in yet.
return;
@@ -514,12 +482,12 @@ void MainController::handleInputIdleChanged(bool idle) {
}
}
-void MainController::handleShowCertificateRequest() {
+void AccountController::handleShowCertificateRequest() {
std::vector<Certificate::ref> chain = client_->getStanzaChannel()->getPeerCertificateChain();
rosterController_->getWindow()->openCertificateDialog(chain);
}
-void MainController::handleLoginRequest(const std::string &username, const std::string &password, const std::string& certificatePath, CertificateWithKey::ref certificate, const ClientOptions& options, bool remember, bool loginAutomatically) {
+void AccountController::handleLoginRequest(const std::string &username, const std::string &password, const std::string& certificatePath, CertificateWithKey::ref certificate, const ClientOptions& options, bool remember, bool loginAutomatically) {
jid_ = JID(username);
if (options.singleSignOn && (!jid_.isValid() || !jid_.getNode().empty())) {
loginWindow_->setMessage(QT_TRANSLATE_NOOP("", "User address invalid. User address should be of the form 'wonderland.lit'"));
@@ -556,8 +524,7 @@ void MainController::handleLoginRequest(const std::string &username, const std::
profileSettings_->storeString("pass", (remember || loginAutomatically) ? password : "");
std::string optionString = serializeClientOptions(options);
profileSettings_->storeString("options", optionString);
- settings_->storeSetting(SettingConstants::LAST_LOGIN_JID, username);
- settings_->storeSetting(SettingConstants::LOGIN_AUTOMATICALLY, loginAutomatically);
+ profileSettings_->storeInt("enabled", 1);
loginWindow_->addAvailableAccount(profileSettings_->getStringSetting("jid"), profileSettings_->getStringSetting("pass"), profileSettings_->getStringSetting("certificate"), options);
}
@@ -568,12 +535,12 @@ void MainController::handleLoginRequest(const std::string &username, const std::
}
}
-void MainController::handlePurgeSavedLoginRequest(const std::string& username) {
+void AccountController::handlePurgeSavedLoginRequest(const std::string& username) {
settings_->removeProfile(username);
loginWindow_->removeAvailableAccount(username);
}
-void MainController::performLoginFromCachedCredentials() {
+void AccountController::performLoginFromCachedCredentials() {
if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS) && password_.empty()) {
/* Then we can't try to login again. */
return;
@@ -598,16 +565,16 @@ void MainController::performLoginFromCachedCredentials() {
client_->setCertificateTrustChecker(certificateTrustChecker_);
client_->onDataRead.connect(boost::bind(&XMLConsoleController::handleDataRead, xmlConsoleController_, _1));
client_->onDataWritten.connect(boost::bind(&XMLConsoleController::handleDataWritten, xmlConsoleController_, _1));
- client_->onDisconnected.connect(boost::bind(&MainController::handleDisconnected, this, _1));
- client_->onConnected.connect(boost::bind(&MainController::handleConnected, this));
+ client_->onDisconnected.connect(boost::bind(&AccountController::handleDisconnected, this, _1));
+ client_->onConnected.connect(boost::bind(&AccountController::handleConnected, this));
client_->setSoftwareVersion(CLIENT_NAME, buildVersion);
- client_->getVCardManager()->onVCardChanged.connect(boost::bind(&MainController::handleVCardReceived, this, _1, _2));
+ client_->getVCardManager()->onVCardChanged.connect(boost::bind(&AccountController::handleVCardReceived, this, _1, _2));
presenceNotifier_ = new PresenceNotifier(client_->getStanzaChannel(), notifier_, client_->getMUCRegistry(), client_->getAvatarManager(), client_->getNickResolver(), client_->getPresenceOracle(), networkFactories_->getTimerFactory());
- presenceNotifier_->onNotificationActivated.connect(boost::bind(&MainController::handleNotificationClicked, this, _1));
+ presenceNotifier_->onNotificationActivated.connect(boost::bind(&AccountController::handleNotificationClicked, this, _1));
eventNotifier_ = new EventNotifier(eventController_, notifier_, client_->getAvatarManager(), client_->getNickResolver());
- eventNotifier_->onNotificationActivated.connect(boost::bind(&MainController::handleNotificationClicked, this, _1));
+ eventNotifier_->onNotificationActivated.connect(boost::bind(&AccountController::handleNotificationClicked, this, _1));
if (certificate_) {
client_->setCertificate(certificate_);
}
@@ -615,6 +582,7 @@ void MainController::performLoginFromCachedCredentials() {
presence->setShow(static_cast<StatusShow::Type>(profileSettings_->getIntSetting("lastShow", StatusShow::Online)));
presence->setStatus(profileSettings_->getStringSetting("lastStatus"));
statusTracker_->setRequestedPresence(presence);
+ fdpFormSubmitController_ = std::make_unique<FdpFormSubmitController>(jid_, client_->getIQRouter(), uiEventStream_, uiFactory_);
} else {
/* In case we're in the middle of another login, make sure they don't overlap */
client_->disconnect();
@@ -630,7 +598,7 @@ void MainController::performLoginFromCachedCredentials() {
client_->connect(clientOptions);
}
-void MainController::handleDisconnected(const boost::optional<ClientError>& error) {
+void AccountController::handleDisconnected(const boost::optional<ClientError>& error) {
if (rosterController_) {
rosterController_->getWindow()->setStreamEncryptionStatus(false);
}
@@ -720,7 +688,7 @@ void MainController::handleDisconnected(const boost::optional<ClientError>& erro
setReconnectTimer();
}
if (lastDisconnectError_) {
- message = str(format(QT_TRANSLATE_NOOP("", "Reconnect to %1% failed: %2%. Will retry in %3% seconds.")) % jid_.getDomain() % message % boost::lexical_cast<std::string>(timeBeforeNextReconnect_));
+ message = str(format(QT_TRANSLATE_NOOP("", "Reconnect to %1% failed: %2%. Will retry in %3% seconds.")) % jid_.getDomain() % message % std::to_string(timeBeforeNextReconnect_));
lastDisconnectError_->conclude();
} else {
message = str(format(QT_TRANSLATE_NOOP("", "Disconnected from %1%: %2%.")) % jid_.getDomain() % message);
@@ -735,7 +703,7 @@ void MainController::handleDisconnected(const boost::optional<ClientError>& erro
}
}
-void MainController::setReconnectTimer() {
+void AccountController::setReconnectTimer() {
if (timeBeforeNextReconnect_ < 0) {
timeBeforeNextReconnect_ = 1;
} else {
@@ -745,25 +713,26 @@ void MainController::setReconnectTimer() {
reconnectTimer_->stop();
}
reconnectTimer_ = networkFactories_->getTimerFactory()->createTimer(timeBeforeNextReconnect_ * 1000);
- reconnectTimer_->onTick.connect(boost::bind(&MainController::reconnectAfterError, this));
+ reconnectTimer_->onTick.connect(boost::bind(&AccountController::reconnectAfterError, this));
reconnectTimer_->start();
}
-void MainController::handleCancelLoginRequest() {
+void AccountController::handleCancelLoginRequest() {
signOut();
}
-void MainController::signOut() {
+void AccountController::signOut() {
if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) {
purgeCachedCredentials();
}
+ profileSettings_->storeInt("enabled", 0);
eventController_->clear();
logout();
loginWindow_->loggedOut();
resetClient();
}
-void MainController::logout() {
+void AccountController::logout() {
if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) {
purgeCachedCredentials();
}
@@ -779,7 +748,7 @@ void MainController::logout() {
setManagersOffline();
}
-void MainController::setManagersOffline() {
+void AccountController::setManagersOffline() {
if (chatsManager_) {
chatsManager_->setOnline(false);
}
@@ -794,7 +763,7 @@ void MainController::setManagersOffline() {
}
}
-void MainController::handleServerDiscoInfoResponse(std::shared_ptr<DiscoInfo> info, ErrorPayload::ref error) {
+void AccountController::handleServerDiscoInfoResponse(std::shared_ptr<DiscoInfo> info, ErrorPayload::ref error) {
if (!error) {
chatsManager_->setServerDiscoInfo(info);
adHocManager_->setServerDiscoInfo(info);
@@ -808,7 +777,7 @@ void MainController::handleServerDiscoInfoResponse(std::shared_ptr<DiscoInfo> in
}
}
-void MainController::enableMessageCarbons() {
+void AccountController::enableMessageCarbons() {
auto enableCarbonsRequest = EnableCarbonsRequest::create(client_->getIQRouter());
enableCarbonsRequestHandlerConnection_ = enableCarbonsRequest->onResponse.connect([&](Payload::ref /*payload*/, ErrorPayload::ref error) {
if (error) {
@@ -822,7 +791,7 @@ void MainController::enableMessageCarbons() {
enableCarbonsRequest->send();
}
-void MainController::handleVCardReceived(const JID& jid, VCard::ref vCard) {
+void AccountController::handleVCardReceived(const JID& jid, VCard::ref vCard) {
if (!jid.equals(jid_, JID::WithoutResource) || !vCard) {
return;
}
@@ -838,7 +807,7 @@ void MainController::handleVCardReceived(const JID& jid, VCard::ref vCard) {
}
}
-void MainController::handleNotificationClicked(const JID& jid) {
+void AccountController::handleNotificationClicked(const JID& jid) {
assert(chatsManager_);
if (clientInitialized_) {
if (client_->getMUCRegistry()->isMUC(jid)) {
@@ -850,7 +819,7 @@ void MainController::handleNotificationClicked(const JID& jid) {
}
}
-void MainController::handleQuitRequest() {
+void AccountController::handleQuitRequest() {
if (client_ && client_->isActive()) {
quitRequested_ = true;
client_->disconnect();
@@ -861,13 +830,15 @@ void MainController::handleQuitRequest() {
}
}
+//FIXME: Switch all this to boost::serialise
+
#define SERIALIZE_BOOL(option) result += options.option ? "1" : "0"; result += ",";
#define SERIALIZE_INT(option) result += boost::lexical_cast<std::string>(options.option); result += ",";
#define SERIALIZE_STRING(option) result += Base64::encode(createByteArray(options.option)); result += ",";
#define SERIALIZE_SAFE_STRING(option) result += safeByteArrayToString(Base64::encode(options.option)); result += ",";
#define SERIALIZE_URL(option) SERIALIZE_STRING(option.toString())
-std::string MainController::serializeClientOptions(const ClientOptions& options) {
+std::string AccountController::serializeClientOptions(const ClientOptions& options) {
std::string result;
SERIALIZE_BOOL(useStreamCompression);
switch (options.useTLS) {
@@ -895,55 +866,7 @@ std::string MainController::serializeClientOptions(const ClientOptions& options)
SERIALIZE_SAFE_STRING(boshHTTPConnectProxyAuthID);
SERIALIZE_SAFE_STRING(boshHTTPConnectProxyAuthPassword);
SERIALIZE_BOOL(tlsOptions.schannelTLS1_0Workaround);
- return result;
-}
-
-#define CHECK_PARSE_LENGTH if (i >= segments.size()) {return result;}
-#define PARSE_INT_RAW(defaultValue) CHECK_PARSE_LENGTH intVal = defaultValue; try {intVal = boost::lexical_cast<int>(segments[i]);} catch(const boost::bad_lexical_cast&) {};i++;
-#define PARSE_STRING_RAW CHECK_PARSE_LENGTH stringVal = byteArrayToString(Base64::decode(segments[i]));i++;
-
-#define PARSE_BOOL(option, defaultValue) PARSE_INT_RAW(defaultValue); result.option = (intVal == 1);
-#define PARSE_INT(option, defaultValue) PARSE_INT_RAW(defaultValue); result.option = intVal;
-#define PARSE_STRING(option) PARSE_STRING_RAW; result.option = stringVal;
-#define PARSE_SAFE_STRING(option) PARSE_STRING_RAW; result.option = SafeString(createSafeByteArray(stringVal));
-#define PARSE_URL(option) {PARSE_STRING_RAW; result.option = URL::fromString(stringVal);}
-
-
-ClientOptions MainController::parseClientOptions(const std::string& optionString) {
- ClientOptions result;
- size_t i = 0;
- int intVal = 0;
- std::string stringVal;
- std::vector<std::string> segments = String::split(optionString, ',');
-
- PARSE_BOOL(useStreamCompression, 1);
- PARSE_INT_RAW(-1);
- switch (intVal) {
- case 1: result.useTLS = ClientOptions::NeverUseTLS;break;
- case 2: result.useTLS = ClientOptions::UseTLSWhenAvailable;break;
- case 3: result.useTLS = ClientOptions::RequireTLS;break;
- default:;
- }
- PARSE_BOOL(allowPLAINWithoutTLS, 0);
- PARSE_BOOL(useStreamResumption, 0);
- PARSE_BOOL(useAcks, 1);
- PARSE_STRING(manualHostname);
- PARSE_INT(manualPort, -1);
- PARSE_INT_RAW(-1);
- switch (intVal) {
- case 1: result.proxyType = ClientOptions::NoProxy;break;
- case 2: result.proxyType = ClientOptions::SystemConfiguredProxy;break;
- case 3: result.proxyType = ClientOptions::SOCKS5Proxy;break;
- case 4: result.proxyType = ClientOptions::HTTPConnectProxy;break;
- }
- PARSE_STRING(manualProxyHostname);
- PARSE_INT(manualProxyPort, -1);
- PARSE_URL(boshURL);
- PARSE_URL(boshHTTPConnectProxyURL);
- PARSE_SAFE_STRING(boshHTTPConnectProxyAuthID);
- PARSE_SAFE_STRING(boshHTTPConnectProxyAuthPassword);
- PARSE_BOOL(tlsOptions.schannelTLS1_0Workaround, false);
-
+ SERIALIZE_BOOL(singleSignOn);
return result;
}
diff --git a/Swift/Controllers/MainController.h b/Swift/Controllers/AccountController.h
index cc3d45f..4a31645 100644
--- a/Swift/Controllers/MainController.h
+++ b/Swift/Controllers/AccountController.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -33,6 +33,7 @@ namespace Swift {
class UIFactory;
class EventLoop;
class Client;
+ class Chattables;
class ChatController;
class ChatsManager;
class CertificateStorageFactory;
@@ -80,10 +81,11 @@ namespace Swift {
class BlockListController;
class ContactSuggester;
class ContactsFromXMPPRoster;
+ class FdpFormSubmitController;
- class MainController {
+ class AccountController {
public:
- MainController(
+ AccountController(
EventLoop* eventLoop,
NetworkFactories* networkFactories,
UIFactory* uiFactories,
@@ -98,8 +100,7 @@ namespace Swift {
IdleDetector* idleDetector,
const std::map<std::string, std::string>& emoticons,
bool useDelayForLatency);
- ~MainController();
-
+ ~AccountController();
private:
void resetClient();
@@ -110,7 +111,7 @@ namespace Swift {
void handleChangeStatusRequest(StatusShow::Type show, const std::string &statusText);
void handleDisconnected(const boost::optional<ClientError>& error);
void handleServerDiscoInfoResponse(std::shared_ptr<DiscoInfo>, ErrorPayload::ref);
- void handleEventQueueLengthChange(int count);
+ void handleEventQueueLengthChange(size_t count);
void handleVCardReceived(const JID& j, VCard::ref vCard);
void handleSettingChanged(const std::string& settingPath);
void handlePurgeSavedLoginRequest(const std::string& username);
@@ -131,7 +132,6 @@ namespace Swift {
void handleForceQuit();
void purgeCachedCredentials();
std::string serializeClientOptions(const ClientOptions& options);
- ClientOptions parseClientOptions(const std::string& optionString);
private:
EventLoop* eventLoop_;
@@ -145,13 +145,14 @@ namespace Swift {
bool clientInitialized_;
std::shared_ptr<Client> client_;
SettingsProvider *settings_;
- ProfileSettingsProvider* profileSettings_;
+ ProfileSettingsProvider* profileSettings_ = nullptr;
Dock* dock_;
URIHandler* uriHandler_;
IdleDetector* idleDetector_;
TogglableNotifier* notifier_;
PresenceNotifier* presenceNotifier_;
EventNotifier* eventNotifier_;
+ std::unique_ptr<Chattables> chattables_;
RosterController* rosterController_;
EventController* eventController_;
EventWindowController* eventWindowController_;
@@ -197,5 +198,6 @@ namespace Swift {
HighlightEditorController* highlightEditorController_;
std::map<std::string, std::string> emoticons_;
boost::signals2::connection enableCarbonsRequestHandlerConnection_;
+ std::unique_ptr<FdpFormSubmitController> fdpFormSubmitController_;
};
}
diff --git a/Swift/Controllers/Chat/ChatController.cpp b/Swift/Controllers/Chat/ChatController.cpp
index 40f6156..5f441f8 100644
--- a/Swift/Controllers/Chat/ChatController.cpp
+++ b/Swift/Controllers/Chat/ChatController.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2017 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -52,8 +52,8 @@ namespace Swift {
/**
* The controller does not gain ownership of the stanzaChannel, nor the factory.
*/
-ChatController::ChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency, UIEventStream* eventStream, TimerFactory* timerFactory, EventController* eventController, EntityCapsProvider* entityCapsProvider, bool userWantsReceipts, SettingsProvider* settings, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, std::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider)
- : ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, contact, nickResolver, presenceOracle, avatarManager, useDelayForLatency, eventStream, eventController, entityCapsProvider, historyController, mucRegistry, highlightManager, chatMessageParser, autoAcceptMUCInviteDecider), userWantsReceipts_(userWantsReceipts), settings_(settings), clientBlockListManager_(clientBlockListManager) {
+ChatController::ChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency, UIEventStream* eventStream, TimerFactory* timerFactory, EventController* eventController, EntityCapsProvider* entityCapsProvider, bool userWantsReceipts, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, std::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider, SettingsProvider* settings, Chattables& chattables)
+ : ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, contact, nickResolver, presenceOracle, avatarManager, useDelayForLatency, eventStream, eventController, entityCapsProvider, historyController, mucRegistry, highlightManager, chatMessageParser, autoAcceptMUCInviteDecider, settings, chattables), userWantsReceipts_(userWantsReceipts), clientBlockListManager_(clientBlockListManager) {
isInMUC_ = isInMUC;
lastWasPresence_ = false;
chatStateNotifier_ = new ChatStateNotifier(stanzaChannel, contact, entityCapsProvider, timerFactory, 20000);
@@ -359,6 +359,7 @@ void ChatController::setOnline(bool online) {
if (!online) {
for (auto& stanzaIdPair : unackedStanzas_) {
chatWindow_->setAckState(stanzaIdPair.second, ChatWindow::Failed);
+ failedStanzas_[stanzaIdPair.second] = stanzaIdPair.first;
}
unackedStanzas_.clear();
diff --git a/Swift/Controllers/Chat/ChatController.h b/Swift/Controllers/Chat/ChatController.h
index a9093d0..447e263 100644
--- a/Swift/Controllers/Chat/ChatController.h
+++ b/Swift/Controllers/Chat/ChatController.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2017 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -9,7 +9,6 @@
#include <map>
#include <string>
-#include <Swiften/Base/Override.h>
#include <Swiften/Base/Tristate.h>
#include <Swift/Controllers/Chat/ChatControllerBase.h>
@@ -31,42 +30,42 @@ namespace Swift {
class ChatController : public ChatControllerBase {
public:
- ChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency, UIEventStream* eventStream, TimerFactory* timerFactory, EventController* eventController, EntityCapsProvider* entityCapsProvider, bool userWantsReceipts, SettingsProvider* settings, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, std::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider);
- virtual ~ChatController();
- virtual void setToJID(const JID& jid) SWIFTEN_OVERRIDE;
- virtual void setAvailableServerFeatures(std::shared_ptr<DiscoInfo> info) SWIFTEN_OVERRIDE;
- virtual void setOnline(bool online) SWIFTEN_OVERRIDE;
+ ChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency, UIEventStream* eventStream, TimerFactory* timerFactory, EventController* eventController, EntityCapsProvider* entityCapsProvider, bool userWantsReceipts, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, std::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider, SettingsProvider* settings, Chattables& chattables);
+ virtual ~ChatController() override;
+ virtual void setToJID(const JID& jid) override;
+ virtual void setAvailableServerFeatures(std::shared_ptr<DiscoInfo> info) override;
+ virtual void setOnline(bool online) override;
virtual void handleNewFileTransferController(FileTransferController* ftc);
virtual void handleWhiteboardSessionRequest(bool senderIsSelf);
virtual void handleWhiteboardStateChange(const ChatWindow::WhiteboardSessionState state);
- virtual void setContactIsReceivingPresence(bool /*isReceivingPresence*/) SWIFTEN_OVERRIDE;
- virtual ChatWindow* detachChatWindow() SWIFTEN_OVERRIDE;
- virtual void handleIncomingOwnMessage(std::shared_ptr<Message> message) SWIFTEN_OVERRIDE;
+ virtual void setContactIsReceivingPresence(bool /*isReceivingPresence*/) override;
+ virtual ChatWindow* detachChatWindow() override;
+ virtual void handleIncomingOwnMessage(std::shared_ptr<Message> message) override;
protected:
- virtual void cancelReplaces() SWIFTEN_OVERRIDE;
- virtual JID getBaseJID() SWIFTEN_OVERRIDE;
- virtual void logMessage(const std::string& message, const JID& fromJID, const JID& toJID, const boost::posix_time::ptime& timeStamp, bool isIncoming) SWIFTEN_OVERRIDE;
- virtual bool shouldIgnoreMessage(std::shared_ptr<Message> message) SWIFTEN_OVERRIDE;
- virtual JID messageCorrectionJID(const JID& fromJID) SWIFTEN_OVERRIDE;
+ virtual void cancelReplaces() override;
+ virtual JID getBaseJID() override;
+ virtual void logMessage(const std::string& message, const JID& fromJID, const JID& toJID, const boost::posix_time::ptime& timeStamp, bool isIncoming) override;
+ virtual bool shouldIgnoreMessage(std::shared_ptr<Message> message) override;
+ virtual JID messageCorrectionJID(const JID& fromJID) override;
private:
void handlePresenceChange(std::shared_ptr<Presence> newPresence);
std::string getStatusChangeString(std::shared_ptr<Presence> presence);
- virtual bool isIncomingMessageFromMe(std::shared_ptr<Message> message) SWIFTEN_OVERRIDE;
- virtual void postSendMessage(const std::string &body, std::shared_ptr<Stanza> sentStanza) SWIFTEN_OVERRIDE;
- virtual void preHandleIncomingMessage(std::shared_ptr<MessageEvent> messageEvent) SWIFTEN_OVERRIDE;
- virtual void addMessageHandleIncomingMessage(const JID& from, const ChatWindow::ChatMessage& message, const std::string& messageID, bool senderIsSelf, std::shared_ptr<SecurityLabel> label, const boost::posix_time::ptime& timeStamp) SWIFTEN_OVERRIDE;
- virtual void handleIncomingReplaceMessage(const JID& from, const ChatWindow::ChatMessage& message, const std::string& messageID, const std::string& idToReplace, bool senderIsSelf, std::shared_ptr<SecurityLabel> label, const boost::posix_time::ptime& timeStamp) SWIFTEN_OVERRIDE;
- virtual void postHandleIncomingMessage(std::shared_ptr<MessageEvent> messageEvent, const ChatWindow::ChatMessage& chatMessage) SWIFTEN_OVERRIDE;
- virtual void preSendMessageRequest(std::shared_ptr<Message>) SWIFTEN_OVERRIDE;
- virtual std::string senderHighlightNameFromMessage(const JID& from) SWIFTEN_OVERRIDE;
- virtual std::string senderDisplayNameFromMessage(const JID& from) SWIFTEN_OVERRIDE;
- virtual boost::optional<boost::posix_time::ptime> getMessageTimestamp(std::shared_ptr<Message>) const SWIFTEN_OVERRIDE;
+ virtual bool isIncomingMessageFromMe(std::shared_ptr<Message> message) override;
+ virtual void postSendMessage(const std::string &body, std::shared_ptr<Stanza> sentStanza) override;
+ virtual void preHandleIncomingMessage(std::shared_ptr<MessageEvent> messageEvent) override;
+ virtual void addMessageHandleIncomingMessage(const JID& from, const ChatWindow::ChatMessage& message, const std::string& messageID, bool senderIsSelf, std::shared_ptr<SecurityLabel> label, const boost::posix_time::ptime& timeStamp) override;
+ virtual void handleIncomingReplaceMessage(const JID& from, const ChatWindow::ChatMessage& message, const std::string& messageID, const std::string& idToReplace, bool senderIsSelf, std::shared_ptr<SecurityLabel> label, const boost::posix_time::ptime& timeStamp) override;
+ virtual void postHandleIncomingMessage(std::shared_ptr<MessageEvent> messageEvent, const ChatWindow::ChatMessage& chatMessage) override;
+ virtual void preSendMessageRequest(std::shared_ptr<Message>) override;
+ virtual std::string senderHighlightNameFromMessage(const JID& from) override;
+ virtual std::string senderDisplayNameFromMessage(const JID& from) override;
+ virtual boost::optional<boost::posix_time::ptime> getMessageTimestamp(std::shared_ptr<Message>) const override;
void handleStanzaAcked(std::shared_ptr<Stanza> stanza);
- virtual void dayTicked() SWIFTEN_OVERRIDE { lastWasPresence_ = false; }
+ virtual void dayTicked() override { lastWasPresence_ = false; }
void handleContactNickChanged(const JID& jid, const std::string& /*oldNick*/);
- virtual void handleBareJIDCapsChanged(const JID& jid) SWIFTEN_OVERRIDE;
+ virtual void handleBareJIDCapsChanged(const JID& jid) override;
void handleFileTransferCancel(std::string /* id */);
void handleFileTransferStart(std::string /* id */, std::string /* description */);
@@ -97,15 +96,12 @@ namespace Swift {
std::string myLastMessageUIID_;
bool isInMUC_;
std::string lastStatusChangeString_;
- std::map<std::shared_ptr<Stanza>, std::string> unackedStanzas_;
- std::map<std::string, std::string> requestedReceipts_;
StatusShow::Type lastShownStatus_;
Tristate contactSupportsReceipts_;
bool receivingPresenceFromUs_ = false;
bool userWantsReceipts_;
std::map<std::string, FileTransferController*> ftControllers;
- SettingsProvider* settings_;
std::string lastWbID_;
std::string lastHandledMessageID_;
@@ -119,4 +115,3 @@ namespace Swift {
boost::optional<ChatWindow::AlertID> blockedContactAlert_;
};
}
-
diff --git a/Swift/Controllers/Chat/ChatControllerBase.cpp b/Swift/Controllers/Chat/ChatControllerBase.cpp
index 19bbf8d..3805084 100644
--- a/Swift/Controllers/Chat/ChatControllerBase.cpp
+++ b/Swift/Controllers/Chat/ChatControllerBase.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2017 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -20,11 +20,14 @@
#include <Swiften/Client/StanzaChannel.h>
#include <Swiften/Disco/EntityCapsProvider.h>
#include <Swiften/Elements/Delay.h>
+#include <Swiften/Elements/DeliveryReceipt.h>
+#include <Swiften/Elements/DeliveryReceiptRequest.h>
#include <Swiften/Elements/MUCInvitationPayload.h>
#include <Swiften/Elements/MUCUserPayload.h>
#include <Swiften/Queries/Requests/GetSecurityLabelsCatalogRequest.h>
#include <Swift/Controllers/Chat/AutoAcceptMUCInviteDecider.h>
+#include <Swift/Controllers/Chat/Chattables.h>
#include <Swift/Controllers/Chat/ChatMessageParser.h>
#include <Swift/Controllers/Highlighting/HighlightManager.h>
#include <Swift/Controllers/Highlighting/Highlighter.h>
@@ -38,11 +41,12 @@
namespace Swift {
-ChatControllerBase::ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, EntityCapsProvider* entityCapsProvider, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, std::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider) : selfJID_(self), stanzaChannel_(stanzaChannel), iqRouter_(iqRouter), chatWindowFactory_(chatWindowFactory), toJID_(toJID), labelsEnabled_(false), presenceOracle_(presenceOracle), avatarManager_(avatarManager), useDelayForLatency_(useDelayForLatency), eventController_(eventController), entityCapsProvider_(entityCapsProvider), historyController_(historyController), mucRegistry_(mucRegistry), chatMessageParser_(chatMessageParser), autoAcceptMUCInviteDecider_(autoAcceptMUCInviteDecider), eventStream_(eventStream) {
+ChatControllerBase::ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, EntityCapsProvider* entityCapsProvider, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, std::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider, SettingsProvider* settings, Chattables& chattables) : selfJID_(self), stanzaChannel_(stanzaChannel), iqRouter_(iqRouter), chatWindowFactory_(chatWindowFactory), toJID_(toJID), labelsEnabled_(false), presenceOracle_(presenceOracle), avatarManager_(avatarManager), useDelayForLatency_(useDelayForLatency), eventController_(eventController), entityCapsProvider_(entityCapsProvider), historyController_(historyController), mucRegistry_(mucRegistry), chatMessageParser_(chatMessageParser), autoAcceptMUCInviteDecider_(autoAcceptMUCInviteDecider), eventStream_(eventStream), roomSecurityMarking_(""), previousMessageSecurityMarking_(""), settings_(settings), chattables_(chattables) {
chatWindow_ = chatWindowFactory_->createChatWindow(toJID, eventStream);
chatWindow_->onAllMessagesRead.connect(boost::bind(&ChatControllerBase::handleAllMessagesRead, this));
chatWindow_->onSendMessageRequest.connect(boost::bind(&ChatControllerBase::handleSendMessageRequest, this, _1, _2));
chatWindow_->onContinuationsBroken.connect(boost::bind(&ChatControllerBase::handleContinuationsBroken, this));
+ scopedConnectionResendMessage_ = chatWindow_->onResendMessageRequest.connect(boost::bind(&ChatControllerBase::handleResendMessageRequest, this, _1));
entityCapsProvider_->onCapsChanged.connect(boost::bind(&ChatControllerBase::handleCapsChanged, this, _1));
highlighter_ = highlightManager->createHighlighter(nickResolver);
ChatControllerBase::setOnline(stanzaChannel->isAvailable() && iqRouter->isAvailable());
@@ -61,6 +65,7 @@ ChatWindow* ChatControllerBase::detachChatWindow() {
chatWindow_->onContinuationsBroken.disconnect(boost::bind(&ChatControllerBase::handleContinuationsBroken, this));
chatWindow_->onSendMessageRequest.disconnect(boost::bind(&ChatControllerBase::handleSendMessageRequest, this, _1, _2));
chatWindow_->onAllMessagesRead.disconnect(boost::bind(&ChatControllerBase::handleAllMessagesRead, this));
+ scopedConnectionResendMessage_.disconnect();
ChatWindow* chatWindow = chatWindow_;
chatWindow_ = nullptr;
return chatWindow;
@@ -113,8 +118,8 @@ void ChatControllerBase::handleAllMessagesRead() {
}
}
-int ChatControllerBase::getUnreadCount() {
- return boost::numeric_cast<int>(targetedUnreadMessages_.size());
+size_t ChatControllerBase::getUnreadCount() {
+ return targetedUnreadMessages_.size();
}
void ChatControllerBase::handleSendMessageRequest(const std::string &body, bool isCorrectionMessage) {
@@ -188,16 +193,44 @@ ChatWindow::ChatMessage ChatControllerBase::buildChatWindowChatMessage(const std
}
void ChatControllerBase::updateMessageCount() {
- chatWindow_->setUnreadMessageCount(boost::numeric_cast<int>(unreadMessages_.size()));
+ auto baseJID = getBaseJID();
+ auto state = chattables_.getState(baseJID);
+ state.unreadCount = unreadMessages_.size();
+ chatWindow_->setUnreadMessageCount(state.unreadCount);
+ chattables_.setState(baseJID, state);
+#ifndef NOT_YET
onUnreadCountChanged();
+#endif
}
std::string ChatControllerBase::addMessage(const ChatWindow::ChatMessage& chatMessage, const std::string& senderName, bool senderIsSelf, const std::shared_ptr<SecurityLabel> label, const boost::filesystem::path& avatarPath, const boost::posix_time::ptime& time) {
+ auto displayedLabel = label;
+
+ if (settings_->getSetting(SettingConstants::MUC_MARKING_ELISION)) {
+ if (roomSecurityMarking_ != "") {
+
+ if (label && label->getDisplayMarking() == roomSecurityMarking_) {
+ if (label->getDisplayMarking() == previousMessageSecurityMarking_) {
+ displayedLabel = std::make_shared<SecurityLabel>();
+ }
+ previousMessageSecurityMarking_ = label->getDisplayMarking();
+ }
+ else if (!label || label->getDisplayMarking().empty()) {
+ displayedLabel = std::make_shared<SecurityLabel>();
+ displayedLabel->setDisplayMarking("Unmarked");
+ previousMessageSecurityMarking_ = "Unmarked";
+ }
+ else {
+ previousMessageSecurityMarking_ = displayedLabel->getDisplayMarking();
+ }
+ }
+ }
+
if (chatMessage.isMeCommand()) {
- return chatWindow_->addAction(chatMessage, senderName, senderIsSelf, label, pathToString(avatarPath), time);
+ return chatWindow_->addAction(chatMessage, senderName, senderIsSelf, displayedLabel, pathToString(avatarPath), time);
}
else {
- return chatWindow_->addMessage(chatMessage, senderName, senderIsSelf, label, pathToString(avatarPath), time);
+ return chatWindow_->addMessage(chatMessage, senderName, senderIsSelf, displayedLabel, pathToString(avatarPath), time);
}
}
@@ -287,7 +320,9 @@ void ChatControllerBase::handleIncomingMessage(std::shared_ptr<MessageEvent> mes
addMessageHandleIncomingMessage(from, chatMessage, message->getID(), senderIsSelf, label, timeStamp);
}
+#ifdef SWIFT_EXPERIMENTAL_HISTORY
logMessage(body, from, selfJID_, timeStamp, true);
+#endif
}
chatWindow_->show();
updateMessageCount();
@@ -342,7 +377,7 @@ void ChatControllerBase::handleMUCInvitation(Message::ref message) {
MUCInvitationPayload::ref invite = message->getPayload<MUCInvitationPayload>();
if (autoAcceptMUCInviteDecider_->isAutoAcceptedInvite(message->getFrom(), invite)) {
- eventStream_->send(std::make_shared<JoinMUCUIEvent>(invite->getJID(), boost::optional<std::string>(), boost::optional<std::string>(), false, false, true));
+ eventStream_->send(std::make_shared<JoinMUCUIEvent>(invite->getJID(), boost::optional<std::string>(), boost::optional<std::string>(), false, true));
} else {
MUCInviteEvent::ref inviteEvent = std::make_shared<MUCInviteEvent>(toJID_, invite->getJID(), invite->getReason(), invite->getPassword(), true, invite->getIsImpromptu());
handleGeneralMUCInvitation(inviteEvent);
@@ -365,4 +400,22 @@ void ChatControllerBase::handleMediatedMUCInvitation(Message::ref message) {
handleGeneralMUCInvitation(inviteEvent);
}
+void ChatControllerBase::handleResendMessageRequest(const std::string& id) {
+ if (failedStanzas_.find(id) != failedStanzas_.end()) {
+ if (auto resendMsg = std::dynamic_pointer_cast<Message>(failedStanzas_[id])) {
+ stanzaChannel_->sendMessage(resendMsg);
+ if (stanzaChannel_->getStreamManagementEnabled()) {
+ chatWindow_->setAckState(id, ChatWindow::Pending);
+ unackedStanzas_[failedStanzas_[id]] = id;
+ }
+ if (resendMsg->getPayload<DeliveryReceiptRequest>()) {
+ requestedReceipts_[resendMsg->getID()] = id;
+ chatWindow_->setMessageReceiptState(id, ChatWindow::ReceiptRequested);
+ }
+ lastWasPresence_ = false;
+ failedStanzas_.erase(id);
+ }
+ }
+}
+
}
diff --git a/Swift/Controllers/Chat/ChatControllerBase.h b/Swift/Controllers/Chat/ChatControllerBase.h
index 88cb95c..92c6175 100644
--- a/Swift/Controllers/Chat/ChatControllerBase.h
+++ b/Swift/Controllers/Chat/ChatControllerBase.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2017 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -28,6 +28,7 @@
#include <Swift/Controllers/Highlighting/HighlightManager.h>
#include <Swift/Controllers/HistoryController.h>
+#include <Swift/Controllers/Settings/SettingsProvider.h>
#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
#include <Swift/Controllers/XMPPEvents/MUCInviteEvent.h>
#include <Swift/Controllers/XMPPEvents/MessageEvent.h>
@@ -36,11 +37,12 @@ namespace Swift {
class AutoAcceptMUCInviteDecider;
class AvatarManager;
class ChatMessageParser;
+ class Chattables;
class ChatWindowFactory;
class EntityCapsProvider;
class EventController;
- class HighlightManager;
class Highlighter;
+ class HighlightManager;
class IQRouter;
class NickResolver;
class StanzaChannel;
@@ -71,7 +73,7 @@ namespace Swift {
boost::signals2::signal<void (const std::string& /*activity*/)> onActivity;
boost::signals2::signal<void ()> onUnreadCountChanged;
boost::signals2::signal<void ()> onWindowClosed;
- int getUnreadCount();
+ size_t getUnreadCount();
const JID& getToJID() {return toJID_;}
void handleCapsChanged(const JID& jid);
void setCanStartImpromptuChats(bool supportsImpromptu);
@@ -79,7 +81,7 @@ namespace Swift {
boost::signals2::signal<void(ChatWindow* /*window to reuse*/, const std::vector<JID>& /*invite people*/, const std::string& /*reason*/)> onConvertToMUC;
protected:
- ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, EntityCapsProvider* entityCapsProvider, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, std::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider);
+ ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, EntityCapsProvider* entityCapsProvider, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, std::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider, SettingsProvider* settings, Chattables& chattables);
/**
* Pass the Message appended, and the stanza used to send it.
@@ -113,6 +115,7 @@ namespace Swift {
* What JID should be used for last message correction (XEP-0308) tracking.
*/
virtual JID messageCorrectionJID(const JID& fromJID) = 0;
+ virtual void handleResendMessageRequest(const std::string& id);
private:
IDGenerator idGenerator_;
@@ -150,5 +153,13 @@ namespace Swift {
AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider_;
UIEventStream* eventStream_;
bool lastWasPresence_ = false;
+ std::string roomSecurityMarking_;
+ std::string previousMessageSecurityMarking_;
+ SettingsProvider* settings_;
+ boost::signals2::scoped_connection scopedConnectionResendMessage_;
+ std::map<std::string, std::string> requestedReceipts_;
+ std::map<std::shared_ptr<Stanza>, std::string> unackedStanzas_;
+ std::map<std::string, std::shared_ptr<Stanza>> failedStanzas_;
+ Chattables& chattables_;
};
}
diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp
index 19400f9..6530a7e 100644
--- a/Swift/Controllers/Chat/ChatsManager.cpp
+++ b/Swift/Controllers/Chat/ChatsManager.cpp
@@ -34,6 +34,7 @@
#include <Swiften/VCards/VCardManager.h>
#include <Swift/Controllers/Chat/AutoAcceptMUCInviteDecider.h>
+#include <Swift/Controllers/Chat/Chattables.h>
#include <Swift/Controllers/Chat/ChatController.h>
#include <Swift/Controllers/Chat/ChatControllerBase.h>
#include <Swift/Controllers/Chat/ChatListWindowChatBoostSerialize.h>
@@ -66,7 +67,9 @@ namespace Swift {
typedef std::pair<JID, ChatController*> JIDChatControllerPair;
typedef std::pair<JID, MUCController*> JIDMUCControllerPair;
+#ifndef NOT_YET
#define RECENT_CHATS "recent_chats"
+#endif
ChatsManager::ChatsManager(
JID jid, StanzaChannel* stanzaChannel,
@@ -78,7 +81,9 @@ ChatsManager::ChatsManager(
PresenceOracle* presenceOracle,
PresenceSender* presenceSender,
UIEventStream* uiEventStream,
+#ifndef NOT_YET
ChatListWindowFactory* chatListWindowFactory,
+#endif
bool useDelayForLatency,
TimerFactory* timerFactory,
MUCRegistry* mucRegistry,
@@ -95,7 +100,8 @@ ChatsManager::ChatsManager(
HighlightManager* highlightManager,
ClientBlockListManager* clientBlockListManager,
const std::map<std::string, std::string>& emoticons,
- VCardManager* vcardManager) :
+ VCardManager* vcardManager,
+ Chattables& chattables) :
jid_(jid),
joinMUCWindowFactory_(joinMUCWindowFactory),
useDelayForLatency_(useDelayForLatency),
@@ -111,7 +117,8 @@ ChatsManager::ChatsManager(
highlightManager_(highlightManager),
emoticons_(emoticons),
clientBlockListManager_(clientBlockListManager),
- vcardManager_(vcardManager) {
+ vcardManager_(vcardManager),
+ chattables_(chattables) {
timerFactory_ = timerFactory;
eventController_ = eventController;
stanzaChannel_ = stanzaChannel;
@@ -127,12 +134,12 @@ ChatsManager::ChatsManager(
profileSettings_ = profileSettings;
presenceOracle_->onPresenceChange.connect(boost::bind(&ChatsManager::handlePresenceChange, this, _1));
uiEventConnection_ = uiEventStream_->onUIEvent.connect(boost::bind(&ChatsManager::handleUIEvent, this, _1));
-
+#ifndef NOT_YET
chatListWindow_ = chatListWindowFactory->createChatListWindow(uiEventStream_);
chatListWindow_->onMUCBookmarkActivated.connect(boost::bind(&ChatsManager::handleMUCBookmarkActivated, this, _1));
chatListWindow_->onRecentActivated.connect(boost::bind(&ChatsManager::handleRecentActivated, this, _1));
chatListWindow_->onClearRecentsRequested.connect(boost::bind(&ChatsManager::handleClearRecentsRequested, this));
-
+#endif
joinMUCWindow_ = nullptr;
mucSearchController_ = new MUCSearchController(jid_, mucSearchWindowFactory, iqRouter, profileSettings_);
mucSearchController_->onMUCSelected.connect(boost::bind(&ChatsManager::handleMUCSelectedAfterSearch, this, _1));
@@ -146,18 +153,22 @@ ChatsManager::ChatsManager(
roster_->onJIDUpdated.connect(boost::bind(&ChatsManager::handleJIDUpdatedInRoster, this, _1));
roster_->onRosterCleared.connect(boost::bind(&ChatsManager::handleRosterCleared, this));
+ chattables_.onActivated.connect(boost::bind(&ChatsManager::handleChattableActivated, this, _1));
+
settings_->onSettingChanged.connect(boost::bind(&ChatsManager::handleSettingChanged, this, _1));
userWantsReceipts_ = settings_->getSetting(SettingConstants::REQUEST_DELIVERYRECEIPTS);
setupBookmarks();
+#ifndef NOT_YET
loadRecents();
-
+#endif
autoAcceptMUCInviteDecider_ = new AutoAcceptMUCInviteDecider(jid.getDomain(), roster_, settings_);
}
ChatsManager::~ChatsManager() {
settings_->onSettingChanged.disconnect(boost::bind(&ChatsManager::handleSettingChanged, this, _1));
+ chattables_.onActivated.disconnect(boost::bind(&ChatsManager::handleChattableActivated, this, _1));
roster_->onJIDAdded.disconnect(boost::bind(&ChatsManager::handleJIDAddedToRoster, this, _1));
roster_->onJIDRemoved.disconnect(boost::bind(&ChatsManager::handleJIDRemovedFromRoster, this, _1));
roster_->onJIDUpdated.disconnect(boost::bind(&ChatsManager::handleJIDUpdatedInRoster, this, _1));
@@ -176,6 +187,7 @@ ChatsManager::~ChatsManager() {
delete autoAcceptMUCInviteDecider_;
}
+#ifndef NOT_YET
void ChatsManager::saveRecents() {
std::stringstream serializeStream;
boost::archive::text_oarchive oa(serializeStream);
@@ -208,6 +220,7 @@ void ChatsManager::handleClearRecentsRequested() {
saveRecents();
handleUnreadCountChanged(nullptr);
}
+#endif
void ChatsManager::handleJIDAddedToRoster(const JID &jid) {
updatePresenceReceivingStateOnChatController(jid);
@@ -242,6 +255,7 @@ void ChatsManager::updatePresenceReceivingStateOnChatController(const JID &jid)
}
}
+#ifndef NOT_YET
ChatListWindow::Chat ChatsManager::updateChatStatusAndAvatarHelper(const ChatListWindow::Chat& chat) const {
ChatListWindow::Chat fixedChat = chat;
if (fixedChat.isMUC) {
@@ -309,6 +323,7 @@ void ChatsManager::loadRecents() {
}
handleUnreadCountChanged(nullptr);
}
+#endif
void ChatsManager::setupBookmarks() {
if (!mucBookmarkManager_) {
@@ -317,35 +332,47 @@ void ChatsManager::setupBookmarks() {
mucBookmarkManager_->onBookmarkAdded.connect(boost::bind(&ChatsManager::handleMUCBookmarkAdded, this, _1));
mucBookmarkManager_->onBookmarkRemoved.connect(boost::bind(&ChatsManager::handleMUCBookmarkRemoved, this, _1));
+#ifndef NOT_YET
if (chatListWindow_) {
chatListWindow_->setBookmarksEnabled(false);
chatListWindow_->clearBookmarks();
}
+#endif
}
}
void ChatsManager::handleBookmarksReady() {
+#ifndef NOT_YET
if (chatListWindow_) {
chatListWindow_->setBookmarksEnabled(true);
}
+#endif
}
void ChatsManager::handleMUCBookmarkAdded(const MUCBookmark& bookmark) {
if (bookmark.getRoom().isBare() && !bookmark.getRoom().getNode().empty()) {
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, false );
+ handleJoinMUCRequest(bookmark.getRoom(), bookmark.getPassword(), bookmark.getNick(), false, false);
}
+#ifndef NOT_YET
+ //Only one entry of the bookmark should exist
+ chatListWindow_->removeMUCBookmark(bookmark);
chatListWindow_->addMUCBookmark(bookmark);
+#endif
+ chattables_.addJID(bookmark.getRoom(), Chattables::State::Type::Room);
}
}
void ChatsManager::handleMUCBookmarkRemoved(const MUCBookmark& bookmark) {
+#ifndef NOT_YET
chatListWindow_->removeMUCBookmark(bookmark);
+#endif
}
+#ifndef NOT_YET
ChatListWindow::Chat ChatsManager::createChatListChatItem(const JID& jid, const std::string& activity, bool privateMessage) {
- int unreadCount = 0;
+ size_t unreadCount = 0;
if (mucRegistry_->isMUC(jid)) {
MUCController* controller = mucControllers_[jid.toBare()];
StatusShow::Type type = StatusShow::None;
@@ -388,8 +415,10 @@ ChatListWindow::Chat ChatsManager::createChatListChatItem(const JID& jid, const
return ChatListWindow::Chat(bareishJID, nickResolver_->jidToNick(bareishJID), activity, unreadCount, type, avatarPath, false, privateMessage);
}
}
+#endif
void ChatsManager::handleChatActivity(const JID& jid, const std::string& activity, bool isMUC) {
+#ifndef NOT_YET
const bool privateMessage = mucRegistry_->isMUC(jid.toBare()) && !isMUC;
ChatListWindow::Chat chat = createChatListChatItem(jid, activity, privateMessage);
/* FIXME: handle nick changes */
@@ -405,15 +434,20 @@ void ChatsManager::handleChatActivity(const JID& jid, const std::string& activit
mucControllers_[jid]->setChatWindowTitle(chatListWindowIter->getTitle());
}
}
+#endif
}
void ChatsManager::handleChatClosed(const JID& /*jid*/) {
cleanupPrivateMessageRecents();
+#ifndef NOT_YET
chatListWindow_->setRecents(recentChats_);
+#endif
}
+#ifndef NOT_YET
+
void ChatsManager::handleUnreadCountChanged(ChatControllerBase* controller) {
- int unreadTotal = 0;
+ size_t unreadTotal = 0;
bool controllerIsMUC = dynamic_cast<MUCController*>(controller);
bool isPM = controller && !controllerIsMUC && mucRegistry_->isMUC(controller->getToJID().toBare());
for (ChatListWindow::Chat& chatItem : recentChats_) {
@@ -445,7 +479,9 @@ boost::optional<ChatListWindow::Chat> ChatsManager::removeExistingChat(const Cha
return boost::optional<ChatListWindow::Chat>();
}
}
+#endif
+#ifndef NOT_YET
void ChatsManager::cleanupPrivateMessageRecents() {
/* if we leave a MUC and close a PM, remove it's recent chat entry */
const std::list<ChatListWindow::Chat> chats = recentChats_;
@@ -483,23 +519,38 @@ void ChatsManager::prependRecent(const ChatListWindow::Chat& chat) {
}
recentChats_.push_back(mergedChat);
}
+#endif
void ChatsManager::handleUserLeftMUC(MUCController* mucController) {
std::map<JID, MUCController*>::iterator it;
for (it = mucControllers_.begin(); it != mucControllers_.end(); ++it) {
if ((*it).second == mucController) {
+#ifndef NOT_YET
for (ChatListWindow::Chat& chat : recentChats_) {
if (chat.isMUC && chat.jid == (*it).first) {
chat.statusType = StatusShow::None;
}
}
+#endif
+ const auto& jid = it->first;
+ auto state = chattables_.getState(jid);
+ state.status = StatusShow::None;
+ chattables_.setState(jid, state);
+ //If user deletes bookmark from chatListWindow_ and then decides to leave the room, or if the server doesn't support bookmarks, the bookmark will not exist.
+ if (auto bookmarkFound = mucBookmarkManager_->lookupBookmark(jid)) {
+ MUCBookmark newBookmark(bookmarkFound.get());
+ newBookmark.setAutojoin(false);
+ mucBookmarkManager_->replaceBookmark(bookmarkFound.get(), newBookmark);
+ }
mucControllers_.erase(it);
delete mucController;
break;
}
}
cleanupPrivateMessageRecents();
+#ifndef NOT_YET
chatListWindow_->setRecents(recentChats_);
+#endif
}
void ChatsManager::handleSettingChanged(const std::string& settingPath) {
@@ -576,7 +627,7 @@ void ChatsManager::handleUIEvent(std::shared_ptr<UIEvent> event) {
invitees_[roomJID].insert(jid);
}
// join muc
- MUC::ref muc = handleJoinMUCRequest(roomJID, boost::optional<std::string>(), nickResolver_->jidToNick(jid_), false, true, true);
+ MUC::ref muc = handleJoinMUCRequest(roomJID, boost::optional<std::string>(), nickResolver_->jidToNick(jid_), true, true);
mucControllers_[roomJID]->onImpromptuConfigCompleted.connect(boost::bind(&ChatsManager::finalizeImpromptuJoin, this, muc, createImpromptuMUCEvent->getJIDs(), createImpromptuMUCEvent->getReason(), boost::optional<JID>()));
mucControllers_[roomJID]->activateChatWindow();
}
@@ -586,7 +637,7 @@ void ChatsManager::handleUIEvent(std::shared_ptr<UIEvent> event) {
mucBookmarkManager_->replaceBookmark(editMUCBookmarkEvent->getOldBookmark(), editMUCBookmarkEvent->getNewBookmark());
}
else if (JoinMUCUIEvent::ref joinEvent = std::dynamic_pointer_cast<JoinMUCUIEvent>(event)) {
- handleJoinMUCRequest(joinEvent->getJID(), joinEvent->getPassword(), joinEvent->getNick(), joinEvent->getShouldJoinAutomatically(), joinEvent->getCreateAsReservedRoomIfNew(), joinEvent->isImpromptu());
+ handleJoinMUCRequest(joinEvent->getJID(), joinEvent->getPassword(), joinEvent->getNick(), joinEvent->getCreateAsReservedRoomIfNew(), joinEvent->isImpromptu());
mucControllers_[joinEvent->getJID()]->activateChatWindow();
}
else if (std::shared_ptr<RequestJoinMUCUIEvent> joinEvent = std::dynamic_pointer_cast<RequestJoinMUCUIEvent>(event)) {
@@ -600,6 +651,7 @@ void ChatsManager::handleUIEvent(std::shared_ptr<UIEvent> event) {
}
}
+#ifndef NOT_YET
void ChatsManager::markAllRecentsOffline() {
for (ChatListWindow::Chat& chat : recentChats_) {
chat.setStatusType(StatusShow::None);
@@ -607,6 +659,7 @@ void ChatsManager::markAllRecentsOffline() {
chatListWindow_->setRecents(recentChats_);
}
+#endif
void ChatsManager::handleTransformChatToMUC(ChatController* chatController, ChatWindow* chatWindow, const std::vector<JID>& jidsToInvite, const std::string& reason) {
JID reuseChatInvite = chatController->getToJID();
@@ -620,7 +673,7 @@ void ChatsManager::handleTransformChatToMUC(ChatController* chatController, Chat
JID roomJID = JID(idGenerator_.generateID(), localMUCServiceJID_);
// join muc
- MUC::ref muc = handleJoinMUCRequest(roomJID, boost::optional<std::string>(), nickResolver_->jidToNick(jid_), false, true, true, chatWindow);
+ MUC::ref muc = handleJoinMUCRequest(roomJID, boost::optional<std::string>(), nickResolver_->jidToNick(jid_), true, true, chatWindow);
mucControllers_[roomJID]->onImpromptuConfigCompleted.connect(boost::bind(&ChatsManager::finalizeImpromptuJoin, this, muc, jidsToInvite, reason, boost::optional<JID>(reuseChatInvite)));
}
@@ -629,7 +682,7 @@ void ChatsManager::handleTransformChatToMUC(ChatController* chatController, Chat
*/
void ChatsManager::handlePresenceChange(std::shared_ptr<Presence> newPresence) {
if (mucRegistry_->isMUC(newPresence->getFrom().toBare())) return;
-
+#ifndef NOT_YET
for (ChatListWindow::Chat& chat : recentChats_) {
if (newPresence->getFrom().toBare() == chat.jid.toBare() && !chat.isMUC) {
Presence::ref presence = presenceOracle_->getHighestPriorityPresence(chat.jid.toBare());
@@ -638,8 +691,9 @@ void ChatsManager::handlePresenceChange(std::shared_ptr<Presence> newPresence) {
break;
}
}
-
+#endif
//if (newPresence->getType() != Presence::Unavailable) return;
+
JID fullJID(newPresence->getFrom());
std::map<JID, ChatController*>::iterator it = chatControllers_.find(fullJID);
if (it == chatControllers_.end()) return;
@@ -654,21 +708,25 @@ void ChatsManager::setAvatarManager(AvatarManager* avatarManager) {
avatarManager_->onAvatarChanged.disconnect(boost::bind(&ChatsManager::handleAvatarChanged, this, _1));
}
avatarManager_ = avatarManager;
+#ifndef NOT_YET
for (ChatListWindow::Chat& chat : recentChats_) {
if (!chat.isMUC) {
chat.setAvatarPath(avatarManager_->getAvatarPath(chat.jid));
}
}
+#endif
avatarManager_->onAvatarChanged.connect(boost::bind(&ChatsManager::handleAvatarChanged, this, _1));
}
void ChatsManager::handleAvatarChanged(const JID& jid) {
+#ifndef NOT_YET
for (ChatListWindow::Chat& chat : recentChats_) {
if (!chat.isMUC && jid.toBare() == chat.jid.toBare()) {
chat.setAvatarPath(avatarManager_->getAvatarPath(jid));
break;
}
}
+#endif
}
void ChatsManager::setServerDiscoInfo(std::shared_ptr<DiscoInfo> info) {
@@ -705,10 +763,11 @@ void ChatsManager::setOnline(bool enabled) {
localMUCServiceFinderWalker_->onWalkComplete.connect(boost::bind(&ChatsManager::handleLocalServiceWalkFinished, this));
localMUCServiceFinderWalker_->beginWalk();
}
-
+#ifndef NOT_YET
if (chatListWindow_) {
chatListWindow_->setBookmarksEnabled(enabled);
}
+#endif
}
void ChatsManager::handleChatRequest(const std::string &contact) {
@@ -732,12 +791,14 @@ ChatController* ChatsManager::getChatControllerOrFindAnother(const JID &contact)
ChatController* ChatsManager::createNewChatController(const JID& contact) {
assert(chatControllers_.find(contact) == chatControllers_.end());
std::shared_ptr<ChatMessageParser> chatMessageParser = std::make_shared<ChatMessageParser>(emoticons_, highlightManager_->getConfiguration(), ChatMessageParser::Mode::Chat); /* a message parser that knows this is a chat (not a room/MUC) */
- ChatController* controller = new ChatController(jid_, stanzaChannel_, iqRouter_, chatWindowFactory_, contact, nickResolver_, presenceOracle_, avatarManager_, mucRegistry_->isMUC(contact.toBare()), useDelayForLatency_, uiEventStream_, timerFactory_, eventController_, entityCapsProvider_, userWantsReceipts_, settings_, historyController_, mucRegistry_, highlightManager_, clientBlockListManager_, chatMessageParser, autoAcceptMUCInviteDecider_);
+ auto controller = new ChatController(jid_, stanzaChannel_, iqRouter_, chatWindowFactory_, contact, nickResolver_, presenceOracle_, avatarManager_, mucRegistry_->isMUC(contact.toBare()), useDelayForLatency_, uiEventStream_, timerFactory_, eventController_, entityCapsProvider_, userWantsReceipts_, historyController_, mucRegistry_, highlightManager_, clientBlockListManager_, chatMessageParser, autoAcceptMUCInviteDecider_, settings_, chattables_);
chatControllers_[contact] = controller;
controller->setAvailableServerFeatures(serverDiscoInfo_);
controller->onActivity.connect(boost::bind(&ChatsManager::handleChatActivity, this, contact, _1, false));
controller->onWindowClosed.connect(boost::bind(&ChatsManager::handleChatClosed, this, contact));
+#ifndef NOT_YET
controller->onUnreadCountChanged.connect(boost::bind(&ChatsManager::handleUnreadCountChanged, this, controller));
+#endif
controller->onConvertToMUC.connect(boost::bind(&ChatsManager::handleTransformChatToMUC, this, controller, _1, _2, _3));
updatePresenceReceivingStateOnChatController(contact);
controller->setCanStartImpromptuChats(!localMUCServiceJID_.toString().empty());
@@ -786,20 +847,8 @@ void ChatsManager::rebindControllerJID(const JID& from, const JID& to) {
chatControllers_[to]->setToJID(to);
}
-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 ChatsManager::handleJoinMUCRequest(const JID &mucJID, const boost::optional<std::string>& password, const boost::optional<std::string>& nickMaybe, bool createAsReservedIfNew, bool isImpromptu, ChatWindow* reuseChatwindow) {
MUC::ref muc;
- if (addAutoJoin) {
- MUCBookmark bookmark(mucJID, mucJID.getNode());
- bookmark.setAutojoin(true);
- if (nickMaybe) {
- bookmark.setNick(*nickMaybe);
- }
- if (password) {
- bookmark.setPassword(*password);
- }
- mucBookmarkManager_->addBookmark(bookmark);
- }
-
std::map<JID, MUCController*>::iterator it = mucControllers_.find(mucJID);
if (it != mucControllers_.end()) {
if (stanzaChannel_->isAvailable()) {
@@ -821,7 +870,11 @@ MUC::ref ChatsManager::handleJoinMUCRequest(const JID &mucJID, const boost::opti
chatWindowFactoryAdapter = new SingleChatWindowFactoryAdapter(reuseChatwindow);
}
std::shared_ptr<ChatMessageParser> chatMessageParser = std::make_shared<ChatMessageParser>(emoticons_, highlightManager_->getConfiguration(), ChatMessageParser::Mode::GroupChat); /* a message parser that knows this is a room/MUC (not a chat) */
- controller = new MUCController(jid_, muc, password, nick, stanzaChannel_, iqRouter_, reuseChatwindow ? chatWindowFactoryAdapter : chatWindowFactory_, nickResolver_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory_, eventController_, entityCapsProvider_, roster_, historyController_, mucRegistry_, highlightManager_, clientBlockListManager_, chatMessageParser, isImpromptu, autoAcceptMUCInviteDecider_, vcardManager_, mucBookmarkManager_);
+ controller = new MUCController(jid_, muc, password, nick, stanzaChannel_, iqRouter_, reuseChatwindow ? chatWindowFactoryAdapter : chatWindowFactory_, nickResolver_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory_, eventController_, entityCapsProvider_, roster_, historyController_, mucRegistry_, highlightManager_, clientBlockListManager_, chatMessageParser, isImpromptu, autoAcceptMUCInviteDecider_, vcardManager_, mucBookmarkManager_, settings_, chattables_);
+ chattables_.addJID(muc->getJID(), Chattables::State::Type::Room);
+ auto state = chattables_.getState(muc->getJID());
+ state.status = StatusShow::Online;
+ chattables_.setState(muc->getJID(), state);
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
@@ -835,7 +888,9 @@ MUC::ref ChatsManager::handleJoinMUCRequest(const JID &mucJID, const boost::opti
controller->onUserJoined.connect(boost::bind(&ChatsManager::handleChatActivity, this, mucJID.toBare(), "", true));
controller->onUserNicknameChanged.connect(boost::bind(&ChatsManager::handleUserNicknameChanged, this, controller, _1, _2));
controller->onActivity.connect(boost::bind(&ChatsManager::handleChatActivity, this, mucJID.toBare(), _1, true));
- controller->onUnreadCountChanged.connect(boost::bind(&ChatsManager::handleUnreadCountChanged, this, controller));
+#ifndef NOT_YET
+ controller->onUnreadCountChanged.connect(boost::bind(&ChatsManager::handleUnreadCountChanged, this, controller));
+#endif
if (!stanzaChannel_->isAvailable()) {
/* When online, the MUC is added to the registry in MUCImpl::internalJoin. This method is not
* called when Swift is offline, so we add it here as only MUCs in the registry are rejoined
@@ -845,12 +900,30 @@ MUC::ref ChatsManager::handleJoinMUCRequest(const JID &mucJID, const boost::opti
}
handleChatActivity(mucJID.toBare(), "", true);
}
-
+#ifndef NOT_YET
auto chatListWindowIter = std::find_if(recentChats_.begin(), recentChats_.end(), [&](const ChatListWindow::Chat& chatListWindow) { return mucJID == (chatListWindow.jid); });
if (chatListWindowIter != recentChats_.end() && (mucControllers_[mucJID]->isImpromptu() || !chatListWindowIter->impromptuJIDs.empty())) {
mucControllers_[mucJID]->setChatWindowTitle(chatListWindowIter->getTitle());
}
-
+#endif
+ if (auto existingBookmark = mucBookmarkManager_->lookupBookmark(mucJID)) {
+ if (!existingBookmark->getAutojoin()) {
+ MUCBookmark newbookmark(existingBookmark.get());
+ newbookmark.setAutojoin(true);
+ mucBookmarkManager_->replaceBookmark(*existingBookmark, newbookmark);
+ }
+ }
+ else {
+ MUCBookmark bookmark(mucJID, mucJID.getNode());
+ bookmark.setAutojoin(true);
+ if (nickMaybe) {
+ bookmark.setNick(*nickMaybe);
+ }
+ if (password) {
+ bookmark.setPassword(*password);
+ }
+ mucBookmarkManager_->addBookmark(bookmark);
+ }
mucControllers_[mucJID]->showChatWindow();
return muc;
}
@@ -960,11 +1033,11 @@ void ChatsManager::handleIncomingMessage(std::shared_ptr<Message> incomingMessag
ChatWindow* window = controller->detachChatWindow();
chatControllers_.erase(fromJID);
delete controller;
- handleJoinMUCRequest(invite->getJID(), boost::optional<std::string>(), boost::optional<std::string>(), false, false, true, window);
+ handleJoinMUCRequest(invite->getJID(), boost::optional<std::string>(), boost::optional<std::string>(), false, true, window);
return;
}
} else {
- handleJoinMUCRequest(invite->getJID(), boost::optional<std::string>(), boost::optional<std::string>(), false, false, true);
+ handleJoinMUCRequest(invite->getJID(), boost::optional<std::string>(), boost::optional<std::string>(), false, true);
return;
}
}
@@ -1023,7 +1096,7 @@ void ChatsManager::handleWhiteboardStateChange(const JID& contact, const ChatWin
chatListWindow_->removeWhiteboardSession(contact.toBare());
}
}
-
+#ifndef NOT_YET
void ChatsManager::handleRecentActivated(const ChatListWindow::Chat& chat) {
if (chat.isMUC && !chat.impromptuJIDs.empty()) {
typedef std::pair<std::string, JID> StringJIDPair;
@@ -1036,13 +1109,30 @@ void ChatsManager::handleRecentActivated(const ChatListWindow::Chat& chat) {
else if (chat.isMUC) {
bool isImpromptu = (!chat.inviteesNames.empty() || !chat.impromptuJIDs.empty());
/* FIXME: This means that recents requiring passwords will just flat-out not work */
- uiEventStream_->send(std::make_shared<JoinMUCUIEvent>(chat.jid, boost::optional<std::string>(), chat.nick, false, false, isImpromptu));
+ uiEventStream_->send(std::make_shared<JoinMUCUIEvent>(chat.jid, boost::optional<std::string>(), chat.nick, false, isImpromptu));
}
else {
uiEventStream_->send(std::make_shared<RequestChatUIEvent>(chat.jid));
}
}
+#endif
+
+void ChatsManager::handleChattableActivated(const JID& jid) {
+ auto state = chattables_.getState(jid);
+ if (state.type == Chattables::State::Type::Person) {
+ uiEventStream_->send(std::make_shared<RequestChatUIEvent>(jid));
+ }
+ else if (state.type == Chattables::State::Type::Room) {
+ if (auto foundBookmark = mucBookmarkManager_->lookupBookmark(jid)) {
+ handleMUCBookmarkActivated(foundBookmark.get());
+ }
+ else {
+ uiEventStream_->send(std::make_shared<JoinMUCUIEvent>(jid, boost::optional<std::string>(), boost::optional<std::string>())); // Just a quick hack to reuse already open MUCs
+ }
+ }
+}
+
void ChatsManager::handleLocalServiceFound(const JID& service, std::shared_ptr<DiscoInfo> info) {
for (DiscoInfo::Identity identity : info->getIdentities()) {
if ((identity.getCategory() == "directory"
@@ -1068,17 +1158,21 @@ void ChatsManager::handleLocalServiceWalkFinished() {
onImpromptuMUCServiceDiscovered(impromptuMUCSupported);
}
+#ifndef NOT_YET
std::vector<ChatListWindow::Chat> ChatsManager::getRecentChats() const {
return std::vector<ChatListWindow::Chat>(recentChats_.begin(), recentChats_.end());
}
+#endif
std::vector<Contact::ref> Swift::ChatsManager::getContacts(bool withMUCNicks) {
std::vector<Contact::ref> result;
+#ifndef NOT_YET
for (ChatListWindow::Chat chat : recentChats_) {
if (!chat.isMUC) {
result.push_back(std::make_shared<Contact>(chat.chatName.empty() ? chat.jid.toString() : chat.chatName, chat.jid, chat.statusType, chat.avatarPath));
}
}
+#endif
if (withMUCNicks) {
/* collect MUC nicks */
typedef std::map<JID, MUCController*>::value_type Item;
diff --git a/Swift/Controllers/Chat/ChatsManager.h b/Swift/Controllers/Chat/ChatsManager.h
index 6004347..e120831 100644
--- a/Swift/Controllers/Chat/ChatsManager.h
+++ b/Swift/Controllers/Chat/ChatsManager.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -27,49 +27,52 @@
#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h>
namespace Swift {
- class EventController;
+ class AutoAcceptMUCInviteDecider;
+ class AvatarManager;
class ChatController;
class ChatControllerBase;
- class MUCController;
- class MUCManager;
+ class ChatListWindowFactory;
+ class ChatMessageParser;
+ class Chattables;
+ class ClientBlockListManager;
+ class DirectedPresenceSender;
+ class DiscoServiceWalker;
+ class EntityCapsProvider;
+ class EventController;
+ class FileTransferController;
+ class FileTransferOverview;
+ class HighlightManager;
+ class HistoryController;
+ class IQRouter;
class JoinMUCWindow;
class JoinMUCWindowFactory;
+ class MUCBookmarkManager;
+ class MUCController;
+ class MUCManager;
+ class MUCSearchController;
+ class MUCSearchWindowFactory;
class NickResolver;
class PresenceOracle;
- class AvatarManager;
- class StanzaChannel;
- class IQRouter;
class PresenceSender;
- class MUCBookmarkManager;
- class ChatListWindowFactory;
- class TimerFactory;
- class EntityCapsProvider;
- class DirectedPresenceSender;
- class MUCSearchWindowFactory;
class ProfileSettingsProvider;
- class MUCSearchController;
- class FileTransferOverview;
- class FileTransferController;
- class XMPPRoster;
class SettingsProvider;
- class WhiteboardManager;
- class HistoryController;
- class HighlightManager;
- class ClientBlockListManager;
- class ChatMessageParser;
- class DiscoServiceWalker;
- class AutoAcceptMUCInviteDecider;
+ class StanzaChannel;
+ class TimerFactory;
class VCardManager;
+ class WhiteboardManager;
+ class XMPPRoster;
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, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, const std::map<std::string, std::string>& emoticons, VCardManager* vcardManager);
+ 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, VCardManager* vcardManager, Chattables& chattables);
virtual ~ChatsManager();
void setAvatarManager(AvatarManager* avatarManager);
void setOnline(bool enabled);
void setServerDiscoInfo(std::shared_ptr<DiscoInfo> info);
void handleIncomingMessage(std::shared_ptr<Message> incomingMessage);
+#ifndef NOT_YET
std::vector<ChatListWindow::Chat> getRecentChats() const;
+#endif
virtual std::vector<Contact::ref> getContacts(bool withMUCNicks);
boost::signals2::signal<void (bool supportsImpromptu)> onImpromptuMUCServiceDiscovered;
@@ -86,10 +89,12 @@ namespace Swift {
};
private:
+#ifndef NOT_YET
ChatListWindow::Chat createChatListChatItem(const JID& jid, const std::string& activity, bool privateMessage);
+#endif
void handleChatRequest(const std::string& contact);
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 = nullptr);
+ MUC::ref handleJoinMUCRequest(const JID& muc, const boost::optional<std::string>& password, const boost::optional<std::string>& nick, bool createAsReservedIfNew, bool isImpromptu, ChatWindow* reuseChatwindow = nullptr);
void handleSearchMUCRequest();
void handleMUCSelectedAfterSearch(const JID&);
void rebindControllerJID(const JID& from, const JID& to);
@@ -105,18 +110,25 @@ namespace Swift {
void handleNewFileTransferController(FileTransferController*);
void handleWhiteboardSessionRequest(const JID& contact, bool senderIsSelf);
void handleWhiteboardStateChange(const JID& contact, const ChatWindow::WhiteboardSessionState state);
+#ifndef NOT_YET
boost::optional<ChatListWindow::Chat> removeExistingChat(const ChatListWindow::Chat& chat);
+#endif
bool messageCausesSessionBinding(std::shared_ptr<Message> message);
void cleanupPrivateMessageRecents();
+#ifndef NOT_YET
void appendRecent(const ChatListWindow::Chat& chat);
void prependRecent(const ChatListWindow::Chat& chat);
+#endif
void setupBookmarks();
+#ifndef NOT_YET
void loadRecents();
void saveRecents();
void handleChatMadeRecent();
void handleMUCBookmarkActivated(const MUCBookmark&);
void handleRecentActivated(const ChatListWindow::Chat&);
void handleUnreadCountChanged(ChatControllerBase* controller);
+#endif
+ void handleChattableActivated(const JID& jid);
void handleAvatarChanged(const JID& jid);
void handleClearRecentsRequested();
void handleJIDAddedToRoster(const JID&);
@@ -126,12 +138,13 @@ namespace Swift {
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, std::shared_ptr<DiscoInfo> info);
void handleLocalServiceWalkFinished();
-
void updatePresenceReceivingStateOnChatController(const JID&);
+#ifndef NOT_YET
ChatListWindow::Chat updateChatStatusAndAvatarHelper(const ChatListWindow::Chat& chat) const;
+#endif
+
ChatController* getChatControllerOrFindAnother(const JID &contact);
@@ -139,6 +152,9 @@ namespace Swift {
ChatController* getChatControllerOrCreate(const JID &contact);
ChatController* getChatControllerIfExists(const JID &contact, bool rebindIfNeeded = true);
+ protected:
+ MUCBookmarkManager* mucBookmarkManager_;
+
private:
std::map<JID, MUCController*> mucControllers_;
std::map<JID, ChatController*> chatControllers_;
@@ -154,9 +170,10 @@ namespace Swift {
AvatarManager* avatarManager_;
PresenceSender* presenceSender_;
UIEventStream* uiEventStream_;
- MUCBookmarkManager* mucBookmarkManager_;
std::shared_ptr<DiscoInfo> serverDiscoInfo_;
+#ifndef NOT_YET
ChatListWindow* chatListWindow_;
+#endif
JoinMUCWindow* joinMUCWindow_;
boost::signals2::scoped_connection uiEventConnection_;
bool useDelayForLatency_;
@@ -165,7 +182,9 @@ namespace Swift {
EntityCapsProvider* entityCapsProvider_;
MUCManager* mucManager;
MUCSearchController* mucSearchController_;
+#ifndef NOT_YET
std::list<ChatListWindow::Chat> recentChats_;
+#endif
ProfileSettingsProvider* profileSettings_;
FileTransferOverview* ftOverview_;
XMPPRoster* roster_;
@@ -182,6 +201,7 @@ namespace Swift {
AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider_;
IDGenerator idGenerator_;
VCardManager* vcardManager_;
+ Chattables& chattables_;
std::map<JID, std::set<JID>> invitees_;
};
diff --git a/Swift/Controllers/Chat/Chattables.cpp b/Swift/Controllers/Chat/Chattables.cpp
new file mode 100644
index 0000000..707046f
--- /dev/null
+++ b/Swift/Controllers/Chat/Chattables.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <Swift/Controllers/Chat/Chattables.h>
+
+namespace Swift {
+
+const std::vector<JID>& Chattables::get() const {
+ return list_;
+}
+
+const Chattables::State& Chattables::getState(const JID& jid) const {
+ auto it = states_.find(jid);
+ return it != states_.end() ? it->second : unknown_;
+}
+
+void Chattables::addJID(const JID& jid, State::Type type) {
+ if (states_.find(jid) != states_.end()) {
+ return;
+ }
+ State state;
+ state.type = type;
+ state.jid = jid;
+ onBeginAdd(static_cast<int>(list_.size()));
+ list_.push_back(jid);
+ states_[jid] = state;
+ onAdded();
+}
+
+void Chattables::setState(const JID& jid, State state) {
+ auto stateIter = states_.find(jid);
+ if (stateIter == states_.end()) {
+ return;
+ }
+ stateIter->second = state;
+ auto listPos = static_cast<int>(std::distance(list_.begin(), std::find(list_.begin(), list_.end(), jid)));
+ onChanged(jid, listPos);
+}
+
+}
diff --git a/Swift/Controllers/Chat/Chattables.h b/Swift/Controllers/Chat/Chattables.h
new file mode 100644
index 0000000..3b5817a
--- /dev/null
+++ b/Swift/Controllers/Chat/Chattables.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <map>
+#include <vector>
+
+#include <boost/signals2.hpp>
+
+#include <Swiften/Elements/StatusShow.h>
+#include <Swiften/JID/JID.h>
+
+namespace Swift {
+class Chattables {
+ public:
+ struct State {
+ enum class Type {Room, Person};
+ JID jid;
+ /// Empty for no name
+ std::string name;
+ size_t unreadCount = 0;
+ Type type;
+ StatusShow::Type status = StatusShow::None;
+ //avatar
+ //status
+ };
+ const std::vector<JID>& get() const;
+ const State& getState(const JID& jid) const;
+
+ void addJID(const JID& jid, State::Type type);
+ void setState(const JID& jid, State state);
+
+ boost::signals2::signal<void (int)> onBeginAdd;
+ boost::signals2::signal<void ()> onAdded;
+ boost::signals2::signal<void (const JID&, int)> onChanged;
+ /// The UI has activated a chattable item (e.g. clicked in the roster)
+ boost::signals2::signal<void (const JID&)> onActivated;
+ private:
+ std::vector<JID> list_;
+ std::map<JID, State> states_;
+ State unknown_;
+};
+}
diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp
index d10e6d4..30d4933 100644
--- a/Swift/Controllers/Chat/MUCController.cpp
+++ b/Swift/Controllers/Chat/MUCController.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2017 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -23,6 +23,7 @@
#include <Swiften/Client/ClientBlockListManager.h>
#include <Swiften/Client/StanzaChannel.h>
#include <Swiften/Disco/EntityCapsProvider.h>
+#include <Swiften/Disco/GetDiscoInfoRequest.h>
#include <Swiften/Elements/Delay.h>
#include <Swiften/Elements/Thread.h>
#include <Swiften/MUC/MUC.h>
@@ -35,6 +36,7 @@
#include <SwifTools/TabComplete.h>
#include <Swift/Controllers/Chat/ChatMessageParser.h>
+#include <Swift/Controllers/Chat/Chattables.h>
#include <Swift/Controllers/Highlighting/Highlighter.h>
#include <Swift/Controllers/Intl.h>
#include <Swift/Controllers/Roster/ContactRosterItem.h>
@@ -59,17 +61,6 @@
namespace Swift {
-class MUCBookmarkPredicate {
- public:
- MUCBookmarkPredicate(const JID& mucJID) : roomJID_(mucJID) { }
- bool operator()(const MUCBookmark& operand) {
- return operand.getRoom() == roomJID_;
- }
-
- private:
- JID roomJID_;
-};
-
/**
* The controller does not gain ownership of the stanzaChannel, nor the factory.
*/
@@ -98,8 +89,10 @@ MUCController::MUCController (
bool isImpromptu,
AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider,
VCardManager* vcardManager,
- MUCBookmarkManager* mucBookmarkManager) :
- ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, muc->getJID(), nickResolver, presenceOracle, avatarManager, useDelayForLatency, uiEventStream, eventController, entityCapsProvider, historyController, mucRegistry, highlightManager, chatMessageParser, autoAcceptMUCInviteDecider), muc_(muc), nick_(nick), desiredNick_(nick), password_(password), renameCounter_(0), isImpromptu_(isImpromptu), isImpromptuAlreadyConfigured_(false), clientBlockListManager_(clientBlockListManager), mucBookmarkManager_(mucBookmarkManager) {
+ MUCBookmarkManager* mucBookmarkManager,
+ SettingsProvider* settings,
+ Chattables& chattables) :
+ ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, muc->getJID(), nickResolver, presenceOracle, avatarManager, useDelayForLatency, uiEventStream, eventController, entityCapsProvider, historyController, mucRegistry, highlightManager, chatMessageParser, autoAcceptMUCInviteDecider, settings, chattables), muc_(muc), nick_(nick), desiredNick_(nick), password_(password), renameCounter_(0), isImpromptu_(isImpromptu), isImpromptuAlreadyConfigured_(false), clientBlockListManager_(clientBlockListManager), mucBookmarkManager_(mucBookmarkManager) {
assert(avatarManager_);
parting_ = true;
@@ -112,7 +105,7 @@ MUCController::MUCController (
isInitialJoin_ = true;
chatWindowTitle_ = "";
- roster_ = std::unique_ptr<Roster>(new Roster(false, true));
+ roster_ = std::make_unique<Roster>(false, true);
rosterVCardProvider_ = new RosterVCardProvider(roster_.get(), vcardManager, JID::WithResource);
completer_ = new TabComplete();
chatWindow_->setRosterModel(roster_.get());
@@ -171,14 +164,7 @@ MUCController::MUCController (
mucBookmarkManagerBookmarkAddedConnection_ = (mucBookmarkManager_->onBookmarkAdded.connect(boost::bind(&MUCController::handleMUCBookmarkAdded, this, _1)));
mucBookmarkManagerBookmarkRemovedConnection_ = (mucBookmarkManager_->onBookmarkRemoved.connect(boost::bind(&MUCController::handleMUCBookmarkRemoved, this, _1)));
- std::vector<MUCBookmark> mucBookmarks = mucBookmarkManager_->getBookmarks();
- std::vector<MUCBookmark>::iterator bookmarkIterator = std::find_if(mucBookmarks.begin(), mucBookmarks.end(), MUCBookmarkPredicate(muc->getJID()));
- if (bookmarkIterator != mucBookmarks.end()) {
- updateChatWindowBookmarkStatus(*bookmarkIterator);
- }
- else {
- updateChatWindowBookmarkStatus(boost::optional<MUCBookmark>());
- }
+ updateChatWindowBookmarkStatus(mucBookmarkManager_->lookupBookmark(muc->getJID()));
}
MUCController::~MUCController() {
@@ -273,6 +259,9 @@ void MUCController::rejoin() {
lastActivity_ = historyController_->getLastTimeStampFromMUC(selfJID_, toJID_);
}
#endif
+
+ requestSecurityMarking();
+
if (lastActivity_ == boost::posix_time::not_a_date_time) {
muc_->joinAs(nick_);
}
@@ -492,6 +481,7 @@ void MUCController::setAvailableRoomActions(const MUCOccupant::Affiliation& affi
if (role <= MUCOccupant::Visitor) {
actions.push_back(ChatWindow::Invite);
}
+ actions.push_back(ChatWindow::Leave);
chatWindow_->setAvailableRoomActions(actions);
}
@@ -1243,4 +1233,63 @@ void MUCController::setChatWindowTitle(const std::string& title) {
chatWindow_->setName(chatWindowTitle_);
}
+void MUCController::requestSecurityMarking() {
+ auto discoInfoRequest = GetDiscoInfoRequest::create(muc_->getJID(), iqRouter_);
+ discoInfoRequest->onResponse.connect(
+ [this](std::shared_ptr<DiscoInfo> discoInfoRef, ErrorPayload::ref errorPayloadRef) {
+ if (!discoInfoRef || errorPayloadRef) {
+ return;
+ }
+ const std::vector<Form::ref>& extensionsList = discoInfoRef->getExtensions();
+ if (extensionsList.empty()) {
+ return;
+ }
+ // Get the correct form if it exists
+ Form::ref roomInfoForm;
+ for (const auto& form : extensionsList) {
+ if (form->getFormType() == "http://jabber.org/protocol/muc#roominfo") {
+ roomInfoForm = form;
+ break;
+ }
+ }
+ if (!roomInfoForm) {
+ return;
+ }
+ // It exists, now examine the security marking data
+ auto marking = roomInfoForm->getField("x-isode#roominfo_marking");
+ if (!marking) {
+ return;
+ }
+ // Now we know the marking is valid
+ auto markingValue = marking->getTextSingleValue();
+ if (markingValue == "") {
+ setMUCSecurityMarkingDefault();
+ return;
+ }
+ auto markingForegroundColor = roomInfoForm->getField("x-isode#roominfo_marking_fg_color");
+ auto markingBackgroundColor = roomInfoForm->getField("x-isode#roominfo_marking_bg_color");
+ std::string markingForegroundColorValue = "Black";
+ std::string markingBackgroundColorValue = "White";
+ if (markingForegroundColor && markingForegroundColor->getTextSingleValue() != "") {
+ markingForegroundColorValue = markingForegroundColor->getTextSingleValue();
+ }
+ if (markingBackgroundColor && markingBackgroundColor->getTextSingleValue() != "") {
+ markingBackgroundColorValue = markingBackgroundColor->getTextSingleValue();
+ }
+ setMUCSecurityMarking(markingValue, markingForegroundColorValue, markingBackgroundColorValue);
+ }
+ );
+ discoInfoRequest->send();
+}
+
+void MUCController::setMUCSecurityMarking(const std::string& markingValue, const std::string& markingForegroundColorValue, const std::string& markingBackgroundColorValue) {
+ roomSecurityMarking_ = markingValue;
+ chatWindow_->setChatSecurityMarking(markingValue, markingForegroundColorValue, markingBackgroundColorValue);
+}
+
+void MUCController::setMUCSecurityMarkingDefault() {
+ roomSecurityMarking_ = "";
+ chatWindow_->removeChatSecurityMarking();
+}
+
}
diff --git a/Swift/Controllers/Chat/MUCController.h b/Swift/Controllers/Chat/MUCController.h
index 258eaaf..bd1148f 100644
--- a/Swift/Controllers/Chat/MUCController.h
+++ b/Swift/Controllers/Chat/MUCController.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2017 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -14,7 +14,6 @@
#include <boost/signals2.hpp>
#include <boost/signals2/connection.hpp>
-#include <Swiften/Base/Override.h>
#include <Swiften/Elements/DiscoInfo.h>
#include <Swiften/Elements/MUCOccupant.h>
#include <Swiften/Elements/Message.h>
@@ -54,14 +53,14 @@ namespace Swift {
class MUCController : public ChatControllerBase {
public:
- MUCController(const JID& self, MUC::ref muc, const boost::optional<std::string>& password, const std::string &nick, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, UIEventStream* events, bool useDelayForLatency, TimerFactory* timerFactory, EventController* eventController, EntityCapsProvider* entityCapsProvider, XMPPRoster* xmppRoster, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, std::shared_ptr<ChatMessageParser> chatMessageParser, bool isImpromptu, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider, VCardManager* vcardManager, MUCBookmarkManager* mucBookmarkManager);
- virtual ~MUCController();
+ MUCController(const JID& self, MUC::ref muc, const boost::optional<std::string>& password, const std::string &nick, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, UIEventStream* events, bool useDelayForLatency, TimerFactory* timerFactory, EventController* eventController, EntityCapsProvider* entityCapsProvider, XMPPRoster* xmppRoster, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, std::shared_ptr<ChatMessageParser> chatMessageParser, bool isImpromptu, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider, VCardManager* vcardManager, MUCBookmarkManager* mucBookmarkManager, SettingsProvider* settings, Chattables& chattables);
+ virtual ~MUCController() override;
boost::signals2::signal<void ()> onUserLeft;
boost::signals2::signal<void ()> onUserJoined;
boost::signals2::signal<void ()> onImpromptuConfigCompleted;
boost::signals2::signal<void (const std::string&, const std::string& )> onUserNicknameChanged;
- virtual void setOnline(bool online) SWIFTEN_OVERRIDE;
- virtual void setAvailableServerFeatures(std::shared_ptr<DiscoInfo> info) SWIFTEN_OVERRIDE;
+ virtual void setOnline(bool online) override;
+ virtual void setAvailableServerFeatures(std::shared_ptr<DiscoInfo> info) override;
void rejoin();
static void appendToJoinParts(std::vector<NickJoinPart>& joinParts, const NickJoinPart& newEvent);
static std::string generateJoinPartString(const std::vector<NickJoinPart>& joinParts, bool isImpromptu);
@@ -76,18 +75,18 @@ namespace Swift {
void setChatWindowTitle(const std::string& title);
protected:
- virtual void preSendMessageRequest(std::shared_ptr<Message> message) SWIFTEN_OVERRIDE;
- virtual bool isIncomingMessageFromMe(std::shared_ptr<Message> message) SWIFTEN_OVERRIDE;
- virtual std::string senderHighlightNameFromMessage(const JID& from) SWIFTEN_OVERRIDE;
- virtual std::string senderDisplayNameFromMessage(const JID& from) SWIFTEN_OVERRIDE;
- virtual boost::optional<boost::posix_time::ptime> getMessageTimestamp(std::shared_ptr<Message> message) const SWIFTEN_OVERRIDE;
- virtual void preHandleIncomingMessage(std::shared_ptr<MessageEvent>) SWIFTEN_OVERRIDE;
- virtual void addMessageHandleIncomingMessage(const JID& from, const ChatWindow::ChatMessage& message, const std::string& messageID, bool senderIsSelf, std::shared_ptr<SecurityLabel> label, const boost::posix_time::ptime& time) SWIFTEN_OVERRIDE;
- virtual void handleIncomingReplaceMessage(const JID& from, const ChatWindow::ChatMessage& message, const std::string& messageID, const std::string& idToReplace, bool senderIsSelf, std::shared_ptr<SecurityLabel> label, const boost::posix_time::ptime& timeStamp) SWIFTEN_OVERRIDE;
- virtual void postHandleIncomingMessage(std::shared_ptr<MessageEvent>, const ChatWindow::ChatMessage& chatMessage) SWIFTEN_OVERRIDE;
- virtual void cancelReplaces() SWIFTEN_OVERRIDE;
- virtual void logMessage(const std::string& message, const JID& fromJID, const JID& toJID, const boost::posix_time::ptime& timeStamp, bool isIncoming) SWIFTEN_OVERRIDE;
- virtual JID messageCorrectionJID(const JID& fromJID) SWIFTEN_OVERRIDE;
+ virtual void preSendMessageRequest(std::shared_ptr<Message> message) override;
+ virtual bool isIncomingMessageFromMe(std::shared_ptr<Message> message) override;
+ virtual std::string senderHighlightNameFromMessage(const JID& from) override;
+ virtual std::string senderDisplayNameFromMessage(const JID& from) override;
+ virtual boost::optional<boost::posix_time::ptime> getMessageTimestamp(std::shared_ptr<Message> message) const override;
+ virtual void preHandleIncomingMessage(std::shared_ptr<MessageEvent>) override;
+ virtual void addMessageHandleIncomingMessage(const JID& from, const ChatWindow::ChatMessage& message, const std::string& messageID, bool senderIsSelf, std::shared_ptr<SecurityLabel> label, const boost::posix_time::ptime& time) override;
+ virtual void handleIncomingReplaceMessage(const JID& from, const ChatWindow::ChatMessage& message, const std::string& messageID, const std::string& idToReplace, bool senderIsSelf, std::shared_ptr<SecurityLabel> label, const boost::posix_time::ptime& timeStamp) override;
+ virtual void postHandleIncomingMessage(std::shared_ptr<MessageEvent>, const ChatWindow::ChatMessage& chatMessage) override;
+ virtual void cancelReplaces() override;
+ virtual void logMessage(const std::string& message, const JID& fromJID, const JID& toJID, const boost::posix_time::ptime& timeStamp, bool isIncoming) override;
+ virtual JID messageCorrectionJID(const JID& fromJID) override;
private:
void setAvailableRoomActions(const MUCOccupant::Affiliation& affiliation, const MUCOccupant::Role& role);
@@ -116,9 +115,9 @@ namespace Swift {
bool messageTargetsMe(std::shared_ptr<Message> message);
void updateJoinParts();
bool shouldUpdateJoinParts();
- virtual void dayTicked() SWIFTEN_OVERRIDE { clearPresenceQueue(); }
+ virtual void dayTicked() override { clearPresenceQueue(); }
void processUserPart();
- virtual void handleBareJIDCapsChanged(const JID& jid) SWIFTEN_OVERRIDE;
+ virtual void handleBareJIDCapsChanged(const JID& jid) override;
void handleConfigureRequest(Form::ref);
void handleConfigurationFailed(ErrorPayload::ref);
void handleConfigurationFormReceived(Form::ref);
@@ -149,6 +148,10 @@ namespace Swift {
void displaySubjectIfChanged(const std::string& sucject);
void addChatSystemMessage();
+ void requestSecurityMarking();
+ void setMUCSecurityMarking(const std::string& markingValue, const std::string& markingForegroundColorValue, const std::string& markingBackgroundColorValue);
+ void setMUCSecurityMarkingDefault();
+
private:
MUC::ref muc_;
std::string nick_;
@@ -190,4 +193,3 @@ namespace Swift {
std::string chatWindowTitle_;
};
}
-
diff --git a/Swift/Controllers/Chat/UnitTest/ChatControllerTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatControllerTest.cpp
new file mode 100644
index 0000000..e010656
--- /dev/null
+++ b/Swift/Controllers/Chat/UnitTest/ChatControllerTest.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <memory>
+#include <string>
+
+#include <gtest/gtest.h>
+#include <hippomocks.h>
+
+#include <Swiften/Avatars/NullAvatarManager.h>
+#include <Swiften/Client/ClientBlockListManager.h>
+#include <Swiften/Client/DummyStanzaChannel.h>
+#include <Swiften/Client/NickResolver.h>
+#include <Swiften/Disco/DummyEntityCapsProvider.h>
+#include <Swiften/Network/DummyTimerFactory.h>
+#include <Swiften/Queries/DummyIQChannel.h>
+#include <Swiften/Roster/XMPPRoster.h>
+#include <Swiften/Roster/XMPPRosterImpl.h>
+#include <Swiften/VCards/VCardManager.h>
+#include <Swiften/VCards/VCardMemoryStorage.h>
+
+#include <Swift/Controllers/Chat/AutoAcceptMUCInviteDecider.h>
+#include <Swift/Controllers/Chat/ChatController.h>
+#include <Swift/Controllers/Chat/ChatMessageParser.h>
+#include <Swift/Controllers/Chat/Chattables.h>
+#include <Swift/Controllers/Settings/DummySettingsProvider.h>
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
+#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h>
+#include <Swift/Controllers/UnitTest/MockChatWindow.h>
+#include <Swift/Controllers/XMPPEvents/EventController.h>
+
+using namespace Swift;
+
+/**
+ * Most of the ChatController tests are in ChatsManagerTest.
+ * New tests related with ChatController should be added here,
+ * and old tests should be migrated when possible.
+ */
+
+class ExtendedChatController : public ChatController {
+public:
+ ExtendedChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency, UIEventStream* eventStream, TimerFactory* timerFactory, EventController* eventController, EntityCapsProvider* entityCapsProvider, bool userWantsReceipts, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, std::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider, SettingsProvider* settings, Chattables& chattables) :
+ ChatController(self, stanzaChannel, iqRouter, chatWindowFactory, contact, nickResolver, presenceOracle, avatarManager, isInMUC, useDelayForLatency, eventStream, timerFactory, eventController, entityCapsProvider, userWantsReceipts, historyController, mucRegistry, highlightManager, clientBlockListManager, chatMessageParser, autoAcceptMUCInviteDecider, settings, chattables) {
+ }
+
+ std::map<std::shared_ptr<Stanza>, std::string> getUnackedStanzas() { return unackedStanzas_; }
+ std::map<std::string, std::shared_ptr<Stanza>> getFailedStanzas() { return failedStanzas_; }
+};
+
+class ChatControllerTest : public ::testing::Test {
+protected:
+ virtual void SetUp() {
+ self_ = JID("alice@wonderland.lit");
+ other_ = JID("whiterabbit@wonderland.lit");
+ stanzaChannel_ = new DummyStanzaChannel();
+ iqChannel_ = new DummyIQChannel();
+ iqRouter_ = new IQRouter(iqChannel_);
+ eventController_ = new EventController();
+ xmppRoster_ = new XMPPRosterImpl();
+ vCardManager_ = new VCardManager(self_, iqRouter_, vCardMemoryStorage_);
+ mucRegistry_ = new MUCRegistry();
+ nickResolver_ = new NickResolver(self_, xmppRoster_, vCardManager_, mucRegistry_);
+ presenceOracle_ = new PresenceOracle(stanzaChannel_, xmppRoster_);
+ avatarManager_ = new NullAvatarManager();
+ uiEventStream_ = new UIEventStream();
+ timerFactory_ = new DummyTimerFactory();
+ entityCapsProvider_ = new DummyEntityCapsProvider();
+ settings_ = new DummySettingsProvider();
+ highlightManager_ = new HighlightManager(settings_);
+ highlightManager_->resetToDefaultConfiguration();
+ clientBlockListManager_ = new ClientBlockListManager(iqRouter_);
+ autoAcceptMUCInviteDecider_ = new AutoAcceptMUCInviteDecider(self_.getDomain(), xmppRoster_, settings_);
+ chatMessageParser_ = std::make_shared<ChatMessageParser>(std::map<std::string, std::string>(), highlightManager_->getConfiguration(), ChatMessageParser::Mode::GroupChat);
+ mocks_ = new MockRepository();
+ window_ = new MockChatWindow();
+ chatWindowFactory_ = mocks_->InterfaceMock<ChatWindowFactory>();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(other_, uiEventStream_).Return(window_);
+ chattables_ = std::make_unique<Chattables>();
+
+ controller_ = new ExtendedChatController(self_, stanzaChannel_, iqRouter_, chatWindowFactory_, other_, nickResolver_, presenceOracle_, avatarManager_, false, false, uiEventStream_, timerFactory_, eventController_, entityCapsProvider_, false, nullptr, mucRegistry_, highlightManager_, clientBlockListManager_, chatMessageParser_, nullptr, settings_, *chattables_);
+ }
+ virtual void TearDown() {
+ delete controller_;
+ chattables_.reset();
+ chatMessageParser_.reset();
+ delete autoAcceptMUCInviteDecider_;
+ delete clientBlockListManager_;
+ delete highlightManager_;
+ delete settings_;
+ delete entityCapsProvider_;
+ delete timerFactory_;
+ delete uiEventStream_;
+ delete avatarManager_;
+ delete presenceOracle_;
+ delete nickResolver_;
+ delete mucRegistry_;
+ delete vCardManager_;
+ delete xmppRoster_;
+ delete eventController_;
+ delete iqRouter_;
+ delete iqChannel_;
+ delete stanzaChannel_;
+ }
+
+ JID self_, other_;
+ AvatarManager* avatarManager_ = nullptr;
+ ExtendedChatController* controller_ = nullptr;
+ ChatWindowFactory* chatWindowFactory_;
+ ClientBlockListManager* clientBlockListManager_;
+ EventController* eventController_ = nullptr;
+ EntityCapsProvider* entityCapsProvider_ = nullptr;
+ IQChannel* iqChannel_ = nullptr;
+ IQRouter* iqRouter_ = nullptr;
+ MockRepository* mocks_;
+ MockChatWindow* window_;
+ MUCRegistry* mucRegistry_ = nullptr;
+ NickResolver* nickResolver_ = nullptr;
+ PresenceOracle* presenceOracle_ = nullptr;
+ DummyStanzaChannel* stanzaChannel_ = nullptr;
+ TimerFactory* timerFactory_;
+ XMPPRosterImpl* xmppRoster_ = nullptr;
+ UIEventStream* uiEventStream_;
+ VCardManager* vCardManager_ = nullptr;
+ VCardMemoryStorage* vCardMemoryStorage_ = nullptr;
+ DummySettingsProvider* settings_;
+ HighlightManager* highlightManager_;
+ std::shared_ptr<ChatMessageParser> chatMessageParser_;
+ AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider_;
+ std::unique_ptr<Chattables> chattables_;
+
+};
+
+TEST_F(ChatControllerTest, testResendMessage) {
+ std::string msgBody("TestMsg");
+ stanzaChannel_->setStreamManagementEnabled(true);
+ window_->onSendMessageRequest(msgBody, false);
+ {
+ auto failedStanzas = controller_->getFailedStanzas();
+ auto unackedStanzas = controller_->getUnackedStanzas();
+ ASSERT_EQ(failedStanzas.size(), 0);
+ ASSERT_EQ(unackedStanzas.size(), 1);
+ }
+ //Disconnecting to fail the stanza
+ controller_->setOnline(false);
+ controller_->setOnline(true);
+ {
+ auto failedStanzas = controller_->getFailedStanzas();
+ auto unackedStanzas = controller_->getUnackedStanzas();
+ ASSERT_EQ(failedStanzas.size(), 1);
+ ASSERT_EQ(unackedStanzas.size(), 0);
+ }
+ window_->onResendMessageRequest("id");
+ {
+ auto failedStanzas = controller_->getFailedStanzas();
+ auto unackedStanzas = controller_->getUnackedStanzas();
+ ASSERT_EQ(failedStanzas.size(), 0);
+ ASSERT_EQ(unackedStanzas.size(), 1);
+ }
+}
diff --git a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
index ac62942..954dd2f 100644
--- a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
+++ b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
@@ -38,6 +38,7 @@
#include <Swiften/Jingle/JingleSessionManager.h>
#include <Swiften/MUC/MUCManager.h>
#include <Swiften/MUC/UnitTest/MockMUC.h>
+#include <Swiften/MUC/MUCBookmarkManager.h>
#include <Swiften/Network/DummyTimerFactory.h>
#include <Swiften/Presence/DirectedPresenceSender.h>
#include <Swiften/Presence/PresenceOracle.h>
@@ -50,6 +51,7 @@
#include <Swift/Controllers/Chat/ChatController.h>
#include <Swift/Controllers/Chat/ChatsManager.h>
+#include <Swift/Controllers/Chat/Chattables.h>
#include <Swift/Controllers/Chat/MUCController.h>
#include <Swift/Controllers/Chat/UnitTest/MockChatListWindow.h>
#include <Swift/Controllers/EventNotifier.h>
@@ -57,6 +59,7 @@
#include <Swift/Controllers/ProfileSettingsProvider.h>
#include <Swift/Controllers/SettingConstants.h>
#include <Swift/Controllers/Settings/DummySettingsProvider.h>
+#include <Swift/Controllers/UIEvents/AddMUCBookmarkUIEvent.h>
#include <Swift/Controllers/UIEvents/CreateImpromptuMUCUIEvent.h>
#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h>
#include <Swift/Controllers/UIEvents/RequestChatUIEvent.h>
@@ -106,6 +109,16 @@ class DummyNotifier : public Notifier {
std::vector<Notification> notifications;
};
+class ExtendedChatsManager : public ChatsManager {
+public:
+ ExtendedChatsManager(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, VCardManager* vcardManager, Chattables& chattables) :
+ ChatsManager(jid, stanzaChannel, iqRouter, eventController, chatWindowFactory, joinMUCWindowFactory, nickResolver, presenceOracle, presenceSender, uiEventStream, chatListWindowFactory, useDelayForLatency, timerFactory, mucRegistry, entityCapsProvider, mucManager, mucSearchWindowFactory, profileSettings, ftOverview, roster, eagleMode, settings, historyController_, whiteboardManager, highlightManager, clientBlockListManager, emoticons, vcardManager, chattables) {
+ }
+ MUCBookmarkManager* getBookmarkManager() {
+ return mucBookmarkManager_;
+ }
+};
+
class ChatsManagerTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(ChatsManagerTest);
@@ -161,13 +174,19 @@ class ChatsManagerTest : public CppUnit::TestFixture {
CPPUNIT_TEST(testReceivingBookmarksWithDomainJID);
CPPUNIT_TEST(testReceivingBookmarksWithBareJID);
CPPUNIT_TEST(testReceivingBookmarksWithFullJID);
+ CPPUNIT_TEST(testAutoJoinBookmarksAndChattables);
+ CPPUNIT_TEST(testJoinNoAutojoinBookmark);
+ CPPUNIT_TEST(testJoinAndBookmarkMUC);
+ CPPUNIT_TEST(testReceivingNoBookmarks);
+ CPPUNIT_TEST(testReceivingNullBookmarks);
+ CPPUNIT_TEST(testReceivingBookmarksError);
CPPUNIT_TEST_SUITE_END();
public:
void setUp() {
mocks_ = new MockRepository();
- notifier_ = std::unique_ptr<DummyNotifier>(new DummyNotifier());
+ notifier_ = std::make_unique<DummyNotifier>();
jid_ = JID("test@test.com/resource");
stanzaChannel_ = new DummyStanzaChannel();
iqRouter_ = new IQRouter(stanzaChannel_);
@@ -207,7 +226,8 @@ public:
mocks_->ExpectCall(chatListWindowFactory_, ChatListWindowFactory::createChatListWindow).With(uiEventStream_).Return(chatListWindow_);
clientBlockListManager_ = new ClientBlockListManager(iqRouter_);
timerFactory_ = new DummyTimerFactory();
- manager_ = new ChatsManager(jid_, stanzaChannel_, iqRouter_, eventController_, chatWindowFactory_, joinMUCWindowFactory_, nickResolver_, presenceOracle_, directedPresenceSender_, uiEventStream_, chatListWindowFactory_, true, timerFactory_, mucRegistry_, entityCapsProvider_, mucManager_, mucSearchWindowFactory_, profileSettings_, ftOverview_, xmppRoster_, false, settings_, nullptr, wbManager_, highlightManager_, clientBlockListManager_, emoticons_, vcardManager_);
+ chattables_ = std::make_unique<Chattables>();
+ manager_ = new ExtendedChatsManager(jid_, stanzaChannel_, iqRouter_, eventController_, chatWindowFactory_, joinMUCWindowFactory_, nickResolver_, presenceOracle_, directedPresenceSender_, uiEventStream_, chatListWindowFactory_, true, timerFactory_, mucRegistry_, entityCapsProvider_, mucManager_, mucSearchWindowFactory_, profileSettings_, ftOverview_, xmppRoster_, false, settings_, nullptr, wbManager_, highlightManager_, clientBlockListManager_, emoticons_, vcardManager_, *chattables_);
manager_->setAvatarManager(avatarManager_);
}
@@ -783,7 +803,7 @@ public:
// send message to participantA
auto messageBody = std::string("message body to send");
window->onSendMessageRequest(messageBody, false);
- auto sendMessageStanza = stanzaChannel_->getStanzaAtIndex<Message>(2);
+ auto sendMessageStanza = stanzaChannel_->getStanzaAtIndex<Message>(3);
CPPUNIT_ASSERT_EQUAL(messageBody, *sendMessageStanza->getBody());
// receive reply with error
@@ -1565,7 +1585,11 @@ public:
uiEventStream_->send(std::make_shared<CreateImpromptuMUCUIEvent>(jids, mucJID, ""));
CPPUNIT_ASSERT_EQUAL(std::string("bar@test.com, foo@test.com"), manager_->getRecentChats()[0].getTitle());
- auto mucJoinPresence = std::dynamic_pointer_cast<Presence>(stanzaChannel_->sentStanzas[2]);
+ // Check the MUC security marking request
+ auto mucInfoRequest = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[2]);
+ CPPUNIT_ASSERT(mucInfoRequest);
+
+ auto mucJoinPresence = std::dynamic_pointer_cast<Presence>(stanzaChannel_->sentStanzas[3]);
CPPUNIT_ASSERT(mucJoinPresence);
// MUC presence reply
@@ -1626,17 +1650,7 @@ public:
CPPUNIT_ASSERT_EQUAL(std::string("mucroom"), window->name_);
}
- static std::shared_ptr<Storage> createBookmarkStorageWithJID(const JID& jid) {
- auto storage = std::make_shared<Storage>();
- auto room = Storage::Room();
- room.jid = jid;
- room.autoJoin = true;
- storage->addRoom(room);
- return storage;
- }
-
- void testReceivingBookmarksWithDomainJID() {
- auto bookmarkRequest = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[0]);
+ std::shared_ptr<Storage> createBookmarkStorageWithJID(std::shared_ptr<IQ> bookmarkRequest, const JID& jid, const bool autojoin) {
CPPUNIT_ASSERT(bookmarkRequest);
CPPUNIT_ASSERT_EQUAL(IQ::Get, bookmarkRequest->getType());
@@ -1646,56 +1660,179 @@ public:
auto storage = std::dynamic_pointer_cast<Storage>(privateStorage->getPayload());
CPPUNIT_ASSERT(storage);
+ auto roomsStorage = std::make_shared<Storage>();
+ if (jid.isValid()) {
+ auto room = Storage::Room();
+ room.jid = jid;
+ room.autoJoin = autojoin;
+ roomsStorage->addRoom(room);
+ }
+ return roomsStorage;
+ }
+
+ void testReceivingBookmarksWithDomainJID() {
+ auto bookmarkRequest = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[0]);
auto response = IQ::createResult(
bookmarkRequest->getFrom(),
bookmarkRequest->getTo(),
bookmarkRequest->getID(),
- std::make_shared<PrivateStorage>(createBookmarkStorageWithJID("montague.lit"))
+ std::make_shared<PrivateStorage>(createBookmarkStorageWithJID(bookmarkRequest, "montague.lit", true))
);
stanzaChannel_->onIQReceived(response);
}
void testReceivingBookmarksWithBareJID() {
auto bookmarkRequest = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[0]);
- CPPUNIT_ASSERT(bookmarkRequest);
- CPPUNIT_ASSERT_EQUAL(IQ::Get, bookmarkRequest->getType());
-
- auto privateStorage = bookmarkRequest->getPayload<PrivateStorage>();
- CPPUNIT_ASSERT(privateStorage);
-
- auto storage = std::dynamic_pointer_cast<Storage>(privateStorage->getPayload());
- CPPUNIT_ASSERT(storage);
-
MockChatWindow* window = new MockChatWindow();
mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID("example@montague.lit"), uiEventStream_).Return(window);
+ auto response = IQ::createResult(
+ bookmarkRequest->getFrom(),
+ bookmarkRequest->getTo(),
+ bookmarkRequest->getID(),
+ std::make_shared<PrivateStorage>(createBookmarkStorageWithJID(bookmarkRequest, "example@montague.lit", true))
+ );
+ stanzaChannel_->onIQReceived(response);
+ }
+ void testReceivingNoBookmarks() {
+ auto bookmarkRequest = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[0]);
auto response = IQ::createResult(
bookmarkRequest->getFrom(),
bookmarkRequest->getTo(),
bookmarkRequest->getID(),
- std::make_shared<PrivateStorage>(createBookmarkStorageWithJID("example@montague.lit"))
+ std::make_shared<PrivateStorage>()
+ );
+ stanzaChannel_->onIQReceived(response);
+ }
+
+ void testReceivingNullBookmarks() {
+ auto bookmarkRequest = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[0]);
+ auto response = IQ::createResult(
+ bookmarkRequest->getFrom(),
+ bookmarkRequest->getTo(),
+ bookmarkRequest->getID(),
+ nullptr
+ );
+ stanzaChannel_->onIQReceived(response);
+ }
+
+ void testReceivingBookmarksError() {
+ auto bookmarkRequest = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[0]);
+ auto response = IQ::createError(
+ bookmarkRequest->getFrom(),
+ bookmarkRequest->getTo(),
+ bookmarkRequest->getID(),
+ ErrorPayload::Condition::ServiceUnavailable,
+ ErrorPayload::Type::Cancel,
+ nullptr
);
stanzaChannel_->onIQReceived(response);
}
void testReceivingBookmarksWithFullJID() {
auto bookmarkRequest = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[0]);
- CPPUNIT_ASSERT(bookmarkRequest);
- CPPUNIT_ASSERT_EQUAL(IQ::Get, bookmarkRequest->getType());
+ auto response = IQ::createResult(
+ bookmarkRequest->getFrom(),
+ bookmarkRequest->getTo(),
+ bookmarkRequest->getID(),
+ std::make_shared<PrivateStorage>(createBookmarkStorageWithJID(bookmarkRequest, "example@montague.lit/someresource", true))
+ );
+ stanzaChannel_->onIQReceived(response);
+ }
- auto privateStorage = bookmarkRequest->getPayload<PrivateStorage>();
- CPPUNIT_ASSERT(privateStorage);
+ void testAutoJoinBookmarksAndChattables() {
- auto storage = std::dynamic_pointer_cast<Storage>(privateStorage->getPayload());
- CPPUNIT_ASSERT(storage);
+ auto bookmarkRequest = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[0]);
+ auto roomsStorage = createBookmarkStorageWithJID(bookmarkRequest, "autojoin@bookmark.lit", true);
+ auto room = Storage::Room();
+ room.jid = "noAutojoin@bookmark.lit";
+ roomsStorage->addRoom(room);
+
+ //Only autojoin@bookmark.lit window should open.
+ MockChatWindow* autojoinBookmarkWindow = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID("autojoin@bookmark.lit"), uiEventStream_).Return(autojoinBookmarkWindow);
auto response = IQ::createResult(
bookmarkRequest->getFrom(),
bookmarkRequest->getTo(),
bookmarkRequest->getID(),
- std::make_shared<PrivateStorage>(createBookmarkStorageWithJID("example@montague.lit/someresource"))
+ std::make_shared<PrivateStorage>(roomsStorage)
);
stanzaChannel_->onIQReceived(response);
+ //Both bookmarks should be added to the chattables.
+ CPPUNIT_ASSERT_EQUAL(size_t(2), chattables_->get().size());
+ auto autoJoinState = chattables_->getState("autojoin@bookmark.lit");
+ CPPUNIT_ASSERT(autoJoinState.type == Chattables::State::Type::Room);
+ CPPUNIT_ASSERT_EQUAL(autoJoinState.status, StatusShow::Online);
+ auto noAutoJoinState = chattables_->getState("noAutojoin@bookmark.lit");
+ CPPUNIT_ASSERT(noAutoJoinState.type == Chattables::State::Type::Room);
+ CPPUNIT_ASSERT_EQUAL(noAutoJoinState.status, StatusShow::None);
+ }
+
+ void testJoinNoAutojoinBookmark() {
+
+ auto bookmarkRequest = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[0]);
+ auto roomsStorage = createBookmarkStorageWithJID(bookmarkRequest, "example@montague.lit", false);
+
+ auto response = IQ::createResult(
+ bookmarkRequest->getFrom(),
+ bookmarkRequest->getTo(),
+ bookmarkRequest->getID(),
+ std::make_shared<PrivateStorage>(roomsStorage)
+ );
+ stanzaChannel_->onIQReceived(response);
+
+ //Join previous bookmarked room, expecting no increase in chattables and change of autojoin in bookmark to true
+ MockChatWindow* newExampleChatWindow = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID("example@montague.lit"), uiEventStream_).Return(newExampleChatWindow);
+ uiEventStream_->send(std::make_shared<JoinMUCUIEvent>("example@montague.lit", boost::optional<std::string>(), boost::optional<std::string>()));
+ CPPUNIT_ASSERT_EQUAL(size_t(1), chattables_->get().size());
+ auto state = chattables_->getState("example@montague.lit");
+ CPPUNIT_ASSERT(state.type == Chattables::State::Type::Room);
+ CPPUNIT_ASSERT_EQUAL(state.status, StatusShow::Online);
+
+ auto bookmarks = manager_->getBookmarkManager()->getBookmarks();
+ CPPUNIT_ASSERT_EQUAL(bookmarks.size(), size_t(1));
+ CPPUNIT_ASSERT(bookmarks[0].getRoom() == JID("example@montague.lit"));
+ CPPUNIT_ASSERT(bookmarks[0].getAutojoin());
+ }
+
+ void testJoinAndBookmarkMUC() {
+ auto bookmarkRequest = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[0]);
+ auto roomsStorage = createBookmarkStorageWithJID(bookmarkRequest, "", true);
+ auto response = IQ::createResult(
+ bookmarkRequest->getFrom(),
+ bookmarkRequest->getTo(),
+ bookmarkRequest->getID(),
+ std::make_shared<PrivateStorage>(roomsStorage)
+ );
+ stanzaChannel_->onIQReceived(response);
+
+ //Join non-bookmarked room expecting for the room to get bookmarked with autojoin to true
+ MockChatWindow* exampleChatWindow = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With("example@montague.lit", uiEventStream_).Return(exampleChatWindow);
+ uiEventStream_->send(std::make_shared<JoinMUCUIEvent>("example@montague.lit", boost::optional<std::string>(), boost::optional<std::string>()));
+ {
+ CPPUNIT_ASSERT_EQUAL(size_t(1), chattables_->get().size());
+ auto state = chattables_->getState("example@montague.lit");
+ CPPUNIT_ASSERT(state.type == Chattables::State::Type::Room);
+ CPPUNIT_ASSERT_EQUAL(state.status, StatusShow::Online);
+
+ auto bookmarks = manager_->getBookmarkManager()->getBookmarks();
+ CPPUNIT_ASSERT_EQUAL(bookmarks.size(), size_t(1));
+ CPPUNIT_ASSERT(bookmarks[0].getRoom() == JID("example@montague.lit"));
+ CPPUNIT_ASSERT(bookmarks[0].getAutojoin());
+
+ }
+ //Exiting room that is bookmarked, expecting chattable to stay but bookmark autojoin change to false.
+ exampleChatWindow->onClosed();
+ {
+ CPPUNIT_ASSERT_EQUAL(size_t(1), chattables_->get().size());
+ auto bookmarks = manager_->getBookmarkManager()->getBookmarks();
+ CPPUNIT_ASSERT_EQUAL(bookmarks.size(), size_t(1));
+ CPPUNIT_ASSERT(bookmarks[0].getRoom() == JID("example@montague.lit"));
+ CPPUNIT_ASSERT(!bookmarks[0].getAutojoin());
+ }
}
private:
@@ -1722,7 +1859,7 @@ private:
private:
JID jid_;
std::unique_ptr<DummyNotifier> notifier_;
- ChatsManager* manager_;
+ ExtendedChatsManager* manager_;
DummyStanzaChannel* stanzaChannel_;
IQRouter* iqRouter_;
EventController* eventController_;
@@ -1760,6 +1897,7 @@ private:
int handledHighlightActions_;
std::set<std::string> soundsPlayed_;
DummyTimerFactory* timerFactory_;
+ std::unique_ptr<Chattables> chattables_;
};
diff --git a/Swift/Controllers/Chat/UnitTest/ChattablesTest.cpp b/Swift/Controllers/Chat/UnitTest/ChattablesTest.cpp
new file mode 100644
index 0000000..f30e3fd
--- /dev/null
+++ b/Swift/Controllers/Chat/UnitTest/ChattablesTest.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <gtest/gtest.h>
+#include <hippomocks.h>
+
+#include <Swift/Controllers/Chat/Chattables.h>
+
+// Clang wrongly things that tests for 0 are using 0 as null.
+#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
+
+using namespace Swift;
+
+class ChattablesTest : public ::testing::Test {
+ protected:
+ void SetUp() {
+ beginListSize_ = 0;
+ endListSize_ = 0;
+ callsToBegin_ = 0;
+ callsToEnd_ = 0;
+ }
+
+ void TearDown() {
+ }
+
+ void updateBeginListSize(int listSize);
+ void updateEndListSize();
+
+ Chattables chattables_;
+ int beginListSize_;
+ int endListSize_;
+ int callsToBegin_;
+ int callsToEnd_;
+};
+
+void ChattablesTest::updateBeginListSize(int listSize) {
+ beginListSize_ = listSize;
+ callsToBegin_++;
+}
+
+void ChattablesTest::updateEndListSize() {
+ endListSize_ = chattables_.get().size();
+ callsToEnd_++;
+}
+
+TEST_F(ChattablesTest, testAddJID) {
+ chattables_.onBeginAdd.connect([this](int listSize){ updateBeginListSize(listSize); });
+ chattables_.onAdded.connect([this](){ updateEndListSize(); });
+ JID jid("user@swift.jid");
+
+ chattables_.addJID(jid, Chattables::State::Type::Person);
+ ASSERT_EQ(0, beginListSize_);
+ ASSERT_EQ(1, endListSize_);
+ ASSERT_EQ(1, callsToBegin_);
+ ASSERT_EQ(1, callsToEnd_);
+
+ ASSERT_EQ(jid, chattables_.get()[0]);
+ Chattables::State state = chattables_.getState(jid);
+ ASSERT_EQ(jid, state.jid);
+ ASSERT_EQ(Chattables::State::Type::Person, state.type);
+}
+
+TEST_F(ChattablesTest, testAddMultipleJIDs) {
+ chattables_.onBeginAdd.connect([this](int listSize){ updateBeginListSize(listSize); });
+ chattables_.onAdded.connect([this](){ updateEndListSize(); });
+ JID jid0("user0@swift.jid");
+ JID jid1("user1@swift.jid");
+ JID jid2("user2@swift.jid");
+
+ chattables_.addJID(jid0, Chattables::State::Type::Person);
+ ASSERT_EQ(0, beginListSize_);
+ ASSERT_EQ(1, endListSize_);
+ ASSERT_EQ(1, callsToBegin_);
+ ASSERT_EQ(1, callsToEnd_);
+ chattables_.addJID(jid1, Chattables::State::Type::Person);
+ ASSERT_EQ(1, beginListSize_);
+ ASSERT_EQ(2, endListSize_);
+ ASSERT_EQ(2, callsToBegin_);
+ ASSERT_EQ(2, callsToEnd_);
+ chattables_.addJID(jid2, Chattables::State::Type::Person);
+ ASSERT_EQ(2, beginListSize_);
+ ASSERT_EQ(3, endListSize_);
+ ASSERT_EQ(3, callsToBegin_);
+ ASSERT_EQ(3, callsToEnd_);
+}
+
+TEST_F(ChattablesTest, testAddRoomJID) {
+ chattables_.onBeginAdd.connect([this](int listSize){ updateBeginListSize(listSize); });
+ chattables_.onAdded.connect([this](){ updateEndListSize(); });
+ JID jid("room@swift.jid");
+
+ chattables_.addJID(jid, Chattables::State::Type::Room);
+ ASSERT_EQ(0, beginListSize_);
+ ASSERT_EQ(1, endListSize_);
+ ASSERT_EQ(1, callsToBegin_);
+ ASSERT_EQ(1, callsToEnd_);
+
+ ASSERT_EQ(jid, chattables_.get()[0]);
+ Chattables::State state = chattables_.getState(jid);
+ ASSERT_EQ(jid, state.jid);
+ ASSERT_EQ(Chattables::State::Type::Room, state.type);
+}
+
+TEST_F(ChattablesTest, testSetState) {
+ JID jid("user@swift.jid");
+ chattables_.addJID(jid, Chattables::State::Type::Person);
+ ASSERT_EQ(1, chattables_.get().size());
+ ASSERT_EQ(jid, chattables_.get()[0]);
+ ASSERT_EQ(Chattables::State::Type::Person, chattables_.getState(jid).type);
+ ASSERT_EQ(StatusShow::None, chattables_.getState(jid).status);
+
+ JID returnedJID;
+ int returnedIndex;
+ int callsToChanged = 0;
+ chattables_.onChanged.connect([&returnedJID, &returnedIndex, &callsToChanged](const JID& jid, int index){
+ returnedJID = jid;
+ returnedIndex = index;
+ callsToChanged++;
+ });
+
+ Chattables::State newState;
+ newState.jid = jid;
+ newState.type = Chattables::State::Type::Room;
+ newState.status = StatusShow::Online;
+ chattables_.setState(jid, newState);
+
+ auto storedState = chattables_.getState(jid);
+
+ ASSERT_EQ(1, chattables_.get().size());
+ ASSERT_EQ(jid, chattables_.get()[0]);
+ ASSERT_EQ(jid, returnedJID);
+ ASSERT_EQ(0, returnedIndex);
+ ASSERT_EQ(1, callsToChanged);
+ ASSERT_EQ(jid, storedState.jid);
+ ASSERT_EQ(Chattables::State::Type::Room, storedState.type);
+ ASSERT_EQ(StatusShow::Online, storedState.status);
+}
diff --git a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
index 1f69f4f..5339c7b 100644
--- a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
+++ b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
@@ -1,13 +1,14 @@
/*
- * Copyright (c) 2010-2017 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#include <boost/algorithm/string.hpp>
-#include <cppunit/extensions/HelperMacros.h>
-#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <memory>
+
+#include <gtest/gtest.h>
#include <hippomocks.h>
#include <Swiften/Avatars/NullAvatarManager.h>
@@ -32,10 +33,12 @@
#include <Swiften/VCards/VCardMemoryStorage.h>
#include <Swift/Controllers/Chat/ChatMessageParser.h>
+#include <Swift/Controllers/Chat/Chattables.h>
#include <Swift/Controllers/Chat/MUCController.h>
#include <Swift/Controllers/Chat/UserSearchController.h>
#include <Swift/Controllers/Roster/GroupRosterItem.h>
#include <Swift/Controllers/Roster/Roster.h>
+#include <Swift/Controllers/SettingConstants.h>
#include <Swift/Controllers/Settings/DummySettingsProvider.h>
#include <Swift/Controllers/UIEvents/UIEventStream.h>
#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
@@ -44,587 +47,918 @@
#include <Swift/Controllers/UnitTest/MockChatWindow.h>
#include <Swift/Controllers/XMPPEvents/EventController.h>
+// Clang wrongly things that tests for 0 are using 0 as null.
+#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
+
using namespace Swift;
-class MUCControllerTest : public CppUnit::TestFixture {
- CPPUNIT_TEST_SUITE(MUCControllerTest);
- CPPUNIT_TEST(testJoinPartStringContructionSimple);
- CPPUNIT_TEST(testJoinPartStringContructionMixed);
- CPPUNIT_TEST(testAppendToJoinParts);
- CPPUNIT_TEST(testAddressedToSelf);
- CPPUNIT_TEST(testNotAddressedToSelf);
- CPPUNIT_TEST(testAddressedToSelfBySelf);
- CPPUNIT_TEST(testMessageWithEmptyLabelItem);
- CPPUNIT_TEST(testMessageWithLabelItem);
- CPPUNIT_TEST(testCorrectMessageWithLabelItem);
- CPPUNIT_TEST(testRoleAffiliationStates);
- CPPUNIT_TEST(testSubjectChangeCorrect);
- CPPUNIT_TEST(testSubjectChangeIncorrectA);
- CPPUNIT_TEST(testSubjectChangeIncorrectB);
- CPPUNIT_TEST(testSubjectChangeIncorrectC);
- CPPUNIT_TEST(testHandleOccupantNicknameChanged);
- CPPUNIT_TEST(testHandleOccupantNicknameChangedRoster);
- CPPUNIT_TEST(testHandleChangeSubjectRequest);
-
- CPPUNIT_TEST(testNonImpromptuMUCWindowTitle);
-
- CPPUNIT_TEST_SUITE_END();
-
-public:
- void setUp() {
- crypto_ = std::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create());
- self_ = JID("girl@wonderland.lit/rabbithole");
- nick_ = "aLiCe";
- mucJID_ = JID("teaparty@rooms.wonderland.lit");
- mocks_ = new MockRepository();
- stanzaChannel_ = new DummyStanzaChannel();
- iqChannel_ = new DummyIQChannel();
- iqRouter_ = new IQRouter(iqChannel_);
- eventController_ = new EventController();
- chatWindowFactory_ = mocks_->InterfaceMock<ChatWindowFactory>();
- userSearchWindowFactory_ = mocks_->InterfaceMock<UserSearchWindowFactory>();
- xmppRoster_ = new XMPPRosterImpl();
- presenceOracle_ = new PresenceOracle(stanzaChannel_, xmppRoster_);
- presenceSender_ = new StanzaChannelPresenceSender(stanzaChannel_);
- directedPresenceSender_ = new DirectedPresenceSender(presenceSender_);
- uiEventStream_ = new UIEventStream();
- avatarManager_ = new NullAvatarManager();
- TimerFactory* timerFactory = nullptr;
- window_ = new MockChatWindow();
- mucRegistry_ = new MUCRegistry();
- entityCapsProvider_ = new DummyEntityCapsProvider();
- settings_ = new DummySettingsProvider();
- highlightManager_ = new HighlightManager(settings_);
- highlightManager_->resetToDefaultConfiguration();
- muc_ = std::make_shared<MockMUC>(mucJID_);
- mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(muc_->getJID(), uiEventStream_).Return(window_);
- chatMessageParser_ = std::make_shared<ChatMessageParser>(std::map<std::string, std::string>(), highlightManager_->getConfiguration(), ChatMessageParser::Mode::GroupChat);
- vcardStorage_ = new VCardMemoryStorage(crypto_.get());
- vcardManager_ = new VCardManager(self_, iqRouter_, vcardStorage_);
- nickResolver_ = new NickResolver(self_, xmppRoster_, vcardManager_, mucRegistry_);
- clientBlockListManager_ = new ClientBlockListManager(iqRouter_);
- mucBookmarkManager_ = new MUCBookmarkManager(iqRouter_);
- controller_ = new MUCController (self_, muc_, boost::optional<std::string>(), nick_, stanzaChannel_, iqRouter_, chatWindowFactory_, nickResolver_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory, eventController_, entityCapsProvider_, nullptr, nullptr, mucRegistry_, highlightManager_, clientBlockListManager_, chatMessageParser_, false, nullptr, vcardManager_, mucBookmarkManager_);
- }
+class MUCControllerTest : public ::testing::Test {
+
+ protected:
+ void SetUp() {
+ crypto_ = std::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create());
+ self_ = JID("girl@wonderland.lit/rabbithole");
+ nick_ = "aLiCe";
+ mucJID_ = JID("teaparty@rooms.wonderland.lit");
+ mocks_ = new MockRepository();
+ stanzaChannel_ = new DummyStanzaChannel();
+ iqChannel_ = new DummyIQChannel();
+ iqRouter_ = new IQRouter(iqChannel_);
+ eventController_ = new EventController();
+ chatWindowFactory_ = mocks_->InterfaceMock<ChatWindowFactory>();
+ userSearchWindowFactory_ = mocks_->InterfaceMock<UserSearchWindowFactory>();
+ xmppRoster_ = new XMPPRosterImpl();
+ presenceOracle_ = new PresenceOracle(stanzaChannel_, xmppRoster_);
+ presenceSender_ = new StanzaChannelPresenceSender(stanzaChannel_);
+ directedPresenceSender_ = new DirectedPresenceSender(presenceSender_);
+ uiEventStream_ = new UIEventStream();
+ avatarManager_ = new NullAvatarManager();
+ TimerFactory* timerFactory = nullptr;
+ window_ = new MockChatWindow();
+ mucRegistry_ = new MUCRegistry();
+ entityCapsProvider_ = new DummyEntityCapsProvider();
+ settings_ = new DummySettingsProvider();
+ highlightManager_ = new HighlightManager(settings_);
+ highlightManager_->resetToDefaultConfiguration();
+ muc_ = std::make_shared<MockMUC>(mucJID_);
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(muc_->getJID(), uiEventStream_).Return(window_);
+ chatMessageParser_ = std::make_shared<ChatMessageParser>(std::map<std::string, std::string>(), highlightManager_->getConfiguration(), ChatMessageParser::Mode::GroupChat);
+ vcardStorage_ = new VCardMemoryStorage(crypto_.get());
+ vcardManager_ = new VCardManager(self_, iqRouter_, vcardStorage_);
+ nickResolver_ = new NickResolver(self_, xmppRoster_, vcardManager_, mucRegistry_);
+ clientBlockListManager_ = new ClientBlockListManager(iqRouter_);
+ mucBookmarkManager_ = new MUCBookmarkManager(iqRouter_);
+ chattables_ = std::make_unique<Chattables>();
+ controller_ = new MUCController (self_, muc_, boost::optional<std::string>(), nick_, stanzaChannel_, iqRouter_, chatWindowFactory_, nickResolver_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory, eventController_, entityCapsProvider_, nullptr, nullptr, mucRegistry_, highlightManager_, clientBlockListManager_, chatMessageParser_, false, nullptr, vcardManager_, mucBookmarkManager_, settings_, *chattables_);
+ }
- void tearDown() {
- delete controller_;
- delete mucBookmarkManager_;
- delete clientBlockListManager_;
- delete nickResolver_;
- delete vcardManager_;
- delete vcardStorage_;
- delete highlightManager_;
- delete settings_;
- delete entityCapsProvider_;
- delete eventController_;
- delete presenceOracle_;
- delete xmppRoster_;
- delete mocks_;
- delete uiEventStream_;
- delete stanzaChannel_;
- delete presenceSender_;
- delete directedPresenceSender_;
- delete iqRouter_;
- delete iqChannel_;
- delete mucRegistry_;
- delete avatarManager_;
- }
+ void TearDown() {
+ delete controller_;
+ delete mucBookmarkManager_;
+ delete clientBlockListManager_;
+ delete nickResolver_;
+ delete vcardManager_;
+ delete vcardStorage_;
+ delete highlightManager_;
+ delete settings_;
+ delete entityCapsProvider_;
+ delete eventController_;
+ delete presenceOracle_;
+ delete xmppRoster_;
+ delete mocks_;
+ delete uiEventStream_;
+ delete stanzaChannel_;
+ delete presenceSender_;
+ delete directedPresenceSender_;
+ delete iqRouter_;
+ delete iqChannel_;
+ delete mucRegistry_;
+ delete avatarManager_;
+ }
- void finishJoin() {
- Presence::ref presence(new Presence());
- presence->setFrom(JID(muc_->getJID().toString() + "/" + nick_));
- MUCUserPayload::ref status(new MUCUserPayload());
- MUCUserPayload::StatusCode code;
- code.code = 110;
- status->addStatusCode(code);
- presence->addPayload(status);
- stanzaChannel_->onPresenceReceived(presence);
- }
+ void finishJoin() {
+ Presence::ref presence(new Presence());
+ presence->setFrom(JID(muc_->getJID().toString() + "/" + nick_));
+ MUCUserPayload::ref status(new MUCUserPayload());
+ MUCUserPayload::StatusCode code;
+ code.code = 110;
+ status->addStatusCode(code);
+ presence->addPayload(status);
+ stanzaChannel_->onPresenceReceived(presence);
+ }
- void joinCompleted() {
- std::string messageBody("test message");
- window_->onSendMessageRequest(messageBody, false);
- std::shared_ptr<Stanza> rawStanza = stanzaChannel_->sentStanzas[stanzaChannel_->sentStanzas.size() - 1];
- Message::ref message = std::dynamic_pointer_cast<Message>(rawStanza);
- CPPUNIT_ASSERT(stanzaChannel_->isAvailable()); /* Otherwise will prevent sends. */
- CPPUNIT_ASSERT(message);
- CPPUNIT_ASSERT_EQUAL(messageBody, message->getBody().get_value_or(""));
-
- {
- Message::ref message = std::make_shared<Message>();
- message->setType(Message::Groupchat);
- message->setTo(self_);
- message->setFrom(mucJID_.withResource("SomeNickname"));
- message->setID(iqChannel_->getNewIQID());
- message->setSubject("Initial");
+ void joinCompleted() {
+ std::string messageBody("test message");
+ window_->onSendMessageRequest(messageBody, false);
+ std::shared_ptr<Stanza> rawStanza = stanzaChannel_->sentStanzas[stanzaChannel_->sentStanzas.size() - 1];
+ Message::ref message = std::dynamic_pointer_cast<Message>(rawStanza);
+ ASSERT_TRUE(stanzaChannel_->isAvailable()); /* Otherwise will prevent sends. */
+ ASSERT_TRUE(message);
+ ASSERT_EQ(messageBody, message->getBody().get_value_or(""));
+
+ {
+ Message::ref message = std::make_shared<Message>();
+ message->setType(Message::Groupchat);
+ message->setTo(self_);
+ message->setFrom(mucJID_.withResource("SomeNickname"));
+ message->setID(iqChannel_->getNewIQID());
+ message->setSubject("Initial");
+
+ controller_->handleIncomingMessage(std::make_shared<MessageEvent>(message));
+ }
+ }
- controller_->handleIncomingMessage(std::make_shared<MessageEvent>(message));
+ void checkEqual(const std::vector<NickJoinPart>& expected, const std::vector<NickJoinPart>& actual) {
+ ASSERT_EQ(expected.size(), actual.size());
+ for (size_t i = 0; i < expected.size(); i++) {
+ ASSERT_EQ(expected[i].nick, actual[i].nick);
+ ASSERT_EQ(expected[i].type, actual[i].type);
+ }
+ }
+
+ JID jidFromOccupant(const MUCOccupant& occupant) {
+ return JID(mucJID_.toString()+"/"+occupant.getNick());
}
- }
- void testAddressedToSelf() {
- finishJoin();
- Message::ref message(new Message());
+ void testRoleAffiliationStatesVerify(const std::map<std::string, MUCOccupant> &occupants) {
+ /* verify that the roster is in sync */
+ GroupRosterItem* group = window_->getRosterModel()->getRoot();
+ for (auto rosterItem : group->getChildren()) {
+ GroupRosterItem* child = dynamic_cast<GroupRosterItem*>(rosterItem);
+ ASSERT_TRUE(child);
+ for (auto childItem : child->getChildren()) {
+ ContactRosterItem* item = dynamic_cast<ContactRosterItem*>(childItem);
+ ASSERT_TRUE(item);
+ std::map<std::string, MUCOccupant>::const_iterator occupant = occupants.find(item->getJID().getResource());
+ ASSERT_TRUE(occupant != occupants.end());
+ ASSERT_TRUE(item->getMUCRole() == occupant->second.getRole());
+ ASSERT_TRUE(item->getMUCAffiliation() == occupant->second.getAffiliation());
+ }
+ }
+ }
- message = Message::ref(new Message());
- message->setFrom(JID(muc_->getJID().toString() + "/otherperson"));
- message->setBody("basic " + nick_ + " test.");
- message->setType(Message::Groupchat);
- controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
- CPPUNIT_ASSERT_EQUAL((size_t)1, eventController_->getEvents().size());
+ void setMUCSecurityMarking(const std::string& markingValue, const std::string& markingForegroundColorValue, const std::string& markingBackgroundColorValue, const bool includeFormTypeField = true) {
+ auto form = std::make_shared<Form>(Form::Type::ResultType);
- message = Message::ref(new Message());
- message->setFrom(JID(muc_->getJID().toString() + "/otherperson"));
- message->setBody(nick_ + ": hi there");
- message->setType(Message::Groupchat);
- controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
- CPPUNIT_ASSERT_EQUAL((size_t)2, eventController_->getEvents().size());
+ if (includeFormTypeField) {
+ std::shared_ptr<FormField> formTypeField = std::make_shared<FormField>(FormField::Type::HiddenType, "http://jabber.org/protocol/muc#roominfo");
+ formTypeField->setName("FORM_TYPE");
+ form->addField(formTypeField);
+ }
- message->setFrom(JID(muc_->getJID().toString() + "/other"));
- message->setBody("Hi there " + nick_);
- message->setType(Message::Groupchat);
- controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
- CPPUNIT_ASSERT_EQUAL((size_t)3, eventController_->getEvents().size());
+ auto markingField = std::make_shared<FormField>(FormField::Type::TextSingleType, markingValue);
+ auto markingForegroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, markingForegroundColorValue);
+ auto markingBackgroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, markingBackgroundColorValue);
- message = Message::ref(new Message());
- message->setFrom(JID(muc_->getJID().toString() + "/other2"));
- message->setBody("Hi " + boost::to_lower_copy(nick_) + ".");
- message->setType(Message::Groupchat);
- controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
+ markingField->setName("x-isode#roominfo_marking");
+ markingForegroundColorField->setName("x-isode#roominfo_marking_fg_color");
+ markingBackgroundColorField->setName("x-isode#roominfo_marking_bg_color");
- // The last message is ignored because self-mention highlights are matched case
- // sensitive against the nickname.
- CPPUNIT_ASSERT_EQUAL((size_t)3, eventController_->getEvents().size());
+ form->addField(markingField);
+ form->addField(markingForegroundColorField);
+ form->addField(markingBackgroundColorField);
- message = Message::ref(new Message());
- message->setFrom(JID(muc_->getJID().toString() + "/other3"));
- message->setBody("Hi bert.");
- message->setType(Message::Groupchat);
- controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
- CPPUNIT_ASSERT_EQUAL((size_t)3, eventController_->getEvents().size());
+ auto discoInfoRef = std::make_shared<DiscoInfo>();
+ discoInfoRef->addExtension(form);
- message = Message::ref(new Message());
- message->setFrom(JID(muc_->getJID().toString() + "/other2"));
- message->setBody("Hi " + boost::to_lower_copy(nick_) + "ie.");
- message->setType(Message::Groupchat);
- controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
- CPPUNIT_ASSERT_EQUAL((size_t)3, eventController_->getEvents().size());
+ auto infoResponse = IQ::createResult(self_, mucJID_, "test-id", discoInfoRef);
+ iqChannel_->onIQReceived(infoResponse);
+ }
+
+ Message::ref createTestMessageWithoutSecurityLabel() {
+ auto message = std::make_shared<Message>();
+ message->setType(Message::Type::Groupchat);
+ message->setID("test-id");
+ message->setTo(self_);
+ message->setFrom(mucJID_.withResource("TestNickname"));
+ message->setBody("Do Not Read This Message");
+ return message;
+ }
+
+ JID self_;
+ JID mucJID_;
+ MockMUC::ref muc_;
+ std::string nick_;
+ DummyStanzaChannel* stanzaChannel_;
+ DummyIQChannel* iqChannel_;
+ IQRouter* iqRouter_;
+ EventController* eventController_;
+ ChatWindowFactory* chatWindowFactory_;
+ UserSearchWindowFactory* userSearchWindowFactory_;
+ MUCController* controller_;
+ NickResolver* nickResolver_;
+ PresenceOracle* presenceOracle_;
+ AvatarManager* avatarManager_;
+ StanzaChannelPresenceSender* presenceSender_;
+ DirectedPresenceSender* directedPresenceSender_;
+ MockRepository* mocks_;
+ UIEventStream* uiEventStream_;
+ MockChatWindow* window_;
+ MUCRegistry* mucRegistry_;
+ DummyEntityCapsProvider* entityCapsProvider_;
+ DummySettingsProvider* settings_;
+ HighlightManager* highlightManager_;
+ std::shared_ptr<ChatMessageParser> chatMessageParser_;
+ std::shared_ptr<CryptoProvider> crypto_;
+ VCardManager* vcardManager_;
+ VCardMemoryStorage* vcardStorage_;
+ ClientBlockListManager* clientBlockListManager_;
+ MUCBookmarkManager* mucBookmarkManager_;
+ XMPPRoster* xmppRoster_;
+ std::unique_ptr<Chattables> chattables_;
+};
+
+TEST_F(MUCControllerTest, testAddressedToSelf) {
+ finishJoin();
+ Message::ref message(new Message());
+
+ message = Message::ref(new Message());
+ message->setFrom(JID(muc_->getJID().toString() + "/otherperson"));
+ message->setBody("basic " + nick_ + " test.");
+ message->setType(Message::Groupchat);
+ controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
+ ASSERT_EQ(1, eventController_->getEvents().size());
+
+ message = Message::ref(new Message());
+ message->setFrom(JID(muc_->getJID().toString() + "/otherperson"));
+ message->setBody(nick_ + ": hi there");
+ message->setType(Message::Groupchat);
+ controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
+ ASSERT_EQ(2, eventController_->getEvents().size());
+
+ message->setFrom(JID(muc_->getJID().toString() + "/other"));
+ message->setBody("Hi there " + nick_);
+ message->setType(Message::Groupchat);
+ controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
+ ASSERT_EQ(3, eventController_->getEvents().size());
+
+ message = Message::ref(new Message());
+ message->setFrom(JID(muc_->getJID().toString() + "/other2"));
+ message->setBody("Hi " + boost::to_lower_copy(nick_) + ".");
+ message->setType(Message::Groupchat);
+ controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
+
+ // The last message is ignored because self-mention highlights are matched case
+ // sensitive against the nickname.
+ ASSERT_EQ(3, eventController_->getEvents().size());
+
+ message = Message::ref(new Message());
+ message->setFrom(JID(muc_->getJID().toString() + "/other3"));
+ message->setBody("Hi bert.");
+ message->setType(Message::Groupchat);
+ controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
+ ASSERT_EQ(3, eventController_->getEvents().size());
+
+ message = Message::ref(new Message());
+ message->setFrom(JID(muc_->getJID().toString() + "/other2"));
+ message->setBody("Hi " + boost::to_lower_copy(nick_) + "ie.");
+ message->setType(Message::Groupchat);
+ controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
+ ASSERT_EQ(3, eventController_->getEvents().size());
+}
+
+TEST_F(MUCControllerTest, testNotAddressedToSelf) {
+ finishJoin();
+ Message::ref message(new Message());
+ message->setFrom(JID(muc_->getJID().toString() + "/other3"));
+ message->setBody("Hi there Hatter");
+ message->setType(Message::Groupchat);
+ controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
+ ASSERT_EQ(0, eventController_->getEvents().size());
+}
+
+TEST_F(MUCControllerTest, testAddressedToSelfBySelf) {
+ finishJoin();
+ Message::ref message(new Message());
+ message->setFrom(JID(muc_->getJID().toString() + "/" + nick_));
+ message->setBody("Hi there " + nick_);
+ message->setType(Message::Groupchat);
+ controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
+ ASSERT_EQ(0, eventController_->getEvents().size());
+}
+
+TEST_F(MUCControllerTest, testMessageWithEmptyLabelItem) {
+ SecurityLabelsCatalog::Item label;
+ label.setSelector("Bob");
+ window_->label_ = label;
+ std::shared_ptr<DiscoInfo> features = std::make_shared<DiscoInfo>();
+ features->addFeature(DiscoInfo::SecurityLabelsCatalogFeature);
+ controller_->setAvailableServerFeatures(features);
+ IQ::ref iq = iqChannel_->iqs_[iqChannel_->iqs_.size() - 1];
+ SecurityLabelsCatalog::ref labelPayload = std::make_shared<SecurityLabelsCatalog>();
+ labelPayload->addItem(label);
+ IQ::ref result = IQ::createResult(self_, iq->getID(), labelPayload);
+ iqChannel_->onIQReceived(result);
+ std::string messageBody("agamemnon");
+ window_->onSendMessageRequest(messageBody, false);
+ std::shared_ptr<Stanza> rawStanza = stanzaChannel_->sentStanzas[stanzaChannel_->sentStanzas.size() - 1];
+ Message::ref message = std::dynamic_pointer_cast<Message>(rawStanza);
+ ASSERT_EQ(iq->getTo(), result->getFrom());
+ ASSERT_TRUE(window_->labelsEnabled_);
+ ASSERT_TRUE(stanzaChannel_->isAvailable()); /* Otherwise will prevent sends. */
+ ASSERT_TRUE(message);
+ ASSERT_EQ(messageBody, message->getBody().get());
+ ASSERT_FALSE(message->getPayload<SecurityLabel>());
+}
+
+TEST_F(MUCControllerTest, testMessageWithLabelItem) {
+ std::shared_ptr<SecurityLabel> label = std::make_shared<SecurityLabel>();
+ label->setLabel("a");
+ SecurityLabelsCatalog::Item labelItem;
+ labelItem.setSelector("Bob");
+ labelItem.setLabel(label);
+ window_->label_ = labelItem;
+ std::shared_ptr<DiscoInfo> features = std::make_shared<DiscoInfo>();
+ features->addFeature(DiscoInfo::SecurityLabelsCatalogFeature);
+ controller_->setAvailableServerFeatures(features);
+ IQ::ref iq = iqChannel_->iqs_[iqChannel_->iqs_.size() - 1];
+ SecurityLabelsCatalog::ref labelPayload = std::make_shared<SecurityLabelsCatalog>();
+ labelPayload->addItem(labelItem);
+ IQ::ref result = IQ::createResult(self_, iq->getID(), labelPayload);
+ iqChannel_->onIQReceived(result);
+ std::string messageBody("agamemnon");
+ window_->onSendMessageRequest(messageBody, false);
+ std::shared_ptr<Stanza> rawStanza = stanzaChannel_->sentStanzas[stanzaChannel_->sentStanzas.size() - 1];
+ Message::ref message = std::dynamic_pointer_cast<Message>(rawStanza);
+ ASSERT_EQ(iq->getTo(), result->getFrom());
+ ASSERT_TRUE(window_->labelsEnabled_);
+ ASSERT_TRUE(stanzaChannel_->isAvailable()); /* Otherwise will prevent sends. */
+ ASSERT_TRUE(message);
+ ASSERT_EQ(messageBody, message->getBody().get());
+ ASSERT_EQ(label, message->getPayload<SecurityLabel>());
+}
+
+TEST_F(MUCControllerTest, testCorrectMessageWithLabelItem) {
+ std::shared_ptr<SecurityLabel> label = std::make_shared<SecurityLabel>();
+ label->setLabel("a");
+ SecurityLabelsCatalog::Item labelItem;
+ labelItem.setSelector("Bob");
+ labelItem.setLabel(label);
+ std::shared_ptr<SecurityLabel> label2 = std::make_shared<SecurityLabel>();
+ label->setLabel("b");
+ SecurityLabelsCatalog::Item labelItem2;
+ labelItem2.setSelector("Charlie");
+ labelItem2.setLabel(label2);
+ window_->label_ = labelItem;
+ std::shared_ptr<DiscoInfo> features = std::make_shared<DiscoInfo>();
+ features->addFeature(DiscoInfo::SecurityLabelsCatalogFeature);
+ controller_->setAvailableServerFeatures(features);
+ IQ::ref iq = iqChannel_->iqs_[iqChannel_->iqs_.size() - 1];
+ SecurityLabelsCatalog::ref labelPayload = std::make_shared<SecurityLabelsCatalog>();
+ labelPayload->addItem(labelItem);
+ IQ::ref result = IQ::createResult(self_, iq->getID(), labelPayload);
+ iqChannel_->onIQReceived(result);
+ std::string messageBody("agamemnon");
+ window_->onSendMessageRequest(messageBody, false);
+ std::shared_ptr<Stanza> rawStanza = stanzaChannel_->sentStanzas[stanzaChannel_->sentStanzas.size() - 1];
+ Message::ref message = std::dynamic_pointer_cast<Message>(rawStanza);
+ ASSERT_EQ(iq->getTo(), result->getFrom());
+ ASSERT_TRUE(window_->labelsEnabled_);
+ ASSERT_TRUE(stanzaChannel_->isAvailable()); /* Otherwise will prevent sends. */
+ ASSERT_TRUE(message);
+ ASSERT_EQ(messageBody, message->getBody().get());
+ ASSERT_EQ(label, message->getPayload<SecurityLabel>());
+ window_->label_ = labelItem2;
+ window_->onSendMessageRequest(messageBody, true);
+ rawStanza = stanzaChannel_->sentStanzas[stanzaChannel_->sentStanzas.size() - 1];
+ message = std::dynamic_pointer_cast<Message>(rawStanza);
+ ASSERT_EQ(messageBody, message->getBody().get());
+ ASSERT_EQ(label, message->getPayload<SecurityLabel>());
+}
+
+TEST_F(MUCControllerTest, testAppendToJoinParts) {
+ std::vector<NickJoinPart> list;
+ std::vector<NickJoinPart> gold;
+ MUCController::appendToJoinParts(list, NickJoinPart("Kev", Join));
+ gold.push_back(NickJoinPart("Kev", Join));
+ checkEqual(gold, list);
+ MUCController::appendToJoinParts(list, NickJoinPart("Remko", Join));
+ gold.push_back(NickJoinPart("Remko", Join));
+ checkEqual(gold, list);
+ MUCController::appendToJoinParts(list, NickJoinPart("Bert", Join));
+ gold.push_back(NickJoinPart("Bert", Join));
+ checkEqual(gold, list);
+ MUCController::appendToJoinParts(list, NickJoinPart("Bert", Part));
+ gold[2].type = JoinThenPart;
+ checkEqual(gold, list);
+ MUCController::appendToJoinParts(list, NickJoinPart("Kev", Part));
+ gold[0].type = JoinThenPart;
+ checkEqual(gold, list);
+ MUCController::appendToJoinParts(list, NickJoinPart("Remko", Part));
+ gold[1].type = JoinThenPart;
+ checkEqual(gold, list);
+ MUCController::appendToJoinParts(list, NickJoinPart("Ernie", Part));
+ gold.push_back(NickJoinPart("Ernie", Part));
+ checkEqual(gold, list);
+ MUCController::appendToJoinParts(list, NickJoinPart("Ernie", Join));
+ gold[3].type = PartThenJoin;
+ checkEqual(gold, list);
+ MUCController::appendToJoinParts(list, NickJoinPart("Kev", Join));
+ gold[0].type = Join;
+ checkEqual(gold, list);
+ MUCController::appendToJoinParts(list, NickJoinPart("Ernie", Part));
+ gold[3].type = Part;
+ checkEqual(gold, list);
+
+}
+
+TEST_F(MUCControllerTest, testJoinPartStringContructionSimple) {
+ std::vector<NickJoinPart> list;
+ list.push_back(NickJoinPart("Kev", Join));
+ ASSERT_EQ(std::string("Kev has entered the room"), MUCController::generateJoinPartString(list, false));
+ list.push_back(NickJoinPart("Remko", Part));
+ ASSERT_EQ(std::string("Kev has entered the room and Remko has left the room"), MUCController::generateJoinPartString(list, false));
+ list.push_back(NickJoinPart("Bert", Join));
+ ASSERT_EQ(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));
+ ASSERT_EQ(std::string("Kev, Bert and Ernie have entered the room and Remko has left the room"), MUCController::generateJoinPartString(list, false));
+}
+
+TEST_F(MUCControllerTest, testJoinPartStringContructionMixed) {
+ std::vector<NickJoinPart> list;
+ list.push_back(NickJoinPart("Kev", JoinThenPart));
+ ASSERT_EQ(std::string("Kev has entered then left the room"), MUCController::generateJoinPartString(list, false));
+ list.push_back(NickJoinPart("Remko", Part));
+ ASSERT_EQ(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));
+ ASSERT_EQ(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));
+ ASSERT_EQ(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));
+}
+
+TEST_F(MUCControllerTest, testRoleAffiliationStates) {
+
+ typedef std::map<std::string, MUCOccupant> occupant_map;
+ occupant_map occupants;
+ occupants.insert(occupant_map::value_type("Kev", MUCOccupant("Kev", MUCOccupant::Participant, MUCOccupant::Owner)));
+ occupants.insert(occupant_map::value_type("Remko", MUCOccupant("Remko", MUCOccupant::Participant, MUCOccupant::Owner)));
+ occupants.insert(occupant_map::value_type("Bert", MUCOccupant("Bert", MUCOccupant::Participant, MUCOccupant::Owner)));
+ occupants.insert(occupant_map::value_type("Ernie", MUCOccupant("Ernie", MUCOccupant::Participant, MUCOccupant::Owner)));
+
+ /* populate the MUC with fake users */
+ for (auto&& occupant : occupants) {
+ muc_->insertOccupant(occupant.second);
}
- void testNotAddressedToSelf() {
- finishJoin();
- Message::ref message(new Message());
- message->setFrom(JID(muc_->getJID().toString() + "/other3"));
- message->setBody("Hi there Hatter");
- message->setType(Message::Groupchat);
- controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
- CPPUNIT_ASSERT_EQUAL((size_t)0, eventController_->getEvents().size());
+ std::vector<MUCOccupant> alterations;
+ alterations.push_back(MUCOccupant("Kev", MUCOccupant::Visitor, MUCOccupant::Admin));
+ alterations.push_back(MUCOccupant("Remko", MUCOccupant::Moderator, MUCOccupant::Member));
+ alterations.push_back(MUCOccupant("Bert", MUCOccupant::Visitor, MUCOccupant::Outcast));
+ alterations.push_back(MUCOccupant("Ernie", MUCOccupant::NoRole, MUCOccupant::Member));
+ alterations.push_back(MUCOccupant("Bert", MUCOccupant::Moderator, MUCOccupant::Owner));
+ alterations.push_back(MUCOccupant("Kev", MUCOccupant::Participant, MUCOccupant::Outcast));
+ alterations.push_back(MUCOccupant("Bert", MUCOccupant::Visitor, MUCOccupant::NoAffiliation));
+ alterations.push_back(MUCOccupant("Remko", MUCOccupant::NoRole, MUCOccupant::NoAffiliation));
+ alterations.push_back(MUCOccupant("Ernie", MUCOccupant::Visitor, MUCOccupant::Outcast));
+
+ for (const auto& alteration : alterations) {
+ /* perform an alteration to a user's role and affiliation */
+ occupant_map::iterator occupant = occupants.find(alteration.getNick());
+ ASSERT_TRUE(occupant != occupants.end());
+ const JID jid = jidFromOccupant(occupant->second);
+ /* change the affiliation, leave the role in place */
+ muc_->changeAffiliation(jid, alteration.getAffiliation());
+ occupant->second = MUCOccupant(occupant->first, occupant->second.getRole(), alteration.getAffiliation());
+ testRoleAffiliationStatesVerify(occupants);
+ /* change the role, leave the affiliation in place */
+ muc_->changeOccupantRole(jid, alteration.getRole());
+ occupant->second = MUCOccupant(occupant->first, alteration.getRole(), occupant->second.getAffiliation());
+ testRoleAffiliationStatesVerify(occupants);
}
+}
+
+TEST_F(MUCControllerTest, testSubjectChangeCorrect) {
+ joinCompleted();
- void testAddressedToSelfBySelf() {
- finishJoin();
- Message::ref message(new Message());
- message->setFrom(JID(muc_->getJID().toString() + "/" + nick_));
- message->setBody("Hi there " + nick_);
+ {
+ Message::ref message = std::make_shared<Message>();
message->setType(Message::Groupchat);
- controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
- CPPUNIT_ASSERT_EQUAL((size_t)0, eventController_->getEvents().size());
- }
+ message->setTo(self_);
+ message->setFrom(mucJID_.withResource("SomeNickname"));
+ message->setID("3FB99C56-7C92-4755-91B0-9C0098BC7AE0");
+ message->setSubject("New Room Subject");
- void testMessageWithEmptyLabelItem() {
- SecurityLabelsCatalog::Item label;
- label.setSelector("Bob");
- window_->label_ = label;
- std::shared_ptr<DiscoInfo> features = std::make_shared<DiscoInfo>();
- features->addFeature(DiscoInfo::SecurityLabelsCatalogFeature);
- controller_->setAvailableServerFeatures(features);
- IQ::ref iq = iqChannel_->iqs_[iqChannel_->iqs_.size() - 1];
- SecurityLabelsCatalog::ref labelPayload = std::make_shared<SecurityLabelsCatalog>();
- labelPayload->addItem(label);
- IQ::ref result = IQ::createResult(self_, iq->getID(), labelPayload);
- iqChannel_->onIQReceived(result);
- std::string messageBody("agamemnon");
- window_->onSendMessageRequest(messageBody, false);
- std::shared_ptr<Stanza> rawStanza = stanzaChannel_->sentStanzas[stanzaChannel_->sentStanzas.size() - 1];
- Message::ref message = std::dynamic_pointer_cast<Message>(rawStanza);
- CPPUNIT_ASSERT_EQUAL(iq->getTo(), result->getFrom());
- CPPUNIT_ASSERT(window_->labelsEnabled_);
- CPPUNIT_ASSERT(stanzaChannel_->isAvailable()); /* Otherwise will prevent sends. */
- CPPUNIT_ASSERT(message);
- CPPUNIT_ASSERT_EQUAL(messageBody, message->getBody().get());
- CPPUNIT_ASSERT(!message->getPayload<SecurityLabel>());
+ controller_->handleIncomingMessage(std::make_shared<MessageEvent>(message));
+ ASSERT_EQ(std::string("The room subject is now: New Room Subject"), std::dynamic_pointer_cast<ChatWindow::ChatTextMessagePart>(window_->lastAddedSystemMessage_.getParts()[0])->text);
}
+}
- void testMessageWithLabelItem() {
- std::shared_ptr<SecurityLabel> label = std::make_shared<SecurityLabel>();
- label->setLabel("a");
- SecurityLabelsCatalog::Item labelItem;
- labelItem.setSelector("Bob");
- labelItem.setLabel(label);
- window_->label_ = labelItem;
- std::shared_ptr<DiscoInfo> features = std::make_shared<DiscoInfo>();
- features->addFeature(DiscoInfo::SecurityLabelsCatalogFeature);
- controller_->setAvailableServerFeatures(features);
- IQ::ref iq = iqChannel_->iqs_[iqChannel_->iqs_.size() - 1];
- SecurityLabelsCatalog::ref labelPayload = std::make_shared<SecurityLabelsCatalog>();
- labelPayload->addItem(labelItem);
- IQ::ref result = IQ::createResult(self_, iq->getID(), labelPayload);
- iqChannel_->onIQReceived(result);
- std::string messageBody("agamemnon");
- window_->onSendMessageRequest(messageBody, false);
- std::shared_ptr<Stanza> rawStanza = stanzaChannel_->sentStanzas[stanzaChannel_->sentStanzas.size() - 1];
- Message::ref message = std::dynamic_pointer_cast<Message>(rawStanza);
- CPPUNIT_ASSERT_EQUAL(iq->getTo(), result->getFrom());
- CPPUNIT_ASSERT(window_->labelsEnabled_);
- CPPUNIT_ASSERT(stanzaChannel_->isAvailable()); /* Otherwise will prevent sends. */
- CPPUNIT_ASSERT(message);
- CPPUNIT_ASSERT_EQUAL(messageBody, message->getBody().get());
- CPPUNIT_ASSERT_EQUAL(label, message->getPayload<SecurityLabel>());
- }
+/*
+ * Test that message stanzas with subject element and non-empty body element do not cause a subject change.
+ */
+TEST_F(MUCControllerTest, testSubjectChangeIncorrectA) {
+ joinCompleted();
- void testCorrectMessageWithLabelItem() {
- std::shared_ptr<SecurityLabel> label = std::make_shared<SecurityLabel>();
- label->setLabel("a");
- SecurityLabelsCatalog::Item labelItem;
- labelItem.setSelector("Bob");
- labelItem.setLabel(label);
- std::shared_ptr<SecurityLabel> label2 = std::make_shared<SecurityLabel>();
- label->setLabel("b");
- SecurityLabelsCatalog::Item labelItem2;
- labelItem2.setSelector("Charlie");
- labelItem2.setLabel(label2);
- window_->label_ = labelItem;
- std::shared_ptr<DiscoInfo> features = std::make_shared<DiscoInfo>();
- features->addFeature(DiscoInfo::SecurityLabelsCatalogFeature);
- controller_->setAvailableServerFeatures(features);
- IQ::ref iq = iqChannel_->iqs_[iqChannel_->iqs_.size() - 1];
- SecurityLabelsCatalog::ref labelPayload = std::make_shared<SecurityLabelsCatalog>();
- labelPayload->addItem(labelItem);
- IQ::ref result = IQ::createResult(self_, iq->getID(), labelPayload);
- iqChannel_->onIQReceived(result);
- std::string messageBody("agamemnon");
- window_->onSendMessageRequest(messageBody, false);
- std::shared_ptr<Stanza> rawStanza = stanzaChannel_->sentStanzas[stanzaChannel_->sentStanzas.size() - 1];
- Message::ref message = std::dynamic_pointer_cast<Message>(rawStanza);
- CPPUNIT_ASSERT_EQUAL(iq->getTo(), result->getFrom());
- CPPUNIT_ASSERT(window_->labelsEnabled_);
- CPPUNIT_ASSERT(stanzaChannel_->isAvailable()); /* Otherwise will prevent sends. */
- CPPUNIT_ASSERT(message);
- CPPUNIT_ASSERT_EQUAL(messageBody, message->getBody().get());
- CPPUNIT_ASSERT_EQUAL(label, message->getPayload<SecurityLabel>());
- window_->label_ = labelItem2;
- window_->onSendMessageRequest(messageBody, true);
- rawStanza = stanzaChannel_->sentStanzas[stanzaChannel_->sentStanzas.size() - 1];
- message = std::dynamic_pointer_cast<Message>(rawStanza);
- CPPUNIT_ASSERT_EQUAL(messageBody, message->getBody().get());
- CPPUNIT_ASSERT_EQUAL(label, message->getPayload<SecurityLabel>());
+ {
+ Message::ref message = std::make_shared<Message>();
+ message->setType(Message::Groupchat);
+ message->setTo(self_);
+ message->setFrom(mucJID_.withResource("SomeNickname"));
+ message->setID(iqChannel_->getNewIQID());
+ message->setSubject("New Room Subject");
+ message->setBody("Some body text that prevents this stanza from being a subject change.");
+
+ controller_->handleIncomingMessage(std::make_shared<MessageEvent>(message));
+ ASSERT_EQ(std::string("Trying to enter room teaparty@rooms.wonderland.lit"), std::dynamic_pointer_cast<ChatWindow::ChatTextMessagePart>(window_->lastAddedSystemMessage_.getParts()[0])->text);
}
+}
- void checkEqual(const std::vector<NickJoinPart>& expected, const std::vector<NickJoinPart>& actual) {
- CPPUNIT_ASSERT_EQUAL(expected.size(), actual.size());
- for (size_t i = 0; i < expected.size(); i++) {
- CPPUNIT_ASSERT_EQUAL(expected[i].nick, actual[i].nick);
- CPPUNIT_ASSERT_EQUAL(expected[i].type, actual[i].type);
- }
+/*
+ * Test that message stanzas with subject element and thread element do not cause a subject change.
+ */
+TEST_F(MUCControllerTest, testSubjectChangeIncorrectB) {
+ joinCompleted();
+
+ {
+ Message::ref message = std::make_shared<Message>();
+ message->setType(Message::Groupchat);
+ message->setTo(self_);
+ message->setFrom(mucJID_.withResource("SomeNickname"));
+ message->setID(iqChannel_->getNewIQID());
+ message->setSubject("New Room Subject");
+ message->addPayload(std::make_shared<Thread>("Thread that prevents the subject change."));
+
+ controller_->handleIncomingMessage(std::make_shared<MessageEvent>(message));
+ ASSERT_EQ(std::string("Trying to enter room teaparty@rooms.wonderland.lit"), std::dynamic_pointer_cast<ChatWindow::ChatTextMessagePart>(window_->lastAddedSystemMessage_.getParts()[0])->text);
}
+}
- void testAppendToJoinParts() {
- std::vector<NickJoinPart> list;
- std::vector<NickJoinPart> gold;
- MUCController::appendToJoinParts(list, NickJoinPart("Kev", Join));
- gold.push_back(NickJoinPart("Kev", Join));
- checkEqual(gold, list);
- MUCController::appendToJoinParts(list, NickJoinPart("Remko", Join));
- gold.push_back(NickJoinPart("Remko", Join));
- checkEqual(gold, list);
- MUCController::appendToJoinParts(list, NickJoinPart("Bert", Join));
- gold.push_back(NickJoinPart("Bert", Join));
- checkEqual(gold, list);
- MUCController::appendToJoinParts(list, NickJoinPart("Bert", Part));
- gold[2].type = JoinThenPart;
- checkEqual(gold, list);
- MUCController::appendToJoinParts(list, NickJoinPart("Kev", Part));
- gold[0].type = JoinThenPart;
- checkEqual(gold, list);
- MUCController::appendToJoinParts(list, NickJoinPart("Remko", Part));
- gold[1].type = JoinThenPart;
- checkEqual(gold, list);
- MUCController::appendToJoinParts(list, NickJoinPart("Ernie", Part));
- gold.push_back(NickJoinPart("Ernie", Part));
- checkEqual(gold, list);
- MUCController::appendToJoinParts(list, NickJoinPart("Ernie", Join));
- gold[3].type = PartThenJoin;
- checkEqual(gold, list);
- MUCController::appendToJoinParts(list, NickJoinPart("Kev", Join));
- gold[0].type = Join;
- checkEqual(gold, list);
- MUCController::appendToJoinParts(list, NickJoinPart("Ernie", Part));
- gold[3].type = Part;
- checkEqual(gold, list);
+/*
+ * Test that message stanzas with subject element and empty body element do not cause a subject change.
+ */
+TEST_F(MUCControllerTest, testSubjectChangeIncorrectC) {
+ joinCompleted();
+ {
+ Message::ref message = std::make_shared<Message>();
+ message->setType(Message::Groupchat);
+ message->setTo(self_);
+ message->setFrom(mucJID_.withResource("SomeNickname"));
+ message->setID(iqChannel_->getNewIQID());
+ message->setSubject("New Room Subject");
+ message->setBody("");
+
+ controller_->handleIncomingMessage(std::make_shared<MessageEvent>(message));
+ ASSERT_EQ(std::string("Trying to enter room teaparty@rooms.wonderland.lit"), std::dynamic_pointer_cast<ChatWindow::ChatTextMessagePart>(window_->lastAddedSystemMessage_.getParts()[0])->text);
}
+}
+
+TEST_F(MUCControllerTest, testHandleOccupantNicknameChanged) {
+ const auto occupantCount = [&](const std::string & nick) {
+ auto roster = window_->getRosterModel();
+ const auto currentOccupantsJIDs = roster->getJIDs();
+ int count = 0;
+ for (auto & p : currentOccupantsJIDs) {
+ if (p.getResource() == nick) {
+ ++count;
+ }
+ }
+ return count;
+ };
+
+ muc_->insertOccupant(MUCOccupant("TestUserOne", MUCOccupant::Participant, MUCOccupant::Owner));
+ muc_->insertOccupant(MUCOccupant("TestUserTwo", MUCOccupant::Participant, MUCOccupant::Owner));
+ muc_->insertOccupant(MUCOccupant("TestUserThree", MUCOccupant::Participant, MUCOccupant::Owner));
+
+ muc_->onOccupantNicknameChanged("TestUserOne", "TestUserTwo");
+
+ ASSERT_EQ(0, occupantCount("TestUserOne"));
+ ASSERT_EQ(1, occupantCount("TestUserTwo"));
+ ASSERT_EQ(1, occupantCount("TestUserThree"));
+}
+
+TEST_F(MUCControllerTest, testHandleOccupantNicknameChangedRoster) {
+ const auto occupantCount = [&](const std::string & nick) {
+ auto roster = window_->getRosterModel();
+ const auto participants = roster->getGroup("Participants");
+ const auto displayedParticipants = participants->getDisplayedChildren();
+ int count = 0;
+ for (auto & p : displayedParticipants) {
+ if (p->getDisplayName() == nick) {
+ ++count;
+ }
+ }
+ return count;
+ };
+
+ muc_->insertOccupant(MUCOccupant("TestUserOne", MUCOccupant::Participant, MUCOccupant::Owner));
+ muc_->insertOccupant(MUCOccupant("TestUserTwo", MUCOccupant::Participant, MUCOccupant::Owner));
+ muc_->insertOccupant(MUCOccupant("TestUserThree", MUCOccupant::Participant, MUCOccupant::Owner));
+ ASSERT_EQ(1, occupantCount("TestUserOne"));
+ ASSERT_EQ(1, occupantCount("TestUserTwo"));
+ ASSERT_EQ(1, occupantCount("TestUserThree"));
+
+ muc_->onOccupantNicknameChanged("TestUserOne", "TestUserTwo");
+
+ ASSERT_EQ(0, occupantCount("TestUserOne"));
+ ASSERT_EQ(1, occupantCount("TestUserTwo"));
+ ASSERT_EQ(1, occupantCount("TestUserThree"));
+}
+
+TEST_F(MUCControllerTest, testHandleChangeSubjectRequest) {
+ std::string testStr("New Subject");
+ ASSERT_EQ(std::string(""), muc_->newSubjectSet_);
+ window_->onChangeSubjectRequest(testStr);
+ ASSERT_EQ(testStr, muc_->newSubjectSet_);
+}
+
+TEST_F(MUCControllerTest, testNonImpromptuMUCWindowTitle) {
+ ASSERT_EQ(muc_->getJID().getNode(), window_->name_);
+}
+
+TEST_F(MUCControllerTest, testSecurityMarkingRequestCompleteMarking) {
+ setMUCSecurityMarking("Test|Highest Possible Security", "Black", "Red", true);
+
+ ASSERT_EQ(std::string("Test|Highest Possible Security"), window_->markingValue_);
+ ASSERT_EQ(std::string("Black"), window_->markingForegroundColorValue_);
+ ASSERT_EQ(std::string("Red"), window_->markingBackgroundColorValue_);
+}
+
+TEST_F(MUCControllerTest, testSecurityMarkingRequestCompleteMarkingWithExtraForm) {
+ auto formTypeField = std::make_shared<FormField>(FormField::Type::HiddenType, "http://jabber.org/protocol/muc#roominfo");
+ auto markingField = std::make_shared<FormField>(FormField::Type::TextSingleType, "Test|Highest Possible Security");
+ auto markingForegroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, "Black");
+ auto markingBackgroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, "Red");
+ formTypeField->setName("FORM_TYPE");
+ markingField->setName("x-isode#roominfo_marking");
+ markingForegroundColorField->setName("x-isode#roominfo_marking_fg_color");
+ markingBackgroundColorField->setName("x-isode#roominfo_marking_bg_color");
+
+ auto extraForm = std::make_shared<Form>(Form::Type::ResultType);
+ auto form = std::make_shared<Form>(Form::Type::ResultType);
+ form->addField(formTypeField);
+ form->addField(markingField);
+ form->addField(markingForegroundColorField);
+ form->addField(markingBackgroundColorField);
+
+ auto discoInfoRef = std::make_shared<DiscoInfo>();
+ discoInfoRef->addExtension(extraForm);
+ discoInfoRef->addExtension(form);
+
+ auto infoResponse = IQ::createResult(self_, mucJID_, "test-id", discoInfoRef);
+ iqChannel_->onIQReceived(infoResponse);
+ ASSERT_EQ(std::string("Test|Highest Possible Security"), window_->markingValue_);
+ ASSERT_EQ(std::string("Black"), window_->markingForegroundColorValue_);
+ ASSERT_EQ(std::string("Red"), window_->markingBackgroundColorValue_);
+}
+
+TEST_F(MUCControllerTest, testSecurityMarkingRequestNoColorsInMarking) {
+ auto formTypeField = std::make_shared<FormField>(FormField::Type::HiddenType, "http://jabber.org/protocol/muc#roominfo");
+ auto markingField = std::make_shared<FormField>(FormField::Type::TextSingleType, "Test|Highest Possible Security");
+ auto markingForegroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, "");
+ auto markingBackgroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, "");
+ formTypeField->setName("FORM_TYPE");
+ markingField->setName("x-isode#roominfo_marking");
+ markingForegroundColorField->setName("x-isode#roominfo_marking_fg_color");
+ markingBackgroundColorField->setName("x-isode#roominfo_marking_bg_color");
+
+ auto form = std::make_shared<Form>(Form::Type::ResultType);
+ form->addField(formTypeField);
+ form->addField(markingField);
+ form->addField(markingForegroundColorField);
+ form->addField(markingBackgroundColorField);
+
+ auto discoInfoRef = std::make_shared<DiscoInfo>();
+ discoInfoRef->addExtension(form);
+
+ auto infoResponse = IQ::createResult(self_, mucJID_, "test-id", discoInfoRef);
+ iqChannel_->onIQReceived(infoResponse);
+ ASSERT_EQ(std::string("Test|Highest Possible Security"), window_->markingValue_);
+ ASSERT_EQ(std::string("Black"), window_->markingForegroundColorValue_);
+ ASSERT_EQ(std::string("White"), window_->markingBackgroundColorValue_);
+}
+
+TEST_F(MUCControllerTest, testSecurityMarkingRequestEmptyMarking) {
+ setMUCSecurityMarking("", "", "", true);
+
+ ASSERT_EQ(std::string(""), window_->markingValue_);
+ ASSERT_EQ(std::string(""), window_->markingForegroundColorValue_);
+ ASSERT_EQ(std::string(""), window_->markingBackgroundColorValue_);
+}
+
+TEST_F(MUCControllerTest, testSecurityMarkingRequestWithMarkingNoFormType) {
+ setMUCSecurityMarking("Test|Highest Possible Security", "Black", "Red", false);
+
+ ASSERT_EQ(std::string(""), window_->markingValue_);
+ ASSERT_EQ(std::string(""), window_->markingForegroundColorValue_);
+ ASSERT_EQ(std::string(""), window_->markingBackgroundColorValue_);
+}
+
+TEST_F(MUCControllerTest, testSecurityMarkingRequestNoMarking) {
+ auto form = std::make_shared<Form>(Form::Type::ResultType);
+
+ auto discoInfoRef = std::make_shared<DiscoInfo>();
+ discoInfoRef->addExtension(form);
+
+ auto infoResponse = IQ::createResult(self_, mucJID_, "test-id", discoInfoRef);
+ iqChannel_->onIQReceived(infoResponse);
+ ASSERT_EQ(std::string(""), window_->markingValue_);
+ ASSERT_EQ(std::string(""), window_->markingForegroundColorValue_);
+ ASSERT_EQ(std::string(""), window_->markingBackgroundColorValue_);
+}
+
+TEST_F(MUCControllerTest, testSecurityMarkingRequestNoForm) {
+ auto discoInfoRef = std::make_shared<DiscoInfo>();
+
+ auto infoResponse = IQ::createResult( self_, mucJID_, "test-id", discoInfoRef);
+ iqChannel_->onIQReceived(infoResponse);
+ ASSERT_EQ(std::string(""), window_->markingValue_);
+ ASSERT_EQ(std::string(""), window_->markingForegroundColorValue_);
+ ASSERT_EQ(std::string(""), window_->markingBackgroundColorValue_);
+}
+
+TEST_F(MUCControllerTest, testSecurityMarkingRequestError) {
+ auto errorPayload = std::make_shared<ErrorPayload>(ErrorPayload::Condition::NotAuthorized, ErrorPayload::Type::Auth);
+
+ auto infoResponse = IQ::createResult( self_, mucJID_, "test-id", errorPayload);
+ iqChannel_->onIQReceived(infoResponse);
+ ASSERT_EQ(std::string(""), window_->markingValue_);
+ ASSERT_EQ(std::string(""), window_->markingForegroundColorValue_);
+ ASSERT_EQ(std::string(""), window_->markingBackgroundColorValue_);
+}
- 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, 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, 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, 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, false));
- }
+TEST_F(MUCControllerTest, testSecurityMarkingAddedToMessage_Elision_NoRoomMarkingA) {
+ settings_->storeSetting(SettingConstants::MUC_MARKING_ELISION, true);
+ setMUCSecurityMarking("", "Black", "Red");
- 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, 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, 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, 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, false));
- }
+ auto messageLabel = std::make_shared<SecurityLabel>();
+ messageLabel->setDisplayMarking("Test|Highest Possible Security");
- JID jidFromOccupant(const MUCOccupant& occupant) {
- return JID(mucJID_.toString()+"/"+occupant.getNick());
- }
+ auto sentMessage = createTestMessageWithoutSecurityLabel();
+ sentMessage->addPayload(messageLabel);
- void testRoleAffiliationStates() {
+ auto sentMessageEvent = std::make_shared<MessageEvent>(sentMessage);
+ controller_->handleIncomingMessage(sentMessageEvent);
- typedef std::map<std::string, MUCOccupant> occupant_map;
- occupant_map occupants;
- occupants.insert(occupant_map::value_type("Kev", MUCOccupant("Kev", MUCOccupant::Participant, MUCOccupant::Owner)));
- occupants.insert(occupant_map::value_type("Remko", MUCOccupant("Remko", MUCOccupant::Participant, MUCOccupant::Owner)));
- occupants.insert(occupant_map::value_type("Bert", MUCOccupant("Bert", MUCOccupant::Participant, MUCOccupant::Owner)));
- occupants.insert(occupant_map::value_type("Ernie", MUCOccupant("Ernie", MUCOccupant::Participant, MUCOccupant::Owner)));
+ auto storedSecurityLabel = window_->lastAddedMessageSecurityLabel_;
- /* populate the MUC with fake users */
- for (auto&& occupant : occupants) {
- muc_->insertOccupant(occupant.second);
- }
+ ASSERT_EQ(false, storedSecurityLabel == nullptr);
+ // This is the potentially altered security label that is displayed on the screen
+ ASSERT_EQ(std::string("Test|Highest Possible Security"), storedSecurityLabel->getDisplayMarking());
+}
- std::vector<MUCOccupant> alterations;
- alterations.push_back(MUCOccupant("Kev", MUCOccupant::Visitor, MUCOccupant::Admin));
- alterations.push_back(MUCOccupant("Remko", MUCOccupant::Moderator, MUCOccupant::Member));
- alterations.push_back(MUCOccupant("Bert", MUCOccupant::Visitor, MUCOccupant::Outcast));
- alterations.push_back(MUCOccupant("Ernie", MUCOccupant::NoRole, MUCOccupant::Member));
- alterations.push_back(MUCOccupant("Bert", MUCOccupant::Moderator, MUCOccupant::Owner));
- alterations.push_back(MUCOccupant("Kev", MUCOccupant::Participant, MUCOccupant::Outcast));
- alterations.push_back(MUCOccupant("Bert", MUCOccupant::Visitor, MUCOccupant::NoAffiliation));
- alterations.push_back(MUCOccupant("Remko", MUCOccupant::NoRole, MUCOccupant::NoAffiliation));
- alterations.push_back(MUCOccupant("Ernie", MUCOccupant::Visitor, MUCOccupant::Outcast));
-
- for (const auto& alteration : alterations) {
- /* perform an alteration to a user's role and affiliation */
- occupant_map::iterator occupant = occupants.find(alteration.getNick());
- CPPUNIT_ASSERT(occupant != occupants.end());
- const JID jid = jidFromOccupant(occupant->second);
- /* change the affiliation, leave the role in place */
- muc_->changeAffiliation(jid, alteration.getAffiliation());
- occupant->second = MUCOccupant(occupant->first, occupant->second.getRole(), alteration.getAffiliation());
- testRoleAffiliationStatesVerify(occupants);
- /* change the role, leave the affiliation in place */
- muc_->changeOccupantRole(jid, alteration.getRole());
- occupant->second = MUCOccupant(occupant->first, alteration.getRole(), occupant->second.getAffiliation());
- testRoleAffiliationStatesVerify(occupants);
- }
- }
+TEST_F(MUCControllerTest, testSecurityMarkingAddedToMessage_Elision_NoRoomMarkingB) {
+ settings_->storeSetting(SettingConstants::MUC_MARKING_ELISION, true);
+ setMUCSecurityMarking("", "Black", "Red");
- void testSubjectChangeCorrect() {
- joinCompleted();
+ auto messageLabel = std::make_shared<SecurityLabel>();
+ messageLabel->setDisplayMarking("");
- {
- Message::ref message = std::make_shared<Message>();
- message->setType(Message::Groupchat);
- message->setTo(self_);
- message->setFrom(mucJID_.withResource("SomeNickname"));
- message->setID("3FB99C56-7C92-4755-91B0-9C0098BC7AE0");
- message->setSubject("New Room Subject");
+ auto sentMessage = createTestMessageWithoutSecurityLabel();
+ sentMessage->addPayload(messageLabel);
- controller_->handleIncomingMessage(std::make_shared<MessageEvent>(message));
- CPPUNIT_ASSERT_EQUAL(std::string("The room subject is now: New Room Subject"), std::dynamic_pointer_cast<ChatWindow::ChatTextMessagePart>(window_->lastAddedSystemMessage_.getParts()[0])->text);
- }
- }
+ auto sentMessageEvent = std::make_shared<MessageEvent>(sentMessage);
+ controller_->handleIncomingMessage(sentMessageEvent);
- /*
- * Test that message stanzas with subject element and non-empty body element do not cause a subject change.
- */
- void testSubjectChangeIncorrectA() {
- joinCompleted();
+ auto storedSecurityLabel = window_->lastAddedMessageSecurityLabel_;
- {
- Message::ref message = std::make_shared<Message>();
- message->setType(Message::Groupchat);
- message->setTo(self_);
- message->setFrom(mucJID_.withResource("SomeNickname"));
- message->setID(iqChannel_->getNewIQID());
- message->setSubject("New Room Subject");
- message->setBody("Some body text that prevents this stanza from being a subject change.");
+ ASSERT_EQ(false, storedSecurityLabel == nullptr);
+ // This is the potentially altered security label that is displayed on the screen
+ ASSERT_EQ(std::string(""), storedSecurityLabel->getDisplayMarking());
+}
- controller_->handleIncomingMessage(std::make_shared<MessageEvent>(message));
- CPPUNIT_ASSERT_EQUAL(std::string("Trying to enter room teaparty@rooms.wonderland.lit"), std::dynamic_pointer_cast<ChatWindow::ChatTextMessagePart>(window_->lastAddedSystemMessage_.getParts()[0])->text);
- }
- }
+TEST_F(MUCControllerTest, testSecurityMarkingAddedToMessage_Elision_WithRoomMarkingA) {
+ settings_->storeSetting(SettingConstants::MUC_MARKING_ELISION, true);
+ setMUCSecurityMarking("Test|Highest Possible Security", "Black", "Red");
- /*
- * Test that message stanzas with subject element and thread element do not cause a subject change.
- */
- void testSubjectChangeIncorrectB() {
- joinCompleted();
+ auto messageLabel = std::make_shared<SecurityLabel>();
+ messageLabel->setDisplayMarking("Test|Highest Possible Security");
- {
- Message::ref message = std::make_shared<Message>();
- message->setType(Message::Groupchat);
- message->setTo(self_);
- message->setFrom(mucJID_.withResource("SomeNickname"));
- message->setID(iqChannel_->getNewIQID());
- message->setSubject("New Room Subject");
- message->addPayload(std::make_shared<Thread>("Thread that prevents the subject change."));
+ auto sentMessage = createTestMessageWithoutSecurityLabel();
+ sentMessage->addPayload(messageLabel);
- controller_->handleIncomingMessage(std::make_shared<MessageEvent>(message));
- CPPUNIT_ASSERT_EQUAL(std::string("Trying to enter room teaparty@rooms.wonderland.lit"), std::dynamic_pointer_cast<ChatWindow::ChatTextMessagePart>(window_->lastAddedSystemMessage_.getParts()[0])->text);
- }
- }
+ // Test the first message matching MUC marking. This message SHOULD have a marking
- /*
- * Test that message stanzas with subject element and empty body element do not cause a subject change.
- */
- void testSubjectChangeIncorrectC() {
- joinCompleted();
+ auto sentMessageEvent1 = std::make_shared<MessageEvent>(sentMessage);
+ controller_->handleIncomingMessage(sentMessageEvent1);
- {
- Message::ref message = std::make_shared<Message>();
- message->setType(Message::Groupchat);
- message->setTo(self_);
- message->setFrom(mucJID_.withResource("SomeNickname"));
- message->setID(iqChannel_->getNewIQID());
- message->setSubject("New Room Subject");
- message->setBody("");
+ auto storedSecurityLabel1 = window_->lastAddedMessageSecurityLabel_;
- controller_->handleIncomingMessage(std::make_shared<MessageEvent>(message));
- CPPUNIT_ASSERT_EQUAL(std::string("Trying to enter room teaparty@rooms.wonderland.lit"), std::dynamic_pointer_cast<ChatWindow::ChatTextMessagePart>(window_->lastAddedSystemMessage_.getParts()[0])->text);
- }
- }
+ ASSERT_EQ(false, storedSecurityLabel1 == nullptr);
+ // This is the potentially altered security label that is displayed on the screen
+ ASSERT_EQ(std::string("Test|Highest Possible Security"), storedSecurityLabel1->getDisplayMarking());
- void testHandleOccupantNicknameChanged() {
- const auto occupantCount = [&](const std::string & nick) {
- auto roster = window_->getRosterModel();
- CPPUNIT_ASSERT(roster != nullptr);
- const auto currentOccupantsJIDs = roster->getJIDs();
- int count = 0;
- for (auto & p : currentOccupantsJIDs) {
- if (p.getResource() == nick) {
- ++count;
- }
- }
- return count;
- };
+ // Test a consecutive message matching MUC marking. This message SHOULD NOT have a marking
- muc_->insertOccupant(MUCOccupant("TestUserOne", MUCOccupant::Participant, MUCOccupant::Owner));
- muc_->insertOccupant(MUCOccupant("TestUserTwo", MUCOccupant::Participant, MUCOccupant::Owner));
- muc_->insertOccupant(MUCOccupant("TestUserThree", MUCOccupant::Participant, MUCOccupant::Owner));
+ auto sentMessageEvent2 = std::make_shared<MessageEvent>(sentMessage);
+ controller_->handleIncomingMessage(sentMessageEvent2);
- muc_->onOccupantNicknameChanged("TestUserOne", "TestUserTwo");
+ auto storedSecurityLabel2 = window_->lastAddedMessageSecurityLabel_;
- CPPUNIT_ASSERT_EQUAL(0, occupantCount("TestUserOne"));
- CPPUNIT_ASSERT_EQUAL(1, occupantCount("TestUserTwo"));
- CPPUNIT_ASSERT_EQUAL(1, occupantCount("TestUserThree"));
- }
+ ASSERT_EQ(false, storedSecurityLabel2 == nullptr);
+ // This is the potentially altered security label that is displayed on the screen
+ ASSERT_EQ(std::string(""), storedSecurityLabel2->getDisplayMarking());
+}
- void testHandleOccupantNicknameChangedRoster() {
- const auto occupantCount = [&](const std::string & nick) {
- auto roster = window_->getRosterModel();
- CPPUNIT_ASSERT(roster != nullptr);
- const auto participants = roster->getGroup("Participants");
- CPPUNIT_ASSERT(participants != nullptr);
- const auto displayedParticipants = participants->getDisplayedChildren();
- int count = 0;
- for (auto & p : displayedParticipants) {
- if (p->getDisplayName() == nick) {
- ++count;
- }
- }
- return count;
- };
+TEST_F(MUCControllerTest, testSecurityMarkingAddedToMessage_Elision_WithRoomMarkingB) {
+ settings_->storeSetting(SettingConstants::MUC_MARKING_ELISION, true);
+ setMUCSecurityMarking("Test|Lower Security Marking", "Black", "Red");
- muc_->insertOccupant(MUCOccupant("TestUserOne", MUCOccupant::Participant, MUCOccupant::Owner));
- muc_->insertOccupant(MUCOccupant("TestUserTwo", MUCOccupant::Participant, MUCOccupant::Owner));
- muc_->insertOccupant(MUCOccupant("TestUserThree", MUCOccupant::Participant, MUCOccupant::Owner));
- CPPUNIT_ASSERT_EQUAL(1, occupantCount("TestUserOne"));
- CPPUNIT_ASSERT_EQUAL(1, occupantCount("TestUserTwo"));
- CPPUNIT_ASSERT_EQUAL(1, occupantCount("TestUserThree"));
+ auto messageLabel = std::make_shared<SecurityLabel>();
+ messageLabel->setDisplayMarking("Test|Highest Possible Security");
- muc_->onOccupantNicknameChanged("TestUserOne", "TestUserTwo");
+ auto sentMessage = createTestMessageWithoutSecurityLabel();
+ sentMessage->addPayload(messageLabel);
- CPPUNIT_ASSERT_EQUAL(0, occupantCount("TestUserOne"));
- CPPUNIT_ASSERT_EQUAL(1, occupantCount("TestUserTwo"));
- CPPUNIT_ASSERT_EQUAL(1, occupantCount("TestUserThree"));
- }
+ auto sentMessageEvent = std::make_shared<MessageEvent>(sentMessage);
+ controller_->handleIncomingMessage(sentMessageEvent);
- void testRoleAffiliationStatesVerify(const std::map<std::string, MUCOccupant> &occupants) {
- /* verify that the roster is in sync */
- GroupRosterItem* group = window_->getRosterModel()->getRoot();
- for (auto rosterItem : group->getChildren()) {
- GroupRosterItem* child = dynamic_cast<GroupRosterItem*>(rosterItem);
- CPPUNIT_ASSERT(child);
- for (auto childItem : child->getChildren()) {
- ContactRosterItem* item = dynamic_cast<ContactRosterItem*>(childItem);
- CPPUNIT_ASSERT(item);
- std::map<std::string, MUCOccupant>::const_iterator occupant = occupants.find(item->getJID().getResource());
- CPPUNIT_ASSERT(occupant != occupants.end());
- CPPUNIT_ASSERT(item->getMUCRole() == occupant->second.getRole());
- CPPUNIT_ASSERT(item->getMUCAffiliation() == occupant->second.getAffiliation());
- }
- }
- }
+ auto storedSecurityLabel = window_->lastAddedMessageSecurityLabel_;
- void testHandleChangeSubjectRequest() {
- std::string testStr("New Subject");
- CPPUNIT_ASSERT_EQUAL(std::string(""), muc_->newSubjectSet_);
- window_->onChangeSubjectRequest(testStr);
- CPPUNIT_ASSERT_EQUAL(testStr, muc_->newSubjectSet_);
- }
+ ASSERT_EQ(false, storedSecurityLabel == nullptr);
+ // This is the potentially altered security label that is displayed on the screen
+ ASSERT_EQ(std::string("Test|Highest Possible Security"), storedSecurityLabel->getDisplayMarking());
+}
- void testNonImpromptuMUCWindowTitle() {
- CPPUNIT_ASSERT_EQUAL(muc_->getJID().getNode(), window_->name_);
- }
+TEST_F(MUCControllerTest, testSecurityMarkingAddedToMessage_Elision_WithRoomMarkingC) {
+ settings_->storeSetting(SettingConstants::MUC_MARKING_ELISION, true);
+ setMUCSecurityMarking("Test|Highest Possible Security", "Black", "Red");
-private:
- JID self_;
- JID mucJID_;
- MockMUC::ref muc_;
- std::string nick_;
- DummyStanzaChannel* stanzaChannel_;
- DummyIQChannel* iqChannel_;
- IQRouter* iqRouter_;
- EventController* eventController_;
- ChatWindowFactory* chatWindowFactory_;
- UserSearchWindowFactory* userSearchWindowFactory_;
- MUCController* controller_;
- NickResolver* nickResolver_;
- PresenceOracle* presenceOracle_;
- AvatarManager* avatarManager_;
- StanzaChannelPresenceSender* presenceSender_;
- DirectedPresenceSender* directedPresenceSender_;
- MockRepository* mocks_;
- UIEventStream* uiEventStream_;
- MockChatWindow* window_;
- MUCRegistry* mucRegistry_;
- DummyEntityCapsProvider* entityCapsProvider_;
- DummySettingsProvider* settings_;
- HighlightManager* highlightManager_;
- std::shared_ptr<ChatMessageParser> chatMessageParser_;
- std::shared_ptr<CryptoProvider> crypto_;
- VCardManager* vcardManager_;
- VCardMemoryStorage* vcardStorage_;
- ClientBlockListManager* clientBlockListManager_;
- MUCBookmarkManager* mucBookmarkManager_;
- XMPPRoster* xmppRoster_;
-};
+ auto messageLabel = std::make_shared<SecurityLabel>();
+ messageLabel->setDisplayMarking("");
+
+ auto sentMessage = createTestMessageWithoutSecurityLabel();
+ sentMessage->addPayload(messageLabel);
+
+ auto sentMessageEvent = std::make_shared<MessageEvent>(sentMessage);
+ controller_->handleIncomingMessage(sentMessageEvent);
+
+ auto storedSecurityLabel = window_->lastAddedMessageSecurityLabel_;
+
+ ASSERT_EQ(false, storedSecurityLabel == nullptr);
+ // This is the potentially altered security label that is displayed on the screen
+ ASSERT_EQ(std::string("Unmarked"), storedSecurityLabel->getDisplayMarking());
+}
+
+TEST_F(MUCControllerTest, testSecurityMarkingAddedToMessage_NoElision_NoRoomMarkingA) {
+ settings_->storeSetting(SettingConstants::MUC_MARKING_ELISION, false);
+ setMUCSecurityMarking("", "Black", "Red");
+
+ auto messageLabel = std::make_shared<SecurityLabel>();
+ messageLabel->setDisplayMarking("Test|Highest Possible Security");
+
+ auto sentMessage = createTestMessageWithoutSecurityLabel();
+ sentMessage->addPayload(messageLabel);
+
+ auto sentMessageEvent = std::make_shared<MessageEvent>(sentMessage);
+ controller_->handleIncomingMessage(sentMessageEvent);
+
+ auto storedSecurityLabel = window_->lastAddedMessageSecurityLabel_;
+
+ ASSERT_EQ(false, storedSecurityLabel == nullptr);
+ // This is the potentially altered security label that is displayed on the screen
+ ASSERT_EQ(std::string("Test|Highest Possible Security"), storedSecurityLabel->getDisplayMarking());
+}
+
+TEST_F(MUCControllerTest, testSecurityMarkingAddedToMessage_NoElision_NoRoomMarkingB) {
+ settings_->storeSetting(SettingConstants::MUC_MARKING_ELISION, false);
+ setMUCSecurityMarking("", "Black", "Red");
+
+ auto messageLabel = std::make_shared<SecurityLabel>();
+ messageLabel->setDisplayMarking("");
+
+ auto sentMessage = createTestMessageWithoutSecurityLabel();
+ sentMessage->addPayload(messageLabel);
+
+ auto sentMessageEvent = std::make_shared<MessageEvent>(sentMessage);
+ controller_->handleIncomingMessage(sentMessageEvent);
+
+ auto storedSecurityLabel = window_->lastAddedMessageSecurityLabel_;
+
+ ASSERT_EQ(false, storedSecurityLabel == nullptr);
+ // This is the potentially altered security label that is displayed on the screen
+ ASSERT_EQ(std::string(""), storedSecurityLabel->getDisplayMarking());
+}
+
+TEST_F(MUCControllerTest, testSecurityMarkingAddedToMessage_NoElision_WithRoomMarkingA) {
+ settings_->storeSetting(SettingConstants::MUC_MARKING_ELISION, false);
+ setMUCSecurityMarking("Test|Highest Possible Security", "Black", "Red");
+
+ auto messageLabel = std::make_shared<SecurityLabel>();
+ messageLabel->setDisplayMarking("Test|Highest Possible Security");
+
+ auto sentMessage = createTestMessageWithoutSecurityLabel();
+ sentMessage->addPayload(messageLabel);
+
+ // Test the first message matching MUC marking. This message SHOULD have a marking
+
+ auto sentMessageEvent1 = std::make_shared<MessageEvent>(sentMessage);
+ controller_->handleIncomingMessage(sentMessageEvent1);
+
+ auto storedSecurityLabel1 = window_->lastAddedMessageSecurityLabel_;
+
+ ASSERT_EQ(false, storedSecurityLabel1 == nullptr);
+ // This is the potentially altered security label that is displayed on the screen
+ ASSERT_EQ(std::string("Test|Highest Possible Security"), storedSecurityLabel1->getDisplayMarking());
+
+ // Test a consecutive message matching MUC marking. This message SHOULD ALSO have a marking
+
+ auto sentMessageEvent2 = std::make_shared<MessageEvent>(sentMessage);
+ controller_->handleIncomingMessage(sentMessageEvent2);
+
+ auto storedSecurityLabel2 = window_->lastAddedMessageSecurityLabel_;
+
+ ASSERT_EQ(false, storedSecurityLabel2 == nullptr);
+ // This is the potentially altered security label that is displayed on the screen
+ ASSERT_EQ(std::string("Test|Highest Possible Security"), storedSecurityLabel2->getDisplayMarking());
+}
+
+TEST_F(MUCControllerTest, testSecurityMarkingAddedToMessage_NoElision_WithRoomMarkingB) {
+ settings_->storeSetting(SettingConstants::MUC_MARKING_ELISION, false);
+ setMUCSecurityMarking("", "Black", "Red");
+
+ auto messageLabel = std::make_shared<SecurityLabel>();
+ messageLabel->setDisplayMarking("");
+
+ auto sentMessage = createTestMessageWithoutSecurityLabel();
+ sentMessage->addPayload(messageLabel);
+
+ auto sentMessageEvent = std::make_shared<MessageEvent>(sentMessage);
+ controller_->handleIncomingMessage(sentMessageEvent);
-CPPUNIT_TEST_SUITE_REGISTRATION(MUCControllerTest);
+ auto storedSecurityLabel = window_->lastAddedMessageSecurityLabel_;
+ ASSERT_EQ(false, storedSecurityLabel == nullptr);
+ // This is the potentially altered security label that is displayed on the screen
+ ASSERT_EQ(std::string(""), storedSecurityLabel->getDisplayMarking());
+}
diff --git a/Swift/Controllers/Chat/UnitTest/MockChatListWindow.h b/Swift/Controllers/Chat/UnitTest/MockChatListWindow.h
index 395b050..1d980d3 100644
--- a/Swift/Controllers/Chat/UnitTest/MockChatListWindow.h
+++ b/Swift/Controllers/Chat/UnitTest/MockChatListWindow.h
@@ -20,7 +20,7 @@ namespace Swift {
void removeWhiteboardSession(const JID& /*jid*/) {}
void setBookmarksEnabled(bool /*enabled*/) {}
void setRecents(const std::list<ChatListWindow::Chat>& /*recents*/) {}
- void setUnreadCount(int /*unread*/) {}
+ void setUnreadCount(size_t /*unread*/) {}
void clearBookmarks() {}
void setOnline(bool /*isOnline*/) {}
};
diff --git a/Swift/Controllers/ContactSuggester.cpp b/Swift/Controllers/ContactSuggester.cpp
index eb27ed4..4b621db 100644
--- a/Swift/Controllers/ContactSuggester.cpp
+++ b/Swift/Controllers/ContactSuggester.cpp
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (c) 2014-2016 Isode Limited.
+ * Copyright (c) 2014-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -19,16 +19,12 @@
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/find.hpp>
#include <boost/bind.hpp>
-#include <boost/lambda/bind.hpp>
-#include <boost/lambda/lambda.hpp>
#include <Swiften/Base/Algorithm.h>
#include <Swiften/JID/JID.h>
#include <Swift/Controllers/ContactProvider.h>
-namespace lambda = boost::lambda;
-
namespace Swift {
ContactSuggester::ContactSuggester() {
@@ -60,8 +56,9 @@ std::vector<Contact::ref> ContactSuggester::getSuggestions(const std::string& se
std::sort(results.begin(), results.end(), Contact::lexicographicalSortPredicate);
results.erase(std::unique(results.begin(), results.end(), Contact::equalityPredicate), results.end());
- results.erase(std::remove_if(results.begin(), results.end(), !lambda::bind(&matchContact, search, lambda::_1)),
- results.end());
+ results.erase(std::remove_if(results.begin(), results.end(), [&](const Contact::ref contact) {
+ return !matchContact(search, contact);
+ }), results.end());
std::sort(results.begin(), results.end(), boost::bind(&Contact::sortPredicate, _1, _2, search));
return results;
diff --git a/Swift/Controllers/FdpFormSubmitController.cpp b/Swift/Controllers/FdpFormSubmitController.cpp
new file mode 100644
index 0000000..639b4e9
--- /dev/null
+++ b/Swift/Controllers/FdpFormSubmitController.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <Swift/Controllers/FdpFormSubmitController.h>
+
+#include <Swiften/Disco/GetDiscoItemsRequest.h>
+#include <Swiften/Elements/DiscoItems.h>
+#include <Swiften/Queries/IQRouter.h>
+#include <Swiften/Queries/PubSubRequest.h>
+
+#include <Swift/Controllers/UIEvents/FdpFormSubmitWindowOpenUIEvent.h>
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
+#include <Swift/Controllers/UIInterfaces/FdpFormSubmitWindow.h>
+#include <Swift/Controllers/UIInterfaces/FdpFormSubmitWindowFactory.h>
+
+namespace Swift {
+
+FdpFormSubmitController::FdpFormSubmitController(const JID& self, IQRouter* iqRouter, UIEventStream* uiEventStream, FdpFormSubmitWindowFactory* factory) : selfJID_(self), iqRouter_(iqRouter), uiEventStream_(uiEventStream), factory_(factory), formSubmitWindow_(nullptr) {
+ fdpFormSubmitWindowOpenUIEventConnection_= uiEventStream_->onUIEvent.connect( [this](const std::shared_ptr<UIEvent>& uiEvent){ handleUIEvent(uiEvent); });
+}
+
+FdpFormSubmitController::~FdpFormSubmitController() {
+}
+
+void FdpFormSubmitController::handleUIEvent(const std::shared_ptr<UIEvent>& uiEvent) {
+ if (auto openEvent = std::dynamic_pointer_cast<FdpFormSubmitWindowOpenUIEvent>(uiEvent)) {
+ if (formSubmitWindow_) {
+ formSubmitWindow_->raise();
+ }
+ else {
+ createFormSubmitWindow();
+ }
+ }
+}
+
+void FdpFormSubmitController::createFormSubmitWindow() {
+ formSubmitWindow_ = factory_->createFdpFormSubmitWindow();
+ formSubmitWindow_->onCloseEvent.connect([this](){ closeFormSubmitWindow(); });
+ formSubmitWindow_->onRequestPubSubNodeData.connect([this](const std::string& string){ requestPubSubNodeData(string); });
+ formSubmitWindow_->onRequestTemplateForm.connect([this](const std::string& fdpTemplateNodeName){ requestTemplateForm(fdpTemplateNodeName); });
+ formSubmitWindow_->onSubmitForm.connect([this](const std::shared_ptr<Form>& form){ submitForm(form); });
+ formSubmitWindow_->show();
+}
+
+void FdpFormSubmitController::closeFormSubmitWindow() {
+ formSubmitWindow_.reset();
+}
+
+void FdpFormSubmitController::requestPubSubNodeData(const std::string& domainName) {
+ JID domainJID(domainName);
+ auto discoItemsRequest = GetDiscoItemsRequest::create(domainJID, iqRouter_);
+ discoItemsRequest->onResponse.connect(
+ [this, domainName](std::shared_ptr<DiscoItems> discoItems, ErrorPayload::ref errorPayloadRef) {
+ if (!discoItems || errorPayloadRef) {
+ formSubmitWindow_->showNodePlaceholder(FdpFormSubmitWindow::NodeError::DomainNotFound);
+ return;
+ }
+ currentDomain_ = domainName;
+
+ bool templateNodeAdded = false;
+ formSubmitWindow_->clearNodeData();
+ auto discoItemList = discoItems->getItems();
+ for (auto discoItem : discoItemList) {
+ auto node = discoItem.getNode();
+ if (node.substr(0, 13) != "fdp/template/") {
+ continue;
+ }
+
+ std::string nodeName = discoItem.getName().empty() ? node : discoItem.getName();
+
+ formSubmitWindow_->addNode(node, nodeName);
+ templateNodeAdded = true;
+ }
+ if (!templateNodeAdded) {
+ formSubmitWindow_->showNodePlaceholder(FdpFormSubmitWindow::NodeError::NoFdpNodesInDomain);
+ }
+ }
+ );
+ discoItemsRequest->send();
+}
+
+void FdpFormSubmitController::requestTemplateForm(const std::string& nodeName) {
+ auto pubSubItems = std::make_shared<PubSubItems>(nodeName);
+ pubSubItems->setMaximumItems(1);
+ auto formRequest = std::make_shared<PubSubRequest<PubSubItems>>(IQ::Type::Get, selfJID_, currentDomain_, pubSubItems, iqRouter_);
+
+ formRequest->onResponse.connect(
+ [this, nodeName](std::shared_ptr<PubSubItems> response, ErrorPayload::ref errorPayload) {
+ if (!response || errorPayload) {
+ formSubmitWindow_->showFormPlaceholder(FdpFormSubmitWindow::TemplateError::RequestFailed);
+ return;
+ }
+ auto pubSubItemList = response->getItems();
+ if (pubSubItemList.empty()) {
+ formSubmitWindow_->showFormPlaceholder(FdpFormSubmitWindow::TemplateError::CannotLocateForm);
+ return;
+ }
+ auto payloadList = pubSubItemList[0]->getData();
+ if (payloadList.empty()) {
+ formSubmitWindow_->showFormPlaceholder(FdpFormSubmitWindow::TemplateError::CannotLocateForm);
+ return;
+ }
+ if (auto form = std::dynamic_pointer_cast<Form>(payloadList[0])) {
+ currentTemplateNode_ = nodeName;
+ formSubmitWindow_->setFormData(form);
+ }
+ else {
+ formSubmitWindow_->showFormPlaceholder(FdpFormSubmitWindow::TemplateError::InvalidPayload);
+ return;
+ }
+ }
+ );
+
+ formRequest->send();
+}
+
+void FdpFormSubmitController::submitForm(const std::shared_ptr<Form>& form) {
+ std::string submittedNode = currentTemplateNode_;
+ submittedNode.replace(submittedNode.find("/template/", 0), 10, "/submitted/");
+ auto pubSubItem = std::make_shared<PubSubItem>();
+ auto pubSubItems = std::make_shared<PubSubItems>(submittedNode);
+ auto pubSubPublish = std::make_shared<PubSubPublish>();
+ pubSubPublish->setNode(submittedNode);
+ pubSubPublish->addItem(pubSubItem);
+ pubSubItem->addData(form);
+ pubSubItems->addItem(pubSubItem);
+ auto formRequest = std::make_shared<PubSubRequest<PubSubPublish>>(IQ::Type::Set, selfJID_, currentDomain_, pubSubPublish, iqRouter_);
+
+ formRequest->onResponse.connect(
+ [this](std::shared_ptr<PubSubPublish> response, ErrorPayload::ref errorPayload) {
+ if (!response || errorPayload) {
+ formSubmitWindow_->handleSubmitServerResponse(false);
+ return;
+ }
+ formSubmitWindow_->handleSubmitServerResponse(true);
+ }
+ );
+
+ formRequest->send();
+}
+
+}
diff --git a/Swift/Controllers/FdpFormSubmitController.h b/Swift/Controllers/FdpFormSubmitController.h
new file mode 100644
index 0000000..69db08c
--- /dev/null
+++ b/Swift/Controllers/FdpFormSubmitController.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include <boost/signals2.hpp>
+
+#include <Swiften/JID/JID.h>
+
+namespace Swift {
+ class FdpFormSubmitWindow;
+ class FdpFormSubmitWindowFactory;
+ class Form;
+ class IQRouter;
+ class UIEvent;
+ class UIEventStream;
+
+ class FdpFormSubmitController {
+ public:
+ FdpFormSubmitController(const JID& self, IQRouter* iqRouter, UIEventStream* uiEventStream, FdpFormSubmitWindowFactory* factory);
+ ~FdpFormSubmitController();
+
+ private:
+ void handleUIEvent(const std::shared_ptr<UIEvent>& uiEvent);
+ void createFormSubmitWindow();
+ void closeFormSubmitWindow();
+ void requestPubSubNodeData(const std::string& domainName);
+ void requestTemplateForm(const std::string& nodeName);
+ void submitForm(const std::shared_ptr<Form>& form);
+
+ JID selfJID_;
+ IQRouter* iqRouter_;
+ UIEventStream* uiEventStream_;
+ FdpFormSubmitWindowFactory* factory_;
+ std::unique_ptr<FdpFormSubmitWindow> formSubmitWindow_;
+ std::string currentDomain_;
+ std::string currentTemplateNode_;
+
+ boost::signals2::scoped_connection fdpFormSubmitWindowOpenUIEventConnection_;
+ };
+}
diff --git a/Swift/Controllers/FileTransfer/FileTransferProgressInfo.cpp b/Swift/Controllers/FileTransfer/FileTransferProgressInfo.cpp
index b073017..eddace9 100644
--- a/Swift/Controllers/FileTransfer/FileTransferProgressInfo.cpp
+++ b/Swift/Controllers/FileTransfer/FileTransferProgressInfo.cpp
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (c) 2016 Isode Limited.
+ * Copyright (c) 2016-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -18,13 +18,13 @@
namespace Swift {
-FileTransferProgressInfo::FileTransferProgressInfo(boost::uintmax_t completeBytes) : completeBytes(completeBytes), completedBytes(0), percentage(0) {
+FileTransferProgressInfo::FileTransferProgressInfo(size_t completeBytes) : completeBytes(completeBytes), completedBytes(0), percentage(0) {
onProgressPercentage(0);
}
-void FileTransferProgressInfo::setBytesProcessed(int processedBytes) {
+void FileTransferProgressInfo::setBytesProcessed(size_t processedBytes) {
int oldPercentage = int(double(completedBytes) / double(completeBytes) * 100.0);
- completedBytes += boost::numeric_cast<boost::uintmax_t>(processedBytes);
+ completedBytes += processedBytes;
int newPercentage = int(double(completedBytes) / double(completeBytes) * 100.0);
if (oldPercentage != newPercentage) {
onProgressPercentage(newPercentage);
diff --git a/Swift/Controllers/FileTransfer/FileTransferProgressInfo.h b/Swift/Controllers/FileTransfer/FileTransferProgressInfo.h
index 5fb955c..869ceba 100644
--- a/Swift/Controllers/FileTransfer/FileTransferProgressInfo.h
+++ b/Swift/Controllers/FileTransfer/FileTransferProgressInfo.h
@@ -5,31 +5,32 @@
*/
/*
- * Copyright (c) 2016 Isode Limited.
+ * Copyright (c) 2016-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#pragma once
-#include <boost/cstdint.hpp>
+#include <cstddef>
+
#include <boost/signals2.hpp>
namespace Swift {
class FileTransferProgressInfo {
public:
- FileTransferProgressInfo(boost::uintmax_t completeBytes);
+ FileTransferProgressInfo(size_t completeBytes);
public:
- void setBytesProcessed(int processedBytes);
+ void setBytesProcessed(size_t processedBytes);
int getPercentage() const;
boost::signals2::signal<void (int)> onProgressPercentage;
private:
- boost::uintmax_t completeBytes;
- boost::uintmax_t completedBytes;
+ size_t completeBytes;
+ size_t completedBytes;
int percentage;
};
diff --git a/Swift/Controllers/Roster/LeastCommonSubsequence.h b/Swift/Controllers/Roster/LeastCommonSubsequence.h
index 8daa20c..7988ee7 100644
--- a/Swift/Controllers/Roster/LeastCommonSubsequence.h
+++ b/Swift/Controllers/Roster/LeastCommonSubsequence.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2016 Isode Limited.
+ * Copyright (c) 2011-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -32,7 +32,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 + 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)]);
+ result[i + j*width] = predicate(*(xBegin + static_cast<long long>(i)-1), *(yBegin + static_cast<long long>(j)-1)) ? result[(i-1) + (j-1)*width] + 1 : std::max(result[i + (j-1)*width], result[i-1 + (j*width)]);
}
}
}
diff --git a/Swift/Controllers/Roster/Roster.cpp b/Swift/Controllers/Roster/Roster.cpp
index f6f6ce0..5b7e454 100644
--- a/Swift/Controllers/Roster/Roster.cpp
+++ b/Swift/Controllers/Roster/Roster.cpp
@@ -23,7 +23,7 @@
namespace Swift {
-Roster::Roster(bool sortByStatus, bool fullJIDMapping) : fullJIDMapping_(fullJIDMapping), sortByStatus_(sortByStatus), root_(std::unique_ptr<GroupRosterItem>(new GroupRosterItem("Dummy-Root", nullptr, sortByStatus_))) {
+Roster::Roster(bool sortByStatus, bool fullJIDMapping) : fullJIDMapping_(fullJIDMapping), sortByStatus_(sortByStatus), root_(std::make_unique<GroupRosterItem>("Dummy-Root", nullptr, sortByStatus_)) {
root_->onChildrenChanged.connect(boost::bind(&Roster::handleChildrenChanged, this, root_.get()));
}
diff --git a/Swift/Controllers/Roster/RosterController.cpp b/Swift/Controllers/Roster/RosterController.cpp
index 1d20c4a..90c5ce1 100644
--- a/Swift/Controllers/Roster/RosterController.cpp
+++ b/Swift/Controllers/Roster/RosterController.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -31,6 +31,7 @@
#include <Swiften/Roster/XMPPRosterItem.h>
#include <Swiften/VCards/VCardManager.h>
+#include <Swift/Controllers/Chat/Chattables.h>
#include <Swift/Controllers/Intl.h>
#include <Swift/Controllers/Roster/GroupRosterItem.h>
#include <Swift/Controllers/Roster/ItemOperations/AppearOffline.h>
@@ -49,6 +50,7 @@
#include <Swift/Controllers/UIEvents/RemoveRosterItemUIEvent.h>
#include <Swift/Controllers/UIEvents/RenameGroupUIEvent.h>
#include <Swift/Controllers/UIEvents/RenameRosterItemUIEvent.h>
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
#include <Swift/Controllers/UIInterfaces/MainWindow.h>
#include <Swift/Controllers/UIInterfaces/MainWindowFactory.h>
#include <Swift/Controllers/XMPPEvents/ErrorEvent.h>
@@ -60,14 +62,16 @@ 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, ClientBlockListManager* clientBlockListManager, VCardManager* vcardManager)
- : myJID_(jid), xmppRoster_(xmppRoster), mainWindowFactory_(mainWindowFactory), mainWindow_(mainWindowFactory_->createMainWindow(uiEventStream)), roster_(new Roster()), offlineFilter_(new OfflineRosterFilter()), vcardManager_(vcardManager), avatarManager_(avatarManager), nickManager_(nickManager), nickResolver_(nickResolver), presenceOracle_(presenceOracle), uiEventStream_(uiEventStream), entityCapsManager_(entityCapsManager), clientBlockListManager_(clientBlockListManager) {
+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, ClientBlockListManager* clientBlockListManager, VCardManager* vcardManager, Chattables& chattables)
+ : myJID_(jid), xmppRoster_(xmppRoster), mainWindowFactory_(mainWindowFactory), mainWindow_(mainWindowFactory_->createMainWindow(chattables, uiEventStream)), roster_(new Roster()), offlineFilter_(new OfflineRosterFilter()), vcardManager_(vcardManager), avatarManager_(avatarManager), nickManager_(nickManager), nickResolver_(nickResolver), presenceOracle_(presenceOracle), uiEventStream_(uiEventStream), entityCapsManager_(entityCapsManager), clientBlockListManager_(clientBlockListManager), chattables_(chattables) {
iqRouter_ = iqRouter;
subscriptionManager_ = subscriptionManager;
eventController_ = eventController;
settings_ = settings;
expandiness_ = new RosterGroupExpandinessPersister(roster_, settings);
+#ifndef NOT_YET
mainWindow_->setRosterModel(roster_);
+#endif
rosterVCardProvider_ = new RosterVCardProvider(roster_, vcardManager, JID::WithoutResource);
changeStatusConnection_ = mainWindow_->onChangeStatusRequest.connect(boost::bind(&RosterController::handleChangeStatusRequest, this, _1, _2));
@@ -79,7 +83,7 @@ RosterController::RosterController(const JID& jid, XMPPRoster* xmppRoster, Avata
subscriptionManager_->onPresenceSubscriptionRequest.connect(boost::bind(&RosterController::handleSubscriptionRequest, this, _1, _2));
uiEventConnection_ = uiEventStream->onUIEvent.connect(boost::bind(&RosterController::handleUIEvent, this, _1));
- featureOracle_ = std::unique_ptr<FeatureOracle>(new FeatureOracle(entityCapsManager_, presenceOracle_));
+ featureOracle_ = std::make_unique<FeatureOracle>(entityCapsManager_, presenceOracle_);
vcardManager_->onOwnVCardChanged.connect(boost::bind(&RosterController::handleOwnVCardChanged, this, _1));
avatarManager_->onAvatarChanged.connect(boost::bind(&RosterController::handleAvatarChanged, this, _1));
@@ -148,6 +152,11 @@ void RosterController::handleOnJIDAdded(const JID& jid) {
roster_->addContact(jid, jid, name, QT_TRANSLATE_NOOP("", "Contacts"), avatarManager_->getAvatarPath(jid));
}
applyAllPresenceTo(jid);
+
+ chattables_.addJID(jid, Chattables::State::Type::Person);
+ auto state = chattables_.getState(jid);
+ state.name = name;
+ chattables_.setState(jid, state);
}
void RosterController::applyAllPresenceTo(const JID& jid) {
@@ -329,13 +338,17 @@ void RosterController::handleIncomingPresence(Presence::ref newPresence) {
if (newPresence->getType() == Presence::Error) {
return;
}
- Presence::ref accountPresence = presenceOracle_->getAccountPresence(newPresence->getFrom().toBare());
+ auto bareFrom = newPresence->getFrom().toBare();
+ Presence::ref accountPresence = presenceOracle_->getAccountPresence(bareFrom);
if (!accountPresence) {
accountPresence = Presence::create();
accountPresence->setFrom(newPresence->getFrom());
accountPresence->setType(Presence::Unavailable);
}
roster_->applyOnItems(SetPresence(accountPresence));
+ auto state = chattables_.getState(bareFrom);
+ state.status = accountPresence->getShow();
+ chattables_.setState(bareFrom, state);
}
void RosterController::handleSubscriptionRequest(const JID& jid, const std::string& message) {
diff --git a/Swift/Controllers/Roster/RosterController.h b/Swift/Controllers/Roster/RosterController.h
index ca2ecdc..d5a5671 100644
--- a/Swift/Controllers/Roster/RosterController.h
+++ b/Swift/Controllers/Roster/RosterController.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -24,6 +24,7 @@
namespace Swift {
class AvatarManager;
+ class Chattables;
class ClientBlockListManager;
class EntityCapsProvider;
class EventController;
@@ -49,7 +50,7 @@ namespace Swift {
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, ClientBlockListManager* clientBlockListManager, VCardManager* vcardManager);
+ 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, ClientBlockListManager* clientBlockListManager, VCardManager* vcardManager, Chattables& chattables);
~RosterController();
void showRosterWindow();
void setJID(const JID& jid) { myJID_ = jid; }
@@ -112,6 +113,7 @@ namespace Swift {
UIEventStream* uiEventStream_;
EntityCapsProvider* entityCapsManager_;
ClientBlockListManager* clientBlockListManager_;
+ Chattables& chattables_;
RosterVCardProvider* rosterVCardProvider_;
std::shared_ptr<ContactRosterItem> ownContact_;
std::unique_ptr<FeatureOracle> featureOracle_;
diff --git a/Swift/Controllers/Roster/TableRoster.cpp b/Swift/Controllers/Roster/TableRoster.cpp
index 713f390..01bf4a6 100644
--- a/Swift/Controllers/Roster/TableRoster.cpp
+++ b/Swift/Controllers/Roster/TableRoster.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2016 Isode Limited.
+ * Copyright (c) 2011-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -132,15 +132,20 @@ void TableRoster::handleUpdateTimerTick() {
std::vector<size_t> itemRemoves;
std::vector<size_t> itemInserts;
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() + 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() + 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() + boost::numeric_cast<long long>(end), CreateIndexForSection(sectionPostUpdates[i]));
+ try {
+ size_t end = update.insertedRows.size();
+ update.insertedRows.resize(update.insertedRows.size() + itemInserts.size());
+ 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() + 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() + boost::numeric_cast<long long>(end), CreateIndexForSection(sectionPostUpdates[i]));
+ }
+ catch (const boost::numeric::bad_numeric_cast&) {
+ // If any container claims it has more than long long max items, we have bigger issues, so letting this pass
+ }
}
// Switch the old model with the new
diff --git a/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp b/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp
index 2f15fb5..0a9ea18 100644
--- a/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp
+++ b/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp
@@ -1,9 +1,11 @@
/*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
+#include <memory>
+
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
@@ -32,6 +34,7 @@
#include <Swiften/VCards/VCardManager.h>
#include <Swiften/VCards/VCardMemoryStorage.h>
+#include <Swift/Controllers/Chat/Chattables.h>
#include <Swift/Controllers/Roster/ContactRosterItem.h>
#include <Swift/Controllers/Roster/GroupRosterItem.h>
#include <Swift/Controllers/Roster/Roster.h>
@@ -62,6 +65,7 @@ class RosterControllerTest : public CppUnit::TestFixture {
CPPUNIT_TEST(testRemoveResultsInUnavailablePresence);
CPPUNIT_TEST(testOwnContactInRosterPresence);
CPPUNIT_TEST(testMultiResourceFileTransferFeature);
+ //FIXME: All needs rewriting for new roster
CPPUNIT_TEST_SUITE_END();
public:
@@ -72,7 +76,7 @@ class RosterControllerTest : public CppUnit::TestFixture {
mainWindowFactory_ = new MockMainWindowFactory();
mucRegistry_ = new MUCRegistry();
crypto_ = PlatformCryptoProvider::create();
- storages_ = std::unique_ptr<MemoryStorages>(new MemoryStorages(crypto_));
+ storages_ = std::make_unique<MemoryStorages>(crypto_);
nickResolver_ = new NickResolver(jid_.toBare(), xmppRoster_, nullptr, mucRegistry_);
channel_ = new DummyIQChannel();
router_ = new IQRouter(channel_);
@@ -83,16 +87,17 @@ class RosterControllerTest : public CppUnit::TestFixture {
uiEventStream_ = new UIEventStream();
settings_ = new DummySettingsProvider();
nickManager_ = new DummyNickManager();
- capsManager_ = std::unique_ptr<CapsManager>(new CapsManager(storages_->getCapsStorage(), stanzaChannel_, router_, crypto_));
+ capsManager_ = std::make_unique<CapsManager>(storages_->getCapsStorage(), stanzaChannel_, router_, crypto_);
entityCapsManager_ = new EntityCapsManager(capsManager_.get(), stanzaChannel_);
jingleSessionManager_ = new JingleSessionManager(router_);
clientBlockListManager_ = new ClientBlockListManager(router_);
vcardStorage_ = new VCardMemoryStorage(crypto_);
vcardManager_ = new VCardManager(jid_, router_, vcardStorage_);
- rosterController_ = new RosterController(jid_, xmppRoster_, avatarManager_, mainWindowFactory_, nickManager_, nickResolver_, presenceOracle_, subscriptionManager_, eventController_, uiEventStream_, router_, settings_, entityCapsManager_, clientBlockListManager_, vcardManager_);
+ chattables_ = std::make_unique<Chattables>();
+ rosterController_ = new RosterController(jid_, xmppRoster_, avatarManager_, mainWindowFactory_, nickManager_, nickResolver_, presenceOracle_, subscriptionManager_, eventController_, uiEventStream_, router_, settings_, entityCapsManager_, clientBlockListManager_, vcardManager_, *chattables_);
mainWindow_ = mainWindowFactory_->last;
- capsInfoGenerator_ = std::unique_ptr<CapsInfoGenerator>(new CapsInfoGenerator("", crypto_));
+ capsInfoGenerator_ = std::make_unique<CapsInfoGenerator>("", crypto_);
}
void tearDown() {
@@ -476,6 +481,7 @@ class RosterControllerTest : public CppUnit::TestFixture {
VCardStorage* vcardStorage_;
VCardManager* vcardManager_;
std::unique_ptr<CapsInfoGenerator> capsInfoGenerator_;
+ std::unique_ptr<Chattables> chattables_;
};
CPPUNIT_TEST_SUITE_REGISTRATION(RosterControllerTest);
diff --git a/Swift/Controllers/Roster/UnitTest/RosterTest.cpp b/Swift/Controllers/Roster/UnitTest/RosterTest.cpp
index 5f500d4..045a5e4 100644
--- a/Swift/Controllers/Roster/UnitTest/RosterTest.cpp
+++ b/Swift/Controllers/Roster/UnitTest/RosterTest.cpp
@@ -30,7 +30,7 @@ class RosterTest : public CppUnit::TestFixture {
jid1_ = JID("a@b.c");
jid2_ = JID("b@c.d");
jid3_ = JID("c@d.e");
- roster_ = std::unique_ptr<Roster>(new Roster());
+ roster_ = std::make_unique<Roster>();
}
void testGetGroup() {
diff --git a/Swift/Controllers/Roster/UnitTest/TableRosterTest.cpp b/Swift/Controllers/Roster/UnitTest/TableRosterTest.cpp
index ddc8785..7ebce17 100644
--- a/Swift/Controllers/Roster/UnitTest/TableRosterTest.cpp
+++ b/Swift/Controllers/Roster/UnitTest/TableRosterTest.cpp
@@ -34,8 +34,8 @@ class TableRosterTest : public CppUnit::TestFixture {
public:
void setUp() {
- timerFactory = std::unique_ptr<DummyTimerFactory>(new DummyTimerFactory());
- roster = std::unique_ptr<Roster>(new Roster());
+ timerFactory = std::make_unique<DummyTimerFactory>();
+ roster = std::make_unique<Roster>();
jid1 = JID("jid1@example.com");
jid2 = JID("jid2@example.com");
}
diff --git a/Swift/Controllers/SConscript b/Swift/Controllers/SConscript
index bc5c2c0..3840fbf 100644
--- a/Swift/Controllers/SConscript
+++ b/Swift/Controllers/SConscript
@@ -25,6 +25,7 @@ if env["SCONS_STAGE"] == "build" :
"AdHocController.cpp",
"AdHocManager.cpp",
"BlockListController.cpp",
+ "Chat/Chattables.cpp",
"Chat/ChatController.cpp",
"Chat/ChatControllerBase.cpp",
"Chat/ChatMessageParser.cpp",
@@ -40,6 +41,7 @@ if env["SCONS_STAGE"] == "build" :
"ContactsFromXMPPRoster.cpp",
"EventNotifier.cpp",
"EventWindowController.cpp",
+ "FdpFormSubmitController.cpp",
"FileTransfer/FileTransferController.cpp",
"FileTransfer/FileTransferOverview.cpp",
"FileTransfer/FileTransferProgressInfo.cpp",
@@ -50,7 +52,7 @@ if env["SCONS_STAGE"] == "build" :
"Highlighting/Highlighter.cpp",
"HistoryController.cpp",
"HistoryViewController.cpp",
- "MainController.cpp",
+ "AccountController.cpp",
"PresenceNotifier.cpp",
"PreviousStatusStore.cpp",
"ProfileController.cpp",
@@ -84,6 +86,7 @@ if env["SCONS_STAGE"] == "build" :
"Translator.cpp",
"UIEvents/UIEvent.cpp",
"UIInterfaces/ChatListWindow.cpp",
+ "UIInterfaces/FdpFormSubmitWindow.cpp",
"UIInterfaces/HighlightEditorWindow.cpp",
"UIInterfaces/XMLConsoleWidget.cpp",
"WhiteboardManager.cpp",
@@ -96,6 +99,8 @@ if env["SCONS_STAGE"] == "build" :
File("Chat/UnitTest/ChatListWindowChatTest.cpp"),
File("Chat/UnitTest/ChatMessageParserTest.cpp"),
File("Chat/UnitTest/ChatsManagerTest.cpp"),
+ File("Chat/UnitTest/ChatControllerTest.cpp"),
+ File("Chat/UnitTest/ChattablesTest.cpp"),
File("Chat/UnitTest/MUCControllerTest.cpp"),
File("Roster/UnitTest/LeastCommonSubsequenceTest.cpp"),
File("Roster/UnitTest/RosterControllerTest.cpp"),
@@ -104,6 +109,7 @@ if env["SCONS_STAGE"] == "build" :
File("Settings/UnitTest/SettingsProviderHierachyTest.cpp"),
File("UnitTest/ChatMessageSummarizerTest.cpp"),
File("UnitTest/ContactSuggesterTest.cpp"),
+ File("UnitTest/FdpFormSubmitControllerTest.cpp"),
File("UnitTest/MockChatWindow.cpp"),
File("UnitTest/PresenceNotifierTest.cpp"),
File("UnitTest/PreviousStatusStoreTest.cpp"),
diff --git a/Swift/Controllers/SettingConstants.cpp b/Swift/Controllers/SettingConstants.cpp
index f0064ba..8336200 100644
--- a/Swift/Controllers/SettingConstants.cpp
+++ b/Swift/Controllers/SettingConstants.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2017 Isode Limited.
+ * Copyright (c) 2012-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -14,8 +14,6 @@ const SettingsProvider::Setting<bool> SettingConstants::SHOW_NOTIFICATIONS = Set
const SettingsProvider::Setting<bool> SettingConstants::REQUEST_DELIVERYRECEIPTS = SettingsProvider::Setting<bool>("requestDeliveryReceipts", false);
const SettingsProvider::Setting<bool> SettingConstants::FORGET_PASSWORDS = SettingsProvider::Setting<bool>("forgetPasswords", false);
const SettingsProvider::Setting<bool> SettingConstants::REMEMBER_RECENT_CHATS = SettingsProvider::Setting<bool>("rememberRecentChats", true);
-const SettingsProvider::Setting<std::string> SettingConstants::LAST_LOGIN_JID = SettingsProvider::Setting<std::string>("lastLoginJID", "");
-const SettingsProvider::Setting<bool> SettingConstants::LOGIN_AUTOMATICALLY = SettingsProvider::Setting<bool>("loginAutomatically", false);
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);
@@ -23,6 +21,7 @@ const SettingsProvider::Setting<std::string> SettingConstants::HIGHLIGHT_RULES("
const SettingsProvider::Setting<std::string> SettingConstants::HIGHLIGHT_RULES_V2("highlightRulesV2", "@");
const SettingsProvider::Setting<std::string> SettingConstants::INVITE_AUTO_ACCEPT_MODE("inviteAutoAcceptMode", "presence");
const SettingsProvider::Setting<bool> SettingConstants::DISCONNECT_ON_CARD_REMOVAL("disconnectOnCardRemoval", true);
-const SettingsProvider::Setting<bool> SettingConstants::SINGLE_SIGN_ON("singleSignOn", false);
+const SettingsProvider::Setting<bool> SettingConstants::MUC_MARKING_ELISION("mucMarkingElision", true);
+const SettingsProvider::Setting<bool> SettingConstants::FUTURE("future", false);
}
diff --git a/Swift/Controllers/SettingConstants.h b/Swift/Controllers/SettingConstants.h
index fec2d27..68c22b7 100644
--- a/Swift/Controllers/SettingConstants.h
+++ b/Swift/Controllers/SettingConstants.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2017 Isode Limited.
+ * Copyright (c) 2012-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -34,8 +34,6 @@ namespace Swift {
static const SettingsProvider::Setting<bool> REQUEST_DELIVERYRECEIPTS;
static const SettingsProvider::Setting<bool> FORGET_PASSWORDS;
static const SettingsProvider::Setting<bool> REMEMBER_RECENT_CHATS;
- static const SettingsProvider::Setting<std::string> LAST_LOGIN_JID;
- static const SettingsProvider::Setting<bool> LOGIN_AUTOMATICALLY;
/**
* The #SHOW_OFFLINE setting specifies whether or not to show offline contacts in the
* roster.
@@ -85,13 +83,21 @@ namespace Swift {
*/
static const SettingsProvider::Setting<bool> DISCONNECT_ON_CARD_REMOVAL;
/**
- * The #SINGLE_SIGN_ON setting
- * specifies whether to log in using Single Sign On.
- * This is currently supported on Windows.
+ * The #MUC_MARKING_ELISION setting
+ * specifies whether or not messages with the default muc
+ * marking display their marking, and whether unmarked messages
+ * are marked as such.
*
- * If set true Swift will use GSSAPI authentication to
- * log in the user; else not.
+ * If set true, unmarked messages will be marked with the marking
+ * "unmarked", and messages with the room default marking will
+ * have their markings stripped.
*/
- static const SettingsProvider::Setting<bool> SINGLE_SIGN_ON;
+ static const SettingsProvider::Setting<bool> MUC_MARKING_ELISION;
+
+ /**
+ * The #FUTURE setting enables use of experimental features
+ * planned for future releases.
+ */
+ static const SettingsProvider::Setting<bool> FUTURE;
};
}
diff --git a/Swift/Controllers/Storages/CertificateFileStorage.cpp b/Swift/Controllers/Storages/CertificateFileStorage.cpp
index 3fe6d54..2e1343f 100644
--- a/Swift/Controllers/Storages/CertificateFileStorage.cpp
+++ b/Swift/Controllers/Storages/CertificateFileStorage.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -50,10 +50,15 @@ void CertificateFileStorage::addCertificate(Certificate::ref certificate) {
std::cerr << "ERROR: " << e.what() << std::endl;
}
}
- 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)), boost::numeric_cast<std::streamsize>(data.size()));
- file.close();
+ try {
+ 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)), boost::numeric_cast<std::streamsize>(data.size()));
+ file.close();
+ }
+ catch (...) {
+ SWIFT_LOG(warning) << "Failed to store certificate to " << certificatePath << std::endl;
+ }
}
boost::filesystem::path CertificateFileStorage::getCertificatePath(Certificate::ref certificate) const {
diff --git a/Swift/Controllers/UIEvents/FdpFormSubmitWindowOpenUIEvent.h b/Swift/Controllers/UIEvents/FdpFormSubmitWindowOpenUIEvent.h
new file mode 100644
index 0000000..d540cb2
--- /dev/null
+++ b/Swift/Controllers/UIEvents/FdpFormSubmitWindowOpenUIEvent.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swift/Controllers/UIEvents/UIEvent.h>
+
+namespace Swift {
+ class FdpFormSubmitWindowOpenUIEvent : public UIEvent {
+ public:
+ FdpFormSubmitWindowOpenUIEvent() {
+ }
+ };
+}
diff --git a/Swift/Controllers/UIEvents/JoinMUCUIEvent.h b/Swift/Controllers/UIEvents/JoinMUCUIEvent.h
index 5d6df55..78103a8 100644
--- a/Swift/Controllers/UIEvents/JoinMUCUIEvent.h
+++ b/Swift/Controllers/UIEvents/JoinMUCUIEvent.h
@@ -19,7 +19,7 @@ namespace Swift {
class JoinMUCUIEvent : public UIEvent {
public:
typedef std::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, bool isImpromptu = false, bool isContinuation = false) : jid_(jid), nick_(nick), joinAutomatically_(joinAutomaticallyInFuture), createAsReservedRoomIfNew_(createAsReservedRoomIfNew), password_(password), isImpromptuMUC_(isImpromptu), isContinuation_(isContinuation) {}
+ 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 createAsReservedRoomIfNew = false, bool isImpromptu = false, bool isContinuation = false) : jid_(jid), nick_(nick), 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_;}
diff --git a/Swift/Controllers/UIInterfaces/ChatListWindow.h b/Swift/Controllers/UIInterfaces/ChatListWindow.h
index 29097e9..6aa729b 100644
--- a/Swift/Controllers/UIInterfaces/ChatListWindow.h
+++ b/Swift/Controllers/UIInterfaces/ChatListWindow.h
@@ -26,7 +26,7 @@ namespace Swift {
class Chat {
public:
Chat() : statusType(StatusShow::None), isMUC(false), unreadCount(0), isPrivateMessage(false) {}
- Chat(const JID& jid, const std::string& chatName, const std::string& activity, int unreadCount, StatusShow::Type statusType, const boost::filesystem::path& avatarPath, bool isMUC, bool isPrivateMessage = false, const std::string& nick = "", const boost::optional<std::string> password = boost::optional<std::string>())
+ Chat(const JID& jid, const std::string& chatName, const std::string& activity, size_t unreadCount, StatusShow::Type statusType, const boost::filesystem::path& avatarPath, bool isMUC, bool isPrivateMessage = false, const std::string& nick = "", const boost::optional<std::string> password = boost::optional<std::string>())
: jid(jid), chatName(chatName), activity(activity), statusType(statusType), isMUC(isMUC), nick(nick), password(password), unreadCount(unreadCount), avatarPath(avatarPath), isPrivateMessage(isPrivateMessage) {}
/** Assume that nicks and other transient features aren't important for equality */
bool operator==(const Chat& other) const {
@@ -53,7 +53,7 @@ namespace Swift {
return key_compare(inviteesNames, other.inviteesNames);
}
}
- void setUnreadCount(int unread) {
+ void setUnreadCount(size_t unread) {
unreadCount = unread;
}
void setStatusType(StatusShow::Type type) {
@@ -93,7 +93,7 @@ namespace Swift {
bool isMUC;
std::string nick;
boost::optional<std::string> password;
- int unreadCount;
+ size_t unreadCount;
boost::filesystem::path avatarPath;
std::map<std::string, JID> impromptuJIDs;
std::map<JID, std::string> inviteesNames;
@@ -107,7 +107,7 @@ namespace Swift {
virtual void removeWhiteboardSession(const JID& jid) = 0;
virtual void removeMUCBookmark(const MUCBookmark& bookmark) = 0;
virtual void setRecents(const std::list<Chat>& recents) = 0;
- virtual void setUnreadCount(int unread) = 0;
+ virtual void setUnreadCount(size_t unread) = 0;
virtual void clearBookmarks() = 0;
virtual void setOnline(bool isOnline) = 0;
diff --git a/Swift/Controllers/UIInterfaces/ChatWindow.h b/Swift/Controllers/UIInterfaces/ChatWindow.h
index 8273802..1c36ffc 100644
--- a/Swift/Controllers/UIInterfaces/ChatWindow.h
+++ b/Swift/Controllers/UIInterfaces/ChatWindow.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2017 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -33,6 +33,8 @@ namespace Swift {
class ContactRosterItem;
class FileTransferController;
class UserSearchWindow;
+ class DiscoInfo;
+ class ErrorPayload;
class ChatWindow {
@@ -139,7 +141,7 @@ namespace Swift {
enum AckState {Pending, Received, Failed};
enum ReceiptState {ReceiptRequested, ReceiptReceived, ReceiptFailed};
enum OccupantAction {Kick, Ban, MakeModerator, MakeParticipant, MakeVisitor, AddContact, ShowProfile};
- enum RoomAction {ChangeSubject, Configure, Affiliations, Destroy, Invite};
+ enum RoomAction {ChangeSubject, Configure, Affiliations, Destroy, Invite, Leave};
enum FileTransferState {
Initialisation, ///< Collecting information required for sending the request out.
WaitingForAccept, ///< The file transfer request was send out.
@@ -200,7 +202,7 @@ namespace Swift {
virtual void setSecurityLabelsEnabled(bool enabled) = 0;
virtual void setCorrectionEnabled(Tristate enabled) = 0;
virtual void setFileTransferEnabled(Tristate enabled) = 0;
- virtual void setUnreadMessageCount(int count) = 0;
+ virtual void setUnreadMessageCount(size_t count) = 0;
virtual void convertToMUC(MUCType mucType) = 0;
// virtual TreeWidget *getTreeWidget() = 0;
virtual void setSecurityLabelsError() = 0;
@@ -219,6 +221,9 @@ namespace Swift {
virtual void showBookmarkWindow(const MUCBookmark& bookmark) = 0;
virtual void setBookmarkState(RoomBookmarkState bookmarkState) = 0;
+ virtual void setChatSecurityMarking(const std::string& markingValue, const std::string& markingForegroundColorValue, const std::string& markingBackgroundColorValue) = 0;
+ virtual void removeChatSecurityMarking() = 0;
+
/**
* A handle that uniquely identities an alert message.
*/
@@ -249,6 +254,7 @@ namespace Swift {
boost::signals2::signal<void ()> onClosed;
boost::signals2::signal<void ()> onAllMessagesRead;
boost::signals2::signal<void (const std::string&, bool isCorrection)> onSendMessageRequest;
+ boost::signals2::signal<void (const std::string&)> onResendMessageRequest;
boost::signals2::signal<void ()> onSendCorrectionMessageRequest;
boost::signals2::signal<void ()> onUserTyping;
boost::signals2::signal<void ()> onUserCancelsTyping;
@@ -282,4 +288,3 @@ namespace Swift {
boost::signals2::signal<void ()> onUnblockUserRequest;
};
}
-
diff --git a/Swift/Controllers/UIInterfaces/FdpFormSubmitWindow.cpp b/Swift/Controllers/UIInterfaces/FdpFormSubmitWindow.cpp
new file mode 100644
index 0000000..47ef9cd
--- /dev/null
+++ b/Swift/Controllers/UIInterfaces/FdpFormSubmitWindow.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <Swift/Controllers/UIInterfaces/FdpFormSubmitWindow.h>
+
+#include <Swift/Controllers/Intl.h>
+
+namespace Swift {
+
+std::string FdpFormSubmitWindow::getNodeErrorText(NodeError nodeError) const {
+ switch(nodeError) {
+ case NodeError::DomainNotFound: return QT_TRANSLATE_NOOP("", "Error: No pubsub domain found");
+ case NodeError::NoFdpNodesInDomain: return QT_TRANSLATE_NOOP("", "Error: Domain does not contain an FDP template node");
+ case NodeError::NoError: return "";
+ }
+ return "";
+}
+
+std::string FdpFormSubmitWindow::getTemplateErrorText(TemplateError templateError) const {
+ switch(templateError) {
+ case TemplateError::CannotLocateForm: return QT_TRANSLATE_NOOP("", "Error: Could not locate template form");
+ case TemplateError::InvalidPayload: return QT_TRANSLATE_NOOP("", "Error: Invalid payload returned from node");
+ case TemplateError::RequestFailed: return QT_TRANSLATE_NOOP("", "Error: Pubsub request failed");
+ case TemplateError::NoError: return "";
+ }
+ return "";
+}
+
+}
diff --git a/Swift/Controllers/UIInterfaces/FdpFormSubmitWindow.h b/Swift/Controllers/UIInterfaces/FdpFormSubmitWindow.h
new file mode 100644
index 0000000..572f910
--- /dev/null
+++ b/Swift/Controllers/UIInterfaces/FdpFormSubmitWindow.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include <boost/signals2.hpp>
+
+namespace Swift {
+
+ class Form;
+
+ class FdpFormSubmitWindow {
+
+ public:
+ enum class NodeError {
+ DomainNotFound,
+ NoFdpNodesInDomain,
+ NoError,
+ };
+ enum class TemplateError {
+ CannotLocateForm,
+ InvalidPayload,
+ RequestFailed,
+ NoError,
+ };
+
+ virtual ~FdpFormSubmitWindow() {}
+
+ virtual void show() = 0;
+ virtual void raise() = 0;
+ virtual void addNode(const std::string& node, const std::string& nodeName) = 0;
+ virtual void clearNodeData() = 0;
+ virtual void setFormData(const std::shared_ptr<Form>& form) = 0;
+ virtual void showNodePlaceholder(NodeError nodeError) = 0;
+ virtual void showFormPlaceholder(TemplateError templateError) = 0;
+ virtual void handleSubmitServerResponse(bool submissionSuccess) = 0;
+
+ boost::signals2::signal<void ()> onCloseEvent;
+ boost::signals2::signal<void (const std::string&)> onRequestPubSubNodeData;
+ boost::signals2::signal<void (const std::string&)> onRequestTemplateForm;
+ boost::signals2::signal<void (const std::shared_ptr<Form>&)> onSubmitForm;
+
+ protected:
+
+ std::string getNodeErrorText(NodeError nodeError) const;
+ std::string getTemplateErrorText(TemplateError templateError) const;
+ };
+}
diff --git a/Swift/Controllers/UIInterfaces/FdpFormSubmitWindowFactory.h b/Swift/Controllers/UIInterfaces/FdpFormSubmitWindowFactory.h
new file mode 100644
index 0000000..ef11eaf
--- /dev/null
+++ b/Swift/Controllers/UIInterfaces/FdpFormSubmitWindowFactory.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <memory>
+
+namespace Swift {
+ class FdpFormSubmitWindow;
+
+ class FdpFormSubmitWindowFactory {
+ public:
+ virtual ~FdpFormSubmitWindowFactory() {}
+ virtual std::unique_ptr<FdpFormSubmitWindow> createFdpFormSubmitWindow() = 0;
+ };
+}
diff --git a/Swift/Controllers/UIInterfaces/MainWindow.h b/Swift/Controllers/UIInterfaces/MainWindow.h
index bfd8c67..e4b4657 100644
--- a/Swift/Controllers/UIInterfaces/MainWindow.h
+++ b/Swift/Controllers/UIInterfaces/MainWindow.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -13,12 +13,12 @@
#include <Swiften/Elements/DiscoItems.h>
#include <Swiften/Elements/StatusShow.h>
-#include <Swiften/JID/JID.h>
#include <Swiften/TLS/Certificate.h>
#include <Swift/Controllers/Roster/ContactRosterItem.h>
namespace Swift {
+ class JID;
class Roster;
class MainWindow {
diff --git a/Swift/Controllers/UIInterfaces/MainWindowFactory.h b/Swift/Controllers/UIInterfaces/MainWindowFactory.h
index c0110cf..af924e2 100644
--- a/Swift/Controllers/UIInterfaces/MainWindowFactory.h
+++ b/Swift/Controllers/UIInterfaces/MainWindowFactory.h
@@ -1,17 +1,15 @@
/*
- * Copyright (c) 2010 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
-#ifndef SWIFTEN_MainWindowFactory_H
-#define SWIFTEN_MainWindowFactory_H
-
-#include "Swiften/JID/JID.h"
-#include "Swift/Controllers/UIEvents/UIEventStream.h"
+#pragma once
namespace Swift {
+ class Chattables;
class MainWindow;
+ class UIEventStream;
class MainWindowFactory {
public:
@@ -19,9 +17,7 @@ namespace Swift {
/**
* Transfers ownership of result.
*/
- virtual MainWindow* createMainWindow(UIEventStream* eventStream) = 0;
+ virtual MainWindow* createMainWindow(Chattables&, UIEventStream*) = 0;
};
}
-#endif
-
diff --git a/Swift/Controllers/UIInterfaces/UIFactory.h b/Swift/Controllers/UIInterfaces/UIFactory.h
index a0976dc..c49364a 100644
--- a/Swift/Controllers/UIInterfaces/UIFactory.h
+++ b/Swift/Controllers/UIInterfaces/UIFactory.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -12,6 +12,7 @@
#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h>
#include <Swift/Controllers/UIInterfaces/ContactEditWindowFactory.h>
#include <Swift/Controllers/UIInterfaces/EventWindowFactory.h>
+#include <Swift/Controllers/UIInterfaces/FdpFormSubmitWindowFactory.h>
#include <Swift/Controllers/UIInterfaces/FileTransferListWidgetFactory.h>
#include <Swift/Controllers/UIInterfaces/HighlightEditorWindowFactory.h>
#include <Swift/Controllers/UIInterfaces/HistoryWindowFactory.h>
@@ -42,7 +43,8 @@ namespace Swift {
public FileTransferListWidgetFactory,
public WhiteboardWindowFactory,
public HighlightEditorWindowFactory,
- public BlockListEditorWidgetFactory {
+ public BlockListEditorWidgetFactory,
+ public FdpFormSubmitWindowFactory {
public:
virtual ~UIFactory() {}
};
diff --git a/Swift/Controllers/UnitTest/FdpFormSubmitControllerTest.cpp b/Swift/Controllers/UnitTest/FdpFormSubmitControllerTest.cpp
new file mode 100644
index 0000000..8dc3442
--- /dev/null
+++ b/Swift/Controllers/UnitTest/FdpFormSubmitControllerTest.cpp
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <memory>
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include <Swiften/Client/DummyStanzaChannel.h>
+#include <Swiften/Elements/DiscoItems.h>
+#include <Swiften/Elements/Form.h>
+#include <Swiften/Elements/FormField.h>
+#include <Swiften/Elements/IQ.h>
+#include <Swiften/Elements/Payload.h>
+#include <Swiften/Elements/PubSub.h>
+#include <Swiften/Elements/PubSubItems.h>
+#include <Swiften/Elements/PubSubPublish.h>
+#include <Swiften/JID/JID.h>
+#include <Swiften/Queries/IQRouter.h>
+
+#include <Swift/Controllers/FdpFormSubmitController.h>
+#include <Swift/Controllers/UIEvents/FdpFormSubmitWindowOpenUIEvent.h>
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
+#include <Swift/Controllers/UnitTest/MockFdpFormSubmitWindowFactory.h>
+#include <Swift/Controllers/UnitTest/MockFdpFormSubmitWindow.h>
+
+namespace Swift {
+
+class FdpFormSubmitControllerTest : public ::testing::Test {
+
+ protected:
+ void SetUp() {
+ clientJid_ = JID(clientJIDString_);
+ stanzaChannel_ = std::make_unique<DummyStanzaChannel>();
+ iqRouter_ = std::make_unique<IQRouter>(stanzaChannel_.get());
+ uiEventStream_ = std::make_unique<UIEventStream>();
+ fdpWindowFactory_ = std::make_unique<MockFdpFormSubmitWindowFactory>();
+ fdpController_ = std::make_unique<FdpFormSubmitController>(clientJid_, iqRouter_.get(), uiEventStream_.get(), fdpWindowFactory_.get());
+ auto fdpWindowOpenUIEvent = std::make_shared<FdpFormSubmitWindowOpenUIEvent>();
+ uiEventStream_->send(fdpWindowOpenUIEvent);
+ fdpWindow_ = fdpWindowFactory_->getMockFdpFormSubmitWindow();
+ }
+
+ void TearDown() {
+ }
+
+ std::shared_ptr<DiscoItems> createDiscoItemsResult();
+ std::shared_ptr<PubSub> createTemplatePubSubResult(const std::shared_ptr<Form>& form);
+ std::shared_ptr<PubSub> createSubmittedPubSubResult();
+
+ std::string clientJIDString_ = "testjid@test.im/swift";
+ JID clientJid_;
+ std::unique_ptr<DummyStanzaChannel> stanzaChannel_;
+ std::unique_ptr<IQRouter> iqRouter_;
+ std::unique_ptr<UIEventStream> uiEventStream_;
+ std::unique_ptr<MockFdpFormSubmitWindowFactory> fdpWindowFactory_;
+ std::unique_ptr<FdpFormSubmitController> fdpController_;
+ MockFdpFormSubmitWindow* fdpWindow_;
+};
+
+std::shared_ptr<DiscoItems> FdpFormSubmitControllerTest::createDiscoItemsResult() {
+ auto discoItems = std::make_shared<DiscoItems>();
+ discoItems->addItem(DiscoItems::Item("node0", JID(), "fdp/template/testNode0"));
+ discoItems->addItem(DiscoItems::Item("node1", JID(), "fdp/template/testNode1"));
+ discoItems->addItem(DiscoItems::Item("node2", JID(), "fdp/template/testNode2"));
+ return discoItems;
+}
+
+std::shared_ptr<PubSub> FdpFormSubmitControllerTest::createTemplatePubSubResult(const std::shared_ptr<Form>& form) {
+ auto pubSubItem = std::make_shared<PubSubItem>();
+ pubSubItem->addData(form);
+ auto pubSubItems = std::make_shared<PubSubItems>();
+ pubSubItems->addItem(pubSubItem);
+ auto pubSub = std::make_shared<PubSub>();
+ pubSub->setPayload(pubSubItems);
+ return pubSub;
+}
+
+std::shared_ptr<PubSub> FdpFormSubmitControllerTest::createSubmittedPubSubResult() {
+ auto pubSubItem = std::make_shared<PubSubItem>();
+ pubSubItem->setID("testID");
+ auto pubSubPublish = std::make_shared<PubSubPublish>();
+ pubSubPublish->addItem(pubSubItem);
+ pubSubPublish->setNode("fdp/submitted/test");
+ auto pubSub = std::make_shared<PubSub>();
+ pubSub->setPayload(pubSubPublish);
+ return pubSub;
+}
+
+TEST_F(FdpFormSubmitControllerTest, testRequestPubSubNodeData) {
+ std::string domainName = "fdp.example.test";
+ fdpWindow_->onRequestPubSubNodeData(domainName);
+ ASSERT_EQ(1, stanzaChannel_->sentStanzas.size());
+ auto requestIq = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[0]);
+ ASSERT_EQ(domainName, requestIq->getTo());
+ auto discoItemsPayloads = requestIq->getPayloads<DiscoItems>();
+ ASSERT_EQ(1, discoItemsPayloads.size());
+
+ auto discoItemsResult = createDiscoItemsResult();
+ auto resultIq = IQ::createResult(clientJid_, domainName, requestIq->getID(), discoItemsResult);
+ stanzaChannel_->onIQReceived(resultIq);
+
+ auto discoItemsList = discoItemsResult->getItems();
+ ASSERT_EQ(discoItemsList.size(), fdpWindow_->nodeData.size());
+ for (unsigned int i = 0; i < fdpWindow_->nodeData.size(); i++) {
+ auto nodeItem = fdpWindow_->nodeData[i];
+ auto discoItem = discoItemsList[i];
+ ASSERT_EQ(discoItem.getNode(), nodeItem.first);
+ ASSERT_EQ(discoItem.getName(), nodeItem.second);
+ }
+ ASSERT_EQ(FdpFormSubmitWindow::NodeError::NoError, fdpWindow_->nodeError_);
+}
+
+TEST_F(FdpFormSubmitControllerTest, testRequestPubSubNodeDataError) {
+ std::string domainName = "fdp.example.test";
+ fdpWindow_->onRequestPubSubNodeData(domainName);
+ ASSERT_EQ(1, stanzaChannel_->sentStanzas.size());
+ auto requestIq = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[0]);
+ ASSERT_EQ(domainName, requestIq->getTo());
+
+ auto resultIq = IQ::createError(clientJid_, domainName, requestIq->getID());
+ stanzaChannel_->onIQReceived(resultIq);
+
+ ASSERT_EQ(true, fdpWindow_->nodeData.empty());
+ ASSERT_EQ(FdpFormSubmitWindow::NodeError::DomainNotFound, fdpWindow_->nodeError_);
+}
+
+TEST_F(FdpFormSubmitControllerTest, testRequestTemplateForm) {
+ std::string domainName = "fdp.example.test";
+ fdpWindow_->onRequestPubSubNodeData(domainName);
+ auto nodeDataRequestIq = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[0]);
+ auto discoItemsResult = createDiscoItemsResult();
+ auto discoItemsResultIq = IQ::createResult(clientJid_, domainName, nodeDataRequestIq->getID(), discoItemsResult);
+ stanzaChannel_->onIQReceived(discoItemsResultIq);
+
+ std::string templateNodeName = "fdp/template/test";
+ fdpWindow_->onRequestTemplateForm(templateNodeName);
+ ASSERT_EQ(2, stanzaChannel_->sentStanzas.size());
+ auto requestIq = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[1]);
+ ASSERT_EQ(domainName, requestIq->getTo());
+ auto pubSubPayloads = requestIq->getPayloads<PubSub>();
+ ASSERT_EQ(1, pubSubPayloads.size());
+
+ std::string value0("value0");
+ std::string value1("value1@example.test");
+ auto field0 = std::make_shared<FormField>(FormField::TextSingleType, value0);
+ auto field1 = std::make_shared<FormField>(FormField::JIDSingleType, value1);
+ auto form = std::make_shared<Form>();
+ form->addField(field0);
+ form->addField(field1);
+ auto pubSubResult = createTemplatePubSubResult(form);
+ auto resultIq = IQ::createResult(clientJid_, domainName, requestIq->getID(), pubSubResult);
+ stanzaChannel_->onIQReceived(resultIq);
+
+ ASSERT_EQ(form, fdpWindow_->templateForm_);
+ auto fields = fdpWindow_->templateForm_->getFields();
+ ASSERT_EQ(2, fields.size());
+ ASSERT_EQ(field0, fields[0]);
+ ASSERT_EQ(field1, fields[1]);
+ ASSERT_EQ(value0, fields[0]->getTextSingleValue());
+ ASSERT_EQ(value1, fields[1]->getJIDSingleValue());
+ ASSERT_EQ(FdpFormSubmitWindow::TemplateError::NoError, fdpWindow_->templateError_);
+}
+
+TEST_F(FdpFormSubmitControllerTest, testRequestTemplateFormError) {
+ std::string domainName = "fdp.example.test";
+ fdpWindow_->onRequestPubSubNodeData(domainName);
+ auto nodeDataRequestIq = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[0]);
+ auto discoItemsResult = createDiscoItemsResult();
+ auto discoItemsResultIq = IQ::createResult(clientJid_, domainName, nodeDataRequestIq->getID(), discoItemsResult);
+ stanzaChannel_->onIQReceived(discoItemsResultIq);
+
+ std::string templateNodeName = "fdp/template/test";
+ fdpWindow_->onRequestTemplateForm(templateNodeName);
+ ASSERT_EQ(2, stanzaChannel_->sentStanzas.size());
+ auto requestIq = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[1]);
+ ASSERT_EQ(domainName, requestIq->getTo());
+
+ auto resultIq = IQ::createError(clientJid_, domainName, requestIq->getID());
+ stanzaChannel_->onIQReceived(resultIq);
+
+ ASSERT_EQ(nullptr, fdpWindow_->templateForm_);
+ ASSERT_EQ(FdpFormSubmitWindow::TemplateError::RequestFailed, fdpWindow_->templateError_);
+}
+
+TEST_F(FdpFormSubmitControllerTest, testSubmitForm) {
+ std::string domainName = "fdp.example.test";
+ std::string templateNodeName = "fdp/template/test";
+ fdpWindow_->onRequestPubSubNodeData(domainName);
+ auto nodeDataRequestIq = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[0]);
+ auto discoItemsResult = createDiscoItemsResult();
+ auto discoItemsResultIq = IQ::createResult(clientJid_, domainName, nodeDataRequestIq->getID(), discoItemsResult);
+ stanzaChannel_->onIQReceived(discoItemsResultIq);
+ fdpWindow_->onRequestTemplateForm(templateNodeName);
+ auto templateFormRequestIq = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[1]);
+ auto templateForm = std::make_shared<Form>();
+ auto templatePubSubResult = createTemplatePubSubResult(templateForm);
+ auto templatePubSubResultIq = IQ::createResult(clientJid_, domainName, templateFormRequestIq->getID(), templatePubSubResult);
+ stanzaChannel_->onIQReceived(templatePubSubResultIq);
+
+ std::string value0("value0");
+ std::string value1("value1@example.test");
+ auto field0 = std::make_shared<FormField>(FormField::TextSingleType, value0);
+ auto field1 = std::make_shared<FormField>(FormField::JIDSingleType, value1);
+ auto form = std::make_shared<Form>();
+ form->addField(field0);
+ form->addField(field1);
+ fdpWindow_->onSubmitForm(form);
+
+ ASSERT_EQ(3, stanzaChannel_->sentStanzas.size());
+ auto requestIq = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[2]);
+ ASSERT_EQ(domainName, requestIq->getTo());
+ auto pubSubPayloads = requestIq->getPayloads<PubSub>();
+ ASSERT_EQ(1, pubSubPayloads.size());
+ auto pubSubPayload = pubSubPayloads[0];
+ auto pubSubPublishPayload = std::dynamic_pointer_cast<PubSubPublish>(pubSubPayload->getPayload());
+ ASSERT_TRUE(pubSubPublishPayload);
+ auto pubSubItems = pubSubPublishPayload->getItems();
+ ASSERT_EQ(1, pubSubItems.size());
+ auto dataList = pubSubItems[0]->getData();
+ ASSERT_EQ(1, dataList.size());
+ auto submittedForm = std::dynamic_pointer_cast<Form>(dataList[0]);
+ ASSERT_TRUE(submittedForm);
+ ASSERT_EQ(form, submittedForm);
+ auto fields = submittedForm->getFields();
+ ASSERT_EQ(2, fields.size());
+ ASSERT_EQ(field0, fields[0]);
+ ASSERT_EQ(field1, fields[1]);
+ ASSERT_EQ(value0, fields[0]->getTextSingleValue());
+ ASSERT_EQ(value1, fields[1]->getJIDSingleValue());
+
+ auto pubSubResult = createSubmittedPubSubResult();
+ auto resultIq = IQ::createResult(clientJid_, domainName, requestIq->getID(), pubSubResult);
+ stanzaChannel_->onIQReceived(resultIq);
+
+ ASSERT_EQ(true, fdpWindow_->submissionSuccess_);
+}
+
+TEST_F(FdpFormSubmitControllerTest, testSubmitFormError) {
+ std::string domainName = "fdp.example.test";
+ std::string templateNodeName = "fdp/template/test";
+ fdpWindow_->onRequestPubSubNodeData(domainName);
+ auto nodeDataRequestIq = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[0]);
+ auto discoItemsResult = createDiscoItemsResult();
+ auto discoItemsResultIq = IQ::createResult(clientJid_, domainName, nodeDataRequestIq->getID(), discoItemsResult);
+ stanzaChannel_->onIQReceived(discoItemsResultIq);
+ fdpWindow_->onRequestTemplateForm(templateNodeName);
+ auto templateFormRequestIq = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[1]);
+ auto templateForm = std::make_shared<Form>();
+ auto templatePubSubResult = createTemplatePubSubResult(templateForm);
+ auto templatePubSubResultIq = IQ::createResult(clientJid_, domainName, templateFormRequestIq->getID(), templatePubSubResult);
+ stanzaChannel_->onIQReceived(templatePubSubResultIq);
+
+ auto form = std::make_shared<Form>();
+ fdpWindow_->onSubmitForm(form);
+ ASSERT_EQ(3, stanzaChannel_->sentStanzas.size());
+ auto requestIq = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[2]);
+ ASSERT_EQ(domainName, requestIq->getTo());
+
+ auto resultIq = IQ::createError(clientJid_, domainName, requestIq->getID());
+ stanzaChannel_->onIQReceived(resultIq);
+
+ ASSERT_EQ(false, fdpWindow_->submissionSuccess_);
+}
+
+}
diff --git a/Swift/Controllers/UnitTest/MockChatWindow.h b/Swift/Controllers/UnitTest/MockChatWindow.h
index 7682781..38b3b1f 100644
--- a/Swift/Controllers/UnitTest/MockChatWindow.h
+++ b/Swift/Controllers/UnitTest/MockChatWindow.h
@@ -17,10 +17,11 @@ namespace Swift {
MockChatWindow() {}
virtual ~MockChatWindow();
- virtual std::string addMessage(const ChatMessage& message, const std::string& senderName, bool senderIsSelf, std::shared_ptr<SecurityLabel> /*label*/, const std::string& /*avatarPath*/, const boost::posix_time::ptime& /*time*/) {
+ virtual std::string addMessage(const ChatMessage& message, const std::string& senderName, bool senderIsSelf, std::shared_ptr<SecurityLabel> label, const std::string& /*avatarPath*/, const boost::posix_time::ptime& /*time*/) {
lastAddedMessage_ = message;
lastAddedMessageSenderName_ = senderName;
lastAddedMessageSenderIsSelf_ = senderIsSelf;
+ lastAddedMessageSecurityLabel_ = label;
return "id";
}
@@ -72,7 +73,7 @@ namespace Swift {
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 setUnreadMessageCount(size_t /*count*/) {}
virtual void convertToMUC(MUCType mucType) {
mucType_ = mucType;
@@ -133,10 +134,19 @@ namespace Swift {
lastAddedMessageSenderIsSelf_ = lastAddedActionSenderIsSelf_ = false;
}
+ void setChatSecurityMarking(const std::string& markingValue, const std::string& markingForegroundColorValue, const std::string& markingBackgroundColorValue) {
+ markingValue_ = markingValue;
+ markingForegroundColorValue_ = markingForegroundColorValue;
+ markingBackgroundColorValue_ = markingBackgroundColorValue;
+ }
+
+ void removeChatSecurityMarking() {}
+
std::string name_;
ChatMessage lastAddedMessage_;
std::string lastAddedMessageSenderName_;
bool lastAddedMessageSenderIsSelf_ = false;
+ std::shared_ptr<SecurityLabel> lastAddedMessageSecurityLabel_ = nullptr;
ChatMessage lastAddedAction_;
std::string lastAddedActionSenderName_;
bool lastAddedActionSenderIsSelf_ = false;
@@ -154,6 +164,9 @@ namespace Swift {
Roster* roster_ = nullptr;
std::vector<std::pair<std::string, ReceiptState>> receiptChanges_;
boost::optional<MUCType> mucType_;
+ std::string markingValue_;
+ std::string markingForegroundColorValue_;
+ std::string markingBackgroundColorValue_;
};
}
diff --git a/Swift/Controllers/UnitTest/MockFdpFormSubmitWindow.h b/Swift/Controllers/UnitTest/MockFdpFormSubmitWindow.h
new file mode 100644
index 0000000..28ef35f
--- /dev/null
+++ b/Swift/Controllers/UnitTest/MockFdpFormSubmitWindow.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include <Swift/Controllers/UIInterfaces/FdpFormSubmitWindow.h>
+
+namespace Swift {
+
+ class Form;
+
+ class MockFdpFormSubmitWindow : public FdpFormSubmitWindow {
+ public:
+ MockFdpFormSubmitWindow() : FdpFormSubmitWindow() {}
+ virtual void show() override {}
+ virtual void raise() override {}
+ virtual void addNode(const std::string& node, const std::string& nodeName) override { nodeData.push_back(std::pair<std::string, std::string>(node, nodeName)); }
+ virtual void clearNodeData() override { nodeData.clear(); }
+ virtual void setFormData(const std::shared_ptr<Form>& form) override { templateForm_ = form; }
+ virtual void showNodePlaceholder(NodeError nodeError) override { nodeError_ = nodeError; }
+ virtual void showFormPlaceholder(TemplateError templateError) override { templateError_ = templateError; }
+ virtual void handleSubmitServerResponse(bool submissionSuccess) override { submissionSuccess_ = submissionSuccess; }
+
+ std::vector<std::pair<std::string, std::string>> nodeData;
+ std::shared_ptr<Form> templateForm_ = nullptr;
+ NodeError nodeError_ = NodeError::NoError;
+ TemplateError templateError_ = TemplateError::NoError;
+ bool submissionSuccess_ = false;
+ };
+
+}
diff --git a/Swift/Controllers/UnitTest/MockFdpFormSubmitWindowFactory.h b/Swift/Controllers/UnitTest/MockFdpFormSubmitWindowFactory.h
new file mode 100644
index 0000000..8015419
--- /dev/null
+++ b/Swift/Controllers/UnitTest/MockFdpFormSubmitWindowFactory.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include <Swift/Controllers/UIInterfaces/FdpFormSubmitWindowFactory.h>
+#include <Swift/Controllers/UnitTest/MockFdpFormSubmitWindow.h>
+
+namespace Swift {
+
+ class MockFdpFormSubmitWindowFactory : public FdpFormSubmitWindowFactory {
+ public:
+ MockFdpFormSubmitWindowFactory() : FdpFormSubmitWindowFactory() {}
+
+ virtual std::unique_ptr<FdpFormSubmitWindow> createFdpFormSubmitWindow() override {
+ std::unique_ptr<FdpFormSubmitWindow> fdpFormSubmitWindow = std::make_unique<MockFdpFormSubmitWindow>();
+ mockFdpFormSubmitWindow_ = static_cast<MockFdpFormSubmitWindow*>(fdpFormSubmitWindow.get());
+ return fdpFormSubmitWindow;
+ }
+
+ MockFdpFormSubmitWindow* getMockFdpFormSubmitWindow() { return mockFdpFormSubmitWindow_; }
+
+ private:
+ MockFdpFormSubmitWindow* mockFdpFormSubmitWindow_;
+ };
+}
diff --git a/Swift/Controllers/UnitTest/MockMainWindow.h b/Swift/Controllers/UnitTest/MockMainWindow.h
index 6ae2aa7..9265310 100644
--- a/Swift/Controllers/UnitTest/MockMainWindow.h
+++ b/Swift/Controllers/UnitTest/MockMainWindow.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -26,6 +26,7 @@ namespace Swift {
virtual void setStreamEncryptionStatus(bool /*tlsInPlaceAndValid*/) {}
virtual void openCertificateDialog(const std::vector<Certificate::ref>& /*chain*/) {}
virtual void setBlockingCommandAvailable(bool /*isAvailable*/) {}
+ virtual void openFdpFormSubmitDialog(const JID& /*self*/, IQRouter* /*iqRouter*/) {}
Roster* roster;
};
diff --git a/Swift/Controllers/UnitTest/MockMainWindowFactory.h b/Swift/Controllers/UnitTest/MockMainWindowFactory.h
index adf4fdf..331ca11 100644
--- a/Swift/Controllers/UnitTest/MockMainWindowFactory.h
+++ b/Swift/Controllers/UnitTest/MockMainWindowFactory.h
@@ -20,9 +20,7 @@ namespace Swift {
/**
* Transfers ownership of result.
*/
- virtual MainWindow* createMainWindow(UIEventStream*) {last = new MockMainWindow();return last;}
+ virtual MainWindow* createMainWindow(Chattables&, UIEventStream*) {last = new MockMainWindow();return last;}
MockMainWindow* last;
};
}
-
-
diff --git a/Swift/Controllers/XMPPEvents/EventController.cpp b/Swift/Controllers/XMPPEvents/EventController.cpp
index f8fb192..0e9429d 100644
--- a/Swift/Controllers/XMPPEvents/EventController.cpp
+++ b/Swift/Controllers/XMPPEvents/EventController.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -51,7 +51,7 @@ void EventController::handleIncomingEvent(std::shared_ptr<StanzaEvent> sourceEve
if ((messageEvent && messageEvent->isReadable()) || subscriptionEvent || errorEvent || mucInviteEvent || incomingFileTransferEvent) {
events_.push_back(sourceEvent);
sourceEvent->onConclusion.connect(boost::bind(&EventController::handleEventConcluded, this, sourceEvent));
- onEventQueueLengthChange(boost::numeric_cast<int>(events_.size()));
+ onEventQueueLengthChange(events_.size());
onEventQueueEventAdded(sourceEvent);
if (sourceEvent->getConcluded()) {
handleEventConcluded(sourceEvent);
@@ -62,7 +62,7 @@ void EventController::handleIncomingEvent(std::shared_ptr<StanzaEvent> sourceEve
void EventController::handleEventConcluded(std::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(boost::numeric_cast<int>(events_.size()));
+ onEventQueueLengthChange(events_.size());
}
void EventController::disconnectAll() {
diff --git a/Swift/Controllers/XMPPEvents/EventController.h b/Swift/Controllers/XMPPEvents/EventController.h
index 8a095d9..5b746e4 100644
--- a/Swift/Controllers/XMPPEvents/EventController.h
+++ b/Swift/Controllers/XMPPEvents/EventController.h
@@ -1,11 +1,12 @@
/*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#pragma once
+#include <cstddef>
#include <memory>
#include <vector>
@@ -22,7 +23,7 @@ namespace Swift {
~EventController();
void handleIncomingEvent(std::shared_ptr<StanzaEvent> sourceEvent);
- boost::signals2::signal<void (int)> onEventQueueLengthChange;
+ boost::signals2::signal<void (size_t)> onEventQueueLengthChange;
boost::signals2::signal<void (std::shared_ptr<StanzaEvent>)> onEventQueueEventAdded;
const EventList& getEvents() const {return events_;}
void disconnectAll();