summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Markmann <tm@ayena.de>2015-03-30 13:49:56 (GMT)
committerKevin Smith <kevin.smith@isode.com>2015-04-10 14:06:42 (GMT)
commit69dce2c01bf46cca3db68a113f49bb31e7be4b03 (patch)
tree55b983a139292cb0b96e498872c4f7e8a93d1520
parent89e5dd08171366ccfb1f598e6e5f140a166b0680 (diff)
downloadswift-69dce2c01bf46cca3db68a113f49bb31e7be4b03.zip
swift-69dce2c01bf46cca3db68a113f49bb31e7be4b03.tar.bz2
Introduce FeatureOracle class for contact feature support detection
This modifies the feature detection in the ChatController to try to use the common features of all available resources feature detection if no full JID has been bound to the chat yet. Test-Information: Tested with two Swift instances. Tested a) the initial chat start case and, b) the offline/online. In case a) Swift used to initally show a yellow warning about no support for message receipts. This warning is gone now. In case b), after a user gone offline and online again in a running chat, Swift used to show a warning about missing support for message receipts. This warning is gone now. Change-Id: I7a769fde8d14847b180503aeaa58280c572d81b3
-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])