diff options
-rw-r--r-- | Swift/Controllers/Chat/ChatController.cpp | 60 | ||||
-rw-r--r-- | Swift/Controllers/Chat/ChatController.h | 7 | ||||
-rw-r--r-- | Swift/Controllers/Chat/MUCController.cpp | 8 | ||||
-rw-r--r-- | Swift/Controllers/UIInterfaces/ChatWindow.h | 2 | ||||
-rw-r--r-- | Swift/QtUI/QtChatWindow.cpp | 9 | ||||
-rw-r--r-- | Swiften/Base/Tristate.h | 13 | ||||
-rw-r--r-- | Swiften/Disco/FeatureOracle.cpp | 99 | ||||
-rw-r--r-- | Swiften/Disco/FeatureOracle.h | 47 | ||||
-rw-r--r-- | Swiften/Disco/SConscript | 1 |
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]) |