summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Swift/Controllers/Chat/ChatController.cpp60
-rw-r--r--Swift/Controllers/Chat/ChatController.h7
-rw-r--r--Swift/Controllers/Chat/MUCController.cpp8
-rw-r--r--Swift/Controllers/UIInterfaces/ChatWindow.h2
-rw-r--r--Swift/QtUI/QtChatWindow.cpp9
-rw-r--r--Swiften/Base/Tristate.h13
-rw-r--r--Swiften/Disco/FeatureOracle.cpp99
-rw-r--r--Swiften/Disco/FeatureOracle.h47
-rw-r--r--Swiften/Disco/SConscript1
9 files changed, 196 insertions, 50 deletions
diff --git a/Swift/Controllers/Chat/ChatController.cpp b/Swift/Controllers/Chat/ChatController.cpp
index 306ee9e..8c132d0 100644
--- a/Swift/Controllers/Chat/ChatController.cpp
+++ b/Swift/Controllers/Chat/ChatController.cpp
@@ -6,43 +6,45 @@
#include <Swift/Controllers/Chat/ChatController.h>
+#include <stdio.h>
+
#include <boost/bind.hpp>
#include <boost/smart_ptr/make_shared.hpp>
-#include <stdio.h>
#include <Swiften/Avatars/AvatarManager.h>
#include <Swiften/Base/Algorithm.h>
#include <Swiften/Base/DateTime.h>
+#include <Swiften/Base/Log.h>
#include <Swiften/Base/foreach.h>
#include <Swiften/Base/format.h>
-#include <Swiften/Base/Log.h>
#include <Swiften/Chat/ChatStateNotifier.h>
#include <Swiften/Chat/ChatStateTracker.h>
#include <Swiften/Client/ClientBlockListManager.h>
#include <Swiften/Client/NickResolver.h>
#include <Swiften/Client/StanzaChannel.h>
#include <Swiften/Disco/EntityCapsProvider.h>
+#include <Swiften/Disco/FeatureOracle.h>
#include <Swiften/Elements/DeliveryReceipt.h>
#include <Swiften/Elements/DeliveryReceiptRequest.h>
#include <Swiften/Elements/Idle.h>
#include <Swiften/FileTransfer/FileTransferManager.h>
-#include <Swift/Controllers/Intl.h>
-#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h>
-#include <Swift/Controllers/XMPPEvents/EventController.h>
+#include <Swift/Controllers/Chat/ChatMessageParser.h>
#include <Swift/Controllers/FileTransfer/FileTransferController.h>
+#include <Swift/Controllers/Highlighter.h>
+#include <Swift/Controllers/Intl.h>
+#include <Swift/Controllers/SettingConstants.h>
#include <Swift/Controllers/StatusUtil.h>
-#include <Swift/Controllers/UIEvents/UIEventStream.h>
-#include <Swift/Controllers/UIEvents/SendFileUIEvent.h>
#include <Swift/Controllers/UIEvents/AcceptWhiteboardSessionUIEvent.h>
#include <Swift/Controllers/UIEvents/CancelWhiteboardSessionUIEvent.h>
-#include <Swift/Controllers/UIEvents/ShowWhiteboardUIEvent.h>
-#include <Swift/Controllers/UIEvents/RequestChangeBlockStateUIEvent.h>
#include <Swift/Controllers/UIEvents/InviteToMUCUIEvent.h>
+#include <Swift/Controllers/UIEvents/RequestChangeBlockStateUIEvent.h>
#include <Swift/Controllers/UIEvents/RequestInviteToMUCUIEvent.h>
-#include <Swift/Controllers/SettingConstants.h>
-#include <Swift/Controllers/Highlighter.h>
-#include <Swift/Controllers/Chat/ChatMessageParser.h>
+#include <Swift/Controllers/UIEvents/SendFileUIEvent.h>
+#include <Swift/Controllers/UIEvents/ShowWhiteboardUIEvent.h>
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
+#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h>
+#include <Swift/Controllers/XMPPEvents/EventController.h>
namespace Swift {
@@ -125,28 +127,12 @@ void ChatController::cancelReplaces() {
}
void ChatController::handleBareJIDCapsChanged(const JID& /*jid*/) {
- DiscoInfo::ref disco = entityCapsProvider_->getCaps(toJID_);
- if (disco) {
- if (disco->hasFeature(DiscoInfo::MessageCorrectionFeature)) {
- chatWindow_->setCorrectionEnabled(ChatWindow::Yes);
- } else {
- chatWindow_->setCorrectionEnabled(ChatWindow::No);
- }
- if (disco->hasFeature(DiscoInfo::MessageDeliveryReceiptsFeature)) {
- contactSupportsReceipts_ = ChatWindow::Yes;
- } else {
- contactSupportsReceipts_ = ChatWindow::No;
- }
- if (FileTransferManager::isSupportedBy(disco)) {
- chatWindow_->setFileTransferEnabled(ChatWindow::Yes);
- } else {
- chatWindow_->setFileTransferEnabled(ChatWindow::No);
- }
- } else {
- SWIFT_LOG(debug) << "No disco info :(" << std::endl;
- chatWindow_->setCorrectionEnabled(ChatWindow::Maybe);
- contactSupportsReceipts_ = ChatWindow::Maybe;
- }
+ FeatureOracle featureOracle(entityCapsProvider_, presenceOracle_);
+
+ chatWindow_->setCorrectionEnabled(featureOracle.isMessageCorrectionSupported(toJID_));
+ chatWindow_->setFileTransferEnabled(featureOracle.isFileTransferSupported(toJID_));
+ contactSupportsReceipts_ = featureOracle.isMessageReceiptsSupported(toJID_);
+
checkForDisplayingDisplayReceiptsAlert();
}
@@ -230,7 +216,7 @@ void ChatController::postHandleIncomingMessage(boost::shared_ptr<MessageEvent> m
void ChatController::preSendMessageRequest(boost::shared_ptr<Message> message) {
chatStateNotifier_->addChatStateRequest(message);
- if (userWantsReceipts_ && (contactSupportsReceipts_ != ChatWindow::No) && message) {
+ if (userWantsReceipts_ && (contactSupportsReceipts_ != No) && message) {
message->addPayload(boost::make_shared<DeliveryReceiptRequest>());
}
}
@@ -248,9 +234,9 @@ void ChatController::handleSettingChanged(const std::string& settingPath) {
void ChatController::checkForDisplayingDisplayReceiptsAlert() {
boost::optional<ChatWindow::AlertID> newDeliverReceiptAlert;
- if (userWantsReceipts_ && (contactSupportsReceipts_ == ChatWindow::No)) {
+ if (userWantsReceipts_ && (contactSupportsReceipts_ == No)) {
newDeliverReceiptAlert = chatWindow_->addAlert(QT_TRANSLATE_NOOP("", "This chat doesn't support delivery receipts."));
- } else if (userWantsReceipts_ && (contactSupportsReceipts_ == ChatWindow::Maybe)) {
+ } else if (userWantsReceipts_ && (contactSupportsReceipts_ == Maybe)) {
newDeliverReceiptAlert = chatWindow_->addAlert(QT_TRANSLATE_NOOP("", "This chat may not support delivery receipts. You might not receive delivery receipts for the messages you send."));
} else {
if (deliveryReceiptAlert_) {
diff --git a/Swift/Controllers/Chat/ChatController.h b/Swift/Controllers/Chat/ChatController.h
index 317a836..a1f40be 100644
--- a/Swift/Controllers/Chat/ChatController.h
+++ b/Swift/Controllers/Chat/ChatController.h
@@ -6,11 +6,12 @@
#pragma once
-#include <Swift/Controllers/Chat/ChatControllerBase.h>
-
#include <map>
#include <string>
+#include <Swiften/Base/Tristate.h>
+
+#include <Swift/Controllers/Chat/ChatControllerBase.h>
#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
namespace Swift {
@@ -95,7 +96,7 @@ namespace Swift {
StatusShow::Type lastShownStatus_;
UIEventStream* eventStream_;
- ChatWindow::Tristate contactSupportsReceipts_;
+ Tristate contactSupportsReceipts_;
bool receivingPresenceFromUs_;
bool userWantsReceipts_;
std::map<std::string, FileTransferController*> ftControllers;
diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp
index 054f896..6794846 100644
--- a/Swift/Controllers/Chat/MUCController.cpp
+++ b/Swift/Controllers/Chat/MUCController.cpp
@@ -15,8 +15,8 @@
#include <Swiften/Avatars/AvatarManager.h>
#include <Swiften/Base/Log.h>
#include <Swiften/Base/foreach.h>
-#include <Swiften/Base/foreach.h>
#include <Swiften/Base/format.h>
+#include <Swiften/Base/Tristate.h>
#include <Swiften/Client/BlockList.h>
#include <Swiften/Client/ClientBlockListManager.h>
#include <Swiften/Client/StanzaChannel.h>
@@ -230,18 +230,18 @@ void MUCController::handleActionRequestedOnOccupant(ChatWindow::OccupantAction a
}
void MUCController::handleBareJIDCapsChanged(const JID& /*jid*/) {
- ChatWindow::Tristate support = ChatWindow::Yes;
+ Tristate support = Yes;
bool any = false;
foreach (const std::string& nick, currentOccupants_) {
DiscoInfo::ref disco = entityCapsProvider_->getCaps(toJID_.toBare().toString() + "/" + nick);
if (disco && disco->hasFeature(DiscoInfo::MessageCorrectionFeature)) {
any = true;
} else {
- support = ChatWindow::Maybe;
+ support = Maybe;
}
}
if (!any) {
- support = ChatWindow::No;
+ support = No;
}
chatWindow_->setCorrectionEnabled(support);
}
diff --git a/Swift/Controllers/UIInterfaces/ChatWindow.h b/Swift/Controllers/UIInterfaces/ChatWindow.h
index 765f16a..b1e2a11 100644
--- a/Swift/Controllers/UIInterfaces/ChatWindow.h
+++ b/Swift/Controllers/UIInterfaces/ChatWindow.h
@@ -14,6 +14,7 @@
#include <boost/optional.hpp>
#include <boost/shared_ptr.hpp>
+#include <Swiften/Base/Tristate.h>
#include <Swiften/Base/boost_bsignals.h>
#include <Swiften/Elements/ChatState.h>
#include <Swiften/Elements/Form.h>
@@ -86,7 +87,6 @@ namespace Swift {
enum AckState {Pending, Received, Failed};
enum ReceiptState {ReceiptRequested, ReceiptReceived, ReceiptFailed};
- enum Tristate {Yes, No, Maybe};
enum OccupantAction {Kick, Ban, MakeModerator, MakeParticipant, MakeVisitor, AddContact, ShowProfile};
enum RoomAction {ChangeSubject, Configure, Affiliations, Destroy, Invite};
enum FileTransferState {WaitingForAccept, Negotiating, Transferring, Canceled, Finished, FTFailed};
diff --git a/Swift/QtUI/QtChatWindow.cpp b/Swift/QtUI/QtChatWindow.cpp
index b1b9f83..88df2e9 100644
--- a/Swift/QtUI/QtChatWindow.cpp
+++ b/Swift/QtUI/QtChatWindow.cpp
@@ -15,6 +15,7 @@
#include <QCloseEvent>
#include <QComboBox>
#include <QCursor>
+#include <QDebug>
#include <QFileDialog>
#include <QFileInfo>
#include <QInputDialog>
@@ -34,8 +35,6 @@
#include <QToolButton>
#include <QUrl>
-#include <qdebug.h>
-
#include <Swiften/Base/Log.h>
#include <Swift/Controllers/Roster/ContactRosterItem.h>
@@ -289,10 +288,10 @@ void QtChatWindow::handleKeyPressEvent(QKeyEvent* event) {
void QtChatWindow::beginCorrection() {
boost::optional<AlertID> newCorrectingAlert;
- if (correctionEnabled_ == ChatWindow::Maybe) {
+ if (correctionEnabled_ == Maybe) {
newCorrectingAlert = addAlert(Q2PSTRING(tr("This chat may not support message correction. If you send a correction anyway, it may appear as a duplicate message")));
}
- else if (correctionEnabled_ == ChatWindow::No) {
+ else if (correctionEnabled_ == No) {
newCorrectingAlert = addAlert(Q2PSTRING(tr("This chat does not support message correction. If you send a correction anyway, it will appear as a duplicate message")));
}
@@ -613,7 +612,7 @@ void QtChatWindow::dragEnterEvent(QDragEnterEvent *event) {
}
void QtChatWindow::dropEvent(QDropEvent *event) {
- if (fileTransferEnabled_ == ChatWindow::Yes && event->mimeData()->hasUrls()) {
+ if (fileTransferEnabled_ == Yes && event->mimeData()->hasUrls()) {
if (event->mimeData()->urls().size() == 1) {
onSendFileRequest(Q2PSTRING(event->mimeData()->urls().at(0).toLocalFile()));
}
diff --git a/Swiften/Base/Tristate.h b/Swiften/Base/Tristate.h
new file mode 100644
index 0000000..edb7444
--- /dev/null
+++ b/Swiften/Base/Tristate.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+namespace Swift {
+
+enum Tristate {Yes, No, Maybe};
+
+}
diff --git a/Swiften/Disco/FeatureOracle.cpp b/Swiften/Disco/FeatureOracle.cpp
new file mode 100644
index 0000000..4e61aa9
--- /dev/null
+++ b/Swiften/Disco/FeatureOracle.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Disco/FeatureOracle.h>
+
+#include <algorithm>
+#include <iterator>
+#include <vector>
+
+#include <Swiften/Base/foreach.h>
+#include <Swiften/Disco/EntityCapsProvider.h>
+#include <Swiften/Elements/Presence.h>
+#include <Swiften/FileTransfer/FileTransferManager.h>
+#include <Swiften/JID/JID.h>
+#include <Swiften/Presence/PresenceOracle.h>
+
+namespace Swift {
+
+FeatureOracle::FeatureOracle(EntityCapsProvider* capsProvider, PresenceOracle* presenceOracle) : capsProvider_(capsProvider), presenceOracle_(presenceOracle) {
+
+}
+
+Tristate FeatureOracle::isFileTransferSupported(const JID& jid) {
+ DiscoInfo::ref discoInfo = getDiscoResultForJID(jid);
+ if (discoInfo) {
+ return FileTransferManager::isSupportedBy(discoInfo) ? Yes : No;
+ }
+ else {
+ return Maybe;
+ }
+}
+
+Tristate FeatureOracle::isMessageReceiptsSupported(const JID& jid) {
+ return isFeatureSupported(jid, DiscoInfo::MessageDeliveryReceiptsFeature);
+}
+
+Tristate FeatureOracle::isMessageCorrectionSupported(const JID& jid) {
+ return isFeatureSupported(jid, DiscoInfo::MessageCorrectionFeature);
+}
+
+DiscoInfo::ref FeatureOracle::getDiscoResultForJID(const JID& jid) {
+ DiscoInfo::ref discoInfo;
+ if (jid.isBare()) {
+ // Calculate the common subset of disco features of all available results and return that.
+ std::vector<Presence::ref> availablePresences = presenceOracle_->getAllPresence(jid);
+
+ bool commonFeaturesInitialized = false;
+ std::vector<std::string> commonFeatures;
+ foreach(Presence::ref presence, availablePresences) {
+ DiscoInfo::ref presenceDiscoInfo = capsProvider_->getCaps(presence->getFrom());
+ if (presenceDiscoInfo) {
+ std::vector<std::string> features = presenceDiscoInfo->getFeatures();
+ if (!commonFeaturesInitialized) {
+ commonFeatures = features;
+ commonFeaturesInitialized = true;
+ }
+ else {
+ std::vector<std::string> featuresToRemove;
+ foreach(const std::string& feature, commonFeatures) {
+ if (std::find(features.begin(), features.end(), feature) == features.end()) {
+ featuresToRemove.push_back(feature);
+ }
+ }
+ foreach(const std::string& featureToRemove, featuresToRemove) {
+ commonFeatures.erase(std::remove(commonFeatures.begin(), commonFeatures.end(), featureToRemove), commonFeatures.end());
+ }
+ }
+ }
+ }
+ discoInfo = boost::make_shared<DiscoInfo>();
+
+ foreach(const std::string& commonFeature, commonFeatures) {
+ discoInfo->addFeature(commonFeature);
+ }
+ }
+ else {
+ // Return the disco result of the full JID.
+ discoInfo = capsProvider_->getCaps(jid);
+ }
+
+ return discoInfo;
+}
+
+Tristate FeatureOracle::isFeatureSupported(const JID& jid, const std::string& feature) {
+ DiscoInfo::ref discoInfo = getDiscoResultForJID(jid);
+ if (discoInfo) {
+ return discoInfo->hasFeature(feature) ? Yes : No;
+ }
+ else {
+ return Maybe;
+ }
+}
+
+}
+
+
diff --git a/Swiften/Disco/FeatureOracle.h b/Swiften/Disco/FeatureOracle.h
new file mode 100644
index 0000000..d579e5a
--- /dev/null
+++ b/Swiften/Disco/FeatureOracle.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/API.h>
+#include <Swiften/Base/Tristate.h>
+#include <Swiften/Elements/DiscoInfo.h>
+
+namespace Swift {
+
+class EntityCapsProvider;
+class JID;
+class PresenceOracle;
+
+/**
+ * @brief The FeatureOracle class enables direct feature support lookup for client features supported by Swiften.
+ */
+class SWIFTEN_API FeatureOracle {
+ public:
+ FeatureOracle(EntityCapsProvider* capsProvider, PresenceOracle* presenceOracle);
+
+ public:
+ Tristate isFileTransferSupported(const JID& jid);
+ Tristate isMessageReceiptsSupported(const JID& jid);
+ Tristate isMessageCorrectionSupported(const JID& jid);
+
+ private:
+ /**
+ * @brief getDiscoResultForJID returns a shared reference to a DiscoInfo representing features supported by the jid.
+ * @param jid The JID to return the DiscoInfo::ref for.
+ * @return DiscoResult::ref
+ */
+ DiscoInfo::ref getDiscoResultForJID(const JID& jid);
+
+ Tristate isFeatureSupported(const JID& jid, const std::string& feature);
+
+ private:
+ EntityCapsProvider* capsProvider_;
+ PresenceOracle* presenceOracle_;
+};
+
+}
+
diff --git a/Swiften/Disco/SConscript b/Swiften/Disco/SConscript
index c821b42..1779e26 100644
--- a/Swiften/Disco/SConscript
+++ b/Swiften/Disco/SConscript
@@ -11,5 +11,6 @@ objects = swiften_env.SwiftenObject([
"DiscoInfoResponder.cpp",
"JIDDiscoInfoResponder.cpp",
"DiscoServiceWalker.cpp",
+ "FeatureOracle.cpp",
])
swiften_env.Append(SWIFTEN_OBJECTS = [objects])