From a0185934b0c929622c5526b84235b86cd44aad1d Mon Sep 17 00:00:00 2001 From: Kevin Smith Date: Fri, 3 Sep 2010 16:07:47 +0100 Subject: XEP-0198 Ack support in the UI Resolves: #7 diff --git a/Swift/Controllers/Chat/ChatController.cpp b/Swift/Controllers/Chat/ChatController.cpp index 52288c2..9154b9a 100644 --- a/Swift/Controllers/Chat/ChatController.cpp +++ b/Swift/Controllers/Chat/ChatController.cpp @@ -12,6 +12,7 @@ #include "Swiften/Chat/ChatStateNotifier.h" #include "Swiften/Chat/ChatStateMessageSender.h" #include "Swiften/Chat/ChatStateTracker.h" +#include "Swiften/Client/StanzaChannel.h" #include "Swift/Controllers/UIInterfaces/ChatWindow.h" #include "Swift/Controllers/UIInterfaces/ChatWindowFactory.h" #include "Swift/Controllers/NickResolver.h" @@ -32,6 +33,7 @@ ChatController::ChatController(const JID& self, StanzaChannel* stanzaChannel, IQ nickResolver_ = nickResolver; presenceOracle_->onPresenceChange.connect(boost::bind(&ChatController::handlePresenceChange, this, _1, _2)); chatStateTracker_->onChatStateChange.connect(boost::bind(&ChatWindow::setContactChatState, chatWindow_, _1)); + stanzaChannel_->onStanzaAcked.connect(boost::bind(&ChatController::handleStanzaAcked, this, _1)); String nick = nickResolver_->jidToNick(toJID_); chatWindow_->setName(nick); String startMessage("Starting chat with " + nick); @@ -43,6 +45,7 @@ ChatController::ChatController(const JID& self, StanzaChannel* stanzaChannel, IQ chatWindow_->addSystemMessage(startMessage); chatWindow_->onUserTyping.connect(boost::bind(&ChatStateNotifier::setUserIsTyping, chatStateNotifier_)); chatWindow_->onUserCancelsTyping.connect(boost::bind(&ChatStateNotifier::userCancelledNewMessage, chatStateNotifier_)); + } ChatController::~ChatController() { @@ -80,12 +83,35 @@ void ChatController::preSendMessageRequest(boost::shared_ptr message) { } } -void ChatController::postSendMessage(const String& body) { - addMessage(body, "me", true, labelsEnabled_ ? chatWindow_->getSelectedSecurityLabel() : boost::optional(), String(avatarManager_->getAvatarPath(selfJID_).string()), boost::posix_time::microsec_clock::universal_time()); +void ChatController::postSendMessage(const String& body, boost::shared_ptr sentStanza) { + String id = addMessage(body, "me", true, labelsEnabled_ ? chatWindow_->getSelectedSecurityLabel() : boost::optional(), String(avatarManager_->getAvatarPath(selfJID_).string()), boost::posix_time::microsec_clock::universal_time()); + if (stanzaChannel_->getStreamManagementEnabled()) { + chatWindow_->setAckState(id, ChatWindow::Pending); + unackedStanzas_[sentStanza] = id; + } lastWasPresence_ = false; chatStateNotifier_->userSentMessage(); } +void ChatController::handleStanzaAcked(boost::shared_ptr stanza) { + String id = unackedStanzas_[stanza]; + if (id != "") { + chatWindow_->setAckState(id, ChatWindow::Received); + } + unackedStanzas_.erase(unackedStanzas_.find(stanza)); +} + +void ChatController::setEnabled(bool enabled) { + if (!enabled) { + std::map, String>::iterator it = unackedStanzas_.begin(); + for ( ; it != unackedStanzas_.end(); it++) { + chatWindow_->setAckState(it->second, ChatWindow::Failed); + } + unackedStanzas_.clear(); + } + ChatControllerBase::setEnabled(enabled); +} + String ChatController::senderDisplayNameFromMessage(const JID& from) { return nickResolver_->jidToNick(from); } diff --git a/Swift/Controllers/Chat/ChatController.h b/Swift/Controllers/Chat/ChatController.h index d833094..971fca9 100644 --- a/Swift/Controllers/Chat/ChatController.h +++ b/Swift/Controllers/Chat/ChatController.h @@ -20,16 +20,18 @@ namespace Swift { ChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController); virtual ~ChatController(); virtual void setToJID(const JID& jid); + virtual void setEnabled(bool enabled); private: void handlePresenceChange(boost::shared_ptr newPresence, boost::shared_ptr previousPresence); String getStatusChangeString(boost::shared_ptr presence); bool isIncomingMessageFromMe(boost::shared_ptr message); - void postSendMessage(const String &body); + void postSendMessage(const String &body, boost::shared_ptr sentStanza); void preHandleIncomingMessage(boost::shared_ptr messageEvent); void preSendMessageRequest(boost::shared_ptr); String senderDisplayNameFromMessage(const JID& from); virtual boost::optional getMessageTimestamp(boost::shared_ptr) const; + void handleStanzaAcked(boost::shared_ptr stanza); private: NickResolver* nickResolver_; @@ -39,6 +41,7 @@ namespace Swift { ChatStateTracker* chatStateTracker_; bool isInMUC_; bool lastWasPresence_; + std::map, String> unackedStanzas_; }; } #endif diff --git a/Swift/Controllers/Chat/ChatControllerBase.cpp b/Swift/Controllers/Chat/ChatControllerBase.cpp index e38d12d..b7dd1c0 100644 --- a/Swift/Controllers/Chat/ChatControllerBase.cpp +++ b/Swift/Controllers/Chat/ChatControllerBase.cpp @@ -79,7 +79,7 @@ void ChatControllerBase::handleSendMessageRequest(const String &body) { message->addPayload(boost::shared_ptr(new Delay(now, selfJID_))); } stanzaChannel_->sendMessage(message); - postSendMessage(message->getBody()); + postSendMessage(message->getBody(), boost::dynamic_pointer_cast(message)); } void ChatControllerBase::handleSecurityLabelsCatalogResponse(boost::shared_ptr catalog, const boost::optional& error) { @@ -106,11 +106,11 @@ void ChatControllerBase::activateChatWindow() { chatWindow_->activate(); } -void ChatControllerBase::addMessage(const String& message, const String& senderName, bool senderIsSelf, const boost::optional& label, const String& avatarPath, const boost::posix_time::ptime& time) { +String ChatControllerBase::addMessage(const String& message, const String& senderName, bool senderIsSelf, const boost::optional& label, const String& avatarPath, const boost::posix_time::ptime& time) { if (message.beginsWith("/me ")) { - chatWindow_->addAction(message.getSplittedAtFirst(' ').second, senderName, senderIsSelf, label, avatarPath, time); + return chatWindow_->addAction(message.getSplittedAtFirst(' ').second, senderName, senderIsSelf, label, avatarPath, time); } else { - chatWindow_->addMessage(message, senderName, senderIsSelf, label, avatarPath, time); + return chatWindow_->addMessage(message, senderName, senderIsSelf, label, avatarPath, time); } } diff --git a/Swift/Controllers/Chat/ChatControllerBase.h b/Swift/Controllers/Chat/ChatControllerBase.h index 61d0ab7..2466690 100644 --- a/Swift/Controllers/Chat/ChatControllerBase.h +++ b/Swift/Controllers/Chat/ChatControllerBase.h @@ -15,6 +15,7 @@ #include #include +#include "Swiften/Elements/Stanza.h" #include "Swiften/Base/String.h" #include "Swiften/Elements/DiscoInfo.h" #include "Swiften/Events/MessageEvent.h" @@ -40,13 +41,16 @@ namespace Swift { void activateChatWindow(); void setAvailableServerFeatures(boost::shared_ptr info); void handleIncomingMessage(boost::shared_ptr message); - void addMessage(const String& message, const String& senderName, bool senderIsSelf, const boost::optional& label, const String& avatarPath, const boost::posix_time::ptime& time); + String addMessage(const String& message, const String& senderName, bool senderIsSelf, const boost::optional& label, const String& avatarPath, const boost::posix_time::ptime& time); virtual void setEnabled(bool enabled); virtual void setToJID(const JID& jid) {toJID_ = jid;}; protected: ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController); - virtual void postSendMessage(const String&) {}; + /** + * Pass the Message appended, and the stanza used to send it. + */ + virtual void postSendMessage(const String&, boost::shared_ptr) {}; virtual String senderDisplayNameFromMessage(const JID& from) = 0; virtual bool isIncomingMessageFromMe(boost::shared_ptr) = 0; virtual void preHandleIncomingMessage(boost::shared_ptr) {}; diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp index dfe75d6..acc5e1d 100644 --- a/Swift/Controllers/Chat/ChatsManager.cpp +++ b/Swift/Controllers/Chat/ChatsManager.cpp @@ -8,8 +8,6 @@ #include -#include "Swiften/Client/Client.h" - #include "Swift/Controllers/Chat/ChatController.h" #include "Swift/Controllers/EventController.h" #include "Swift/Controllers/Chat/MUCController.h" diff --git a/Swift/Controllers/Chat/ChatsManager.h b/Swift/Controllers/Chat/ChatsManager.h index d7a6275..3efd507 100644 --- a/Swift/Controllers/Chat/ChatsManager.h +++ b/Swift/Controllers/Chat/ChatsManager.h @@ -61,7 +61,7 @@ namespace Swift { EventController* eventController_; JID jid_; StanzaChannel* stanzaChannel_; - IQRouter* iqRouter_;; + IQRouter* iqRouter_; ChatWindowFactory* chatWindowFactory_; NickResolver* nickResolver_; PresenceOracle* presenceOracle_; diff --git a/Swift/Controllers/UIInterfaces/ChatWindow.h b/Swift/Controllers/UIInterfaces/ChatWindow.h index 4d00dca..1ee632c 100644 --- a/Swift/Controllers/UIInterfaces/ChatWindow.h +++ b/Swift/Controllers/UIInterfaces/ChatWindow.h @@ -25,11 +25,18 @@ namespace Swift { class ChatWindow { public: + enum AckState {Pending, Received, Failed}; ChatWindow() {} virtual ~ChatWindow() {}; - virtual void addMessage(const String& message, const String& senderName, bool senderIsSelf, const boost::optional& label, const String& avatarPath, const boost::posix_time::ptime& time) = 0; - virtual void addAction(const String& message, const String& senderName, bool senderIsSelf, const boost::optional& label, const String& avatarPath, const boost::posix_time::ptime& time) = 0; + /** Add message to window. + * @return id of added message (for acks). + */ + virtual String addMessage(const String& message, const String& senderName, bool senderIsSelf, const boost::optional& label, const String& avatarPath, const boost::posix_time::ptime& time) = 0; + /** Adds action to window. + * @return id of added message (for acks); + */ + virtual String addAction(const String& message, const String& senderName, bool senderIsSelf, const boost::optional& label, const String& avatarPath, const boost::posix_time::ptime& time) = 0; virtual void addSystemMessage(const String& message) = 0; virtual void addPresenceMessage(const String& message) = 0; virtual void addErrorMessage(const String& message) = 0; @@ -49,6 +56,7 @@ namespace Swift { virtual void setRosterModel(Roster* model) = 0; virtual void setTabComplete(TabComplete* completer) = 0; virtual void replaceLastMessage(const String& message) = 0; + virtual void setAckState(const String& id, AckState state) = 0; boost::signal onClosed; boost::signal onAllMessagesRead; diff --git a/Swift/Controllers/UnitTest/MockChatWindow.h b/Swift/Controllers/UnitTest/MockChatWindow.h index 822a128..4e7a117 100644 --- a/Swift/Controllers/UnitTest/MockChatWindow.h +++ b/Swift/Controllers/UnitTest/MockChatWindow.h @@ -14,8 +14,8 @@ namespace Swift { MockChatWindow() {}; virtual ~MockChatWindow(); - virtual void addMessage(const String& message, const String& /*senderName*/, bool /*senderIsSelf*/, const boost::optional& /*label*/, const String& /*avatarPath*/, const boost::posix_time::ptime&) {lastMessageBody_ = message;}; - virtual void addAction(const String& message, const String& /*senderName*/, bool /*senderIsSelf*/, const boost::optional& /*label*/, const String& /*avatarPath*/, const boost::posix_time::ptime&) {lastMessageBody_ = message;}; + virtual String addMessage(const String& message, const String& /*senderName*/, bool /*senderIsSelf*/, const boost::optional& /*label*/, const String& /*avatarPath*/, const boost::posix_time::ptime&) {lastMessageBody_ = message; return "";}; + virtual String addAction(const String& message, const String& /*senderName*/, bool /*senderIsSelf*/, const boost::optional& /*label*/, const String& /*avatarPath*/, const boost::posix_time::ptime&) {lastMessageBody_ = message; return "";}; virtual void addSystemMessage(const String& /*message*/) {}; virtual void addErrorMessage(const String& /*message*/) {}; virtual void addPresenceMessage(const String& /*message*/) {}; @@ -34,6 +34,7 @@ namespace Swift { virtual void setRosterModel(Roster* /*roster*/) {}; virtual void setTabComplete(TabComplete*) {}; virtual void replaceLastMessage(const Swift::String&) {}; + void setAckState(const String& /*id*/, AckState /*state*/) {}; boost::signal onClosed; boost::signal onAllMessagesRead; diff --git a/Swift/QtUI/MessageSnippet.cpp b/Swift/QtUI/MessageSnippet.cpp index 0159386..1c8ddca 100644 --- a/Swift/QtUI/MessageSnippet.cpp +++ b/Swift/QtUI/MessageSnippet.cpp @@ -11,7 +11,7 @@ namespace Swift { -MessageSnippet::MessageSnippet(const QString& message, const QString& sender, const QDateTime& time, const QString& iconURI, bool isIncoming, bool appendToPrevious, QtChatTheme* theme) : ChatSnippet(appendToPrevious) { +MessageSnippet::MessageSnippet(const QString& message, const QString& sender, const QDateTime& time, const QString& iconURI, bool isIncoming, bool appendToPrevious, QtChatTheme* theme, const QString& id) : ChatSnippet(appendToPrevious) { if (isIncoming) { if (appendToPrevious) { content_ = theme->getIncomingNextContent(); @@ -29,10 +29,11 @@ MessageSnippet::MessageSnippet(const QString& message, const QString& sender, co } } - content_.replace("%message%", "" + escape(message) + ""); + content_.replace("%message%", "" + escape(message) + ""); content_.replace("%sender%", escape(sender)); content_.replace("%time%", "" + escape(time.toString("h:mm")) + ""); content_.replace("%userIconPath%", escape(iconURI)); + content_ = "
" + content_ + "
"; } MessageSnippet::~MessageSnippet() { diff --git a/Swift/QtUI/MessageSnippet.h b/Swift/QtUI/MessageSnippet.h index 4918c19..c7425e9 100644 --- a/Swift/QtUI/MessageSnippet.h +++ b/Swift/QtUI/MessageSnippet.h @@ -15,7 +15,7 @@ class QDateTime; namespace Swift { class MessageSnippet : public ChatSnippet { public: - MessageSnippet(const QString& message, const QString& sender, const QDateTime& time, const QString& iconURI, bool isIncoming, bool appendToPrevious, QtChatTheme* theme); + MessageSnippet(const QString& message, const QString& sender, const QDateTime& time, const QString& iconURI, bool isIncoming, bool appendToPrevious, QtChatTheme* theme, const QString& id); virtual ~MessageSnippet(); const QString& getContent() const { return content_; diff --git a/Swift/QtUI/QtChatView.cpp b/Swift/QtUI/QtChatView.cpp index d48365b..145371f 100644 --- a/Swift/QtUI/QtChatView.cpp +++ b/Swift/QtUI/QtChatView.cpp @@ -129,6 +129,15 @@ void QtChatView::copySelectionToClipboard() { } } +void QtChatView::setAckXML(const QString& id, const QString& xml) { + QWebElement message = document_.findFirst("#" + id); + /* Deliberately not asserting here, so that when we start expiring old messages it won't hit us */ + if (message.isNull()) return; + QWebElement ackElement = message.findFirst("span.swift_ack"); + assert(!ackElement.isNull()); + ackElement.setInnerXml(xml); +} + bool QtChatView::isScrolledToBottom() const { return webPage_->mainFrame()->scrollBarValue(Qt::Vertical) == webPage_->mainFrame()->scrollBarMaximum(Qt::Vertical); } diff --git a/Swift/QtUI/QtChatView.h b/Swift/QtUI/QtChatView.h index ce1f8bc..e60c92f 100644 --- a/Swift/QtUI/QtChatView.h +++ b/Swift/QtUI/QtChatView.h @@ -31,6 +31,7 @@ namespace Swift { void replaceLastMessage(const QString& newMessage); void replaceLastMessage(const QString& newMessage, const QString& note); bool isScrolledToBottom() const; + void setAckXML(const QString& id, const QString& xml); signals: void gotFocus(); diff --git a/Swift/QtUI/QtChatWindow.cpp b/Swift/QtUI/QtChatWindow.cpp index 70bde4b..2955ee4 100644 --- a/Swift/QtUI/QtChatWindow.cpp +++ b/Swift/QtUI/QtChatWindow.cpp @@ -245,11 +245,11 @@ void QtChatWindow::updateTitleWithUnreadCount() { emit titleUpdated(); } -void QtChatWindow::addMessage(const String &message, const String &senderName, bool senderIsSelf, const boost::optional& label, const String& avatarPath, const boost::posix_time::ptime& time) { - addMessage(message, senderName, senderIsSelf, label, avatarPath, "", time); +String QtChatWindow::addMessage(const String &message, const String &senderName, bool senderIsSelf, const boost::optional& label, const String& avatarPath, const boost::posix_time::ptime& time) { + return addMessage(message, senderName, senderIsSelf, label, avatarPath, "", time); } -void QtChatWindow::addMessage(const String &message, const String &senderName, bool senderIsSelf, const boost::optional& label, const String& avatarPath, const QString& style, const boost::posix_time::ptime& time) { +String QtChatWindow::addMessage(const String &message, const String &senderName, bool senderIsSelf, const boost::optional& label, const String& avatarPath, const QString& style, const boost::posix_time::ptime& time) { if (isWidgetSelected()) { onAllMessagesRead(); } @@ -268,20 +268,32 @@ void QtChatWindow::addMessage(const String &message, const String &senderName, b bool appendToPrevious = !previousMessageWasSystem_ && !previousMessageWasPresence_ && ((senderIsSelf && previousMessageWasSelf_) || (!senderIsSelf && !previousMessageWasSelf_ && previousSenderName_ == P2QSTRING(senderName))); QString qAvatarPath = avatarPath.isEmpty() ? "qrc:/icons/avatar.png" : QUrl::fromLocalFile(P2QSTRING(avatarPath)).toEncoded(); - messageLog_->addMessage(boost::shared_ptr(new MessageSnippet(htmlString, Qt::escape(P2QSTRING(senderName)), B2QDATE(time), qAvatarPath, senderIsSelf, appendToPrevious, theme_))); + String id = id_.generateID(); + messageLog_->addMessage(boost::shared_ptr(new MessageSnippet(htmlString, Qt::escape(P2QSTRING(senderName)), B2QDATE(time), qAvatarPath, senderIsSelf, appendToPrevious, theme_, P2QSTRING(id)))); previousMessageWasSelf_ = senderIsSelf; previousSenderName_ = P2QSTRING(senderName); previousMessageWasSystem_ = false; previousMessageWasPresence_ = false; + return id; +} + +void QtChatWindow::setAckState(String const& id, ChatWindow::AckState state) { + QString xml; + switch (state) { + case ChatWindow::Pending: xml = "This message has not been received by your server yet."; break; + case ChatWindow::Received: xml = ""; break; + case ChatWindow::Failed: xml = "This message may not have been transmitted."; break; + } + messageLog_->setAckXML(P2QSTRING(id), xml); } int QtChatWindow::getCount() { return unreadCount_; } -void QtChatWindow::addAction(const String &message, const String &senderName, bool senderIsSelf, const boost::optional& label, const String& avatarPath, const boost::posix_time::ptime& time) { - addMessage(" *" + message + "*", senderName, senderIsSelf, label, avatarPath, "font-style:italic ", time); +String QtChatWindow::addAction(const String &message, const String &senderName, bool senderIsSelf, const boost::optional& label, const String& avatarPath, const boost::posix_time::ptime& time) { + return addMessage(" *" + message + "*", senderName, senderIsSelf, label, avatarPath, "font-style:italic ", time); } void QtChatWindow::addErrorMessage(const String& errorMessage) { diff --git a/Swift/QtUI/QtChatWindow.h b/Swift/QtUI/QtChatWindow.h index a51b866..333aa44 100644 --- a/Swift/QtUI/QtChatWindow.h +++ b/Swift/QtUI/QtChatWindow.h @@ -11,6 +11,8 @@ #include "QtTabbable.h" +#include "Swiften/Base/IDGenerator.h" + class QTextEdit; class QLineEdit; class QComboBox; @@ -28,8 +30,8 @@ namespace Swift { public: QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventStream* eventStream); ~QtChatWindow(); - void addMessage(const String &message, const String &senderName, bool senderIsSelf, const boost::optional& label, const String& avatarPath, const boost::posix_time::ptime& time); - void addAction(const String &message, const String &senderName, bool senderIsSelf, const boost::optional& label, const String& avatarPath, const boost::posix_time::ptime& time); + String addMessage(const String &message, const String &senderName, bool senderIsSelf, const boost::optional& label, const String& avatarPath, const boost::posix_time::ptime& time); + String addAction(const String &message, const String &senderName, bool senderIsSelf, const boost::optional& label, const String& avatarPath, const boost::posix_time::ptime& time); void addSystemMessage(const String& message); void addPresenceMessage(const String& message); void addErrorMessage(const String& errorMessage); @@ -50,6 +52,7 @@ namespace Swift { void setTabComplete(TabComplete* completer); int getCount(); void replaceLastMessage(const String& message); + void setAckState(const String& id, AckState state); signals: void geometryChanged(); @@ -71,7 +74,7 @@ namespace Swift { private: void updateTitleWithUnreadCount(); void tabComplete(); - void addMessage(const String &message, const String &senderName, bool senderIsSelf, const boost::optional& label, const String& avatarPath, const QString& style, const boost::posix_time::ptime& time); + String addMessage(const String &message, const String &senderName, bool senderIsSelf, const boost::optional& label, const String& avatarPath, const QString& style, const boost::posix_time::ptime& time); int unreadCount_; bool contactIsTyping_; @@ -90,6 +93,7 @@ namespace Swift { bool inputClearing_; UIEventStream* eventStream_; bool inputEnabled_; + IDGenerator id_; }; } diff --git a/Swift/QtUI/Swift.qrc b/Swift/QtUI/Swift.qrc index 4da687c..6c8e027 100644 --- a/Swift/QtUI/Swift.qrc +++ b/Swift/QtUI/Swift.qrc @@ -10,6 +10,7 @@ ../resources/icons/offline.png ../resources/icons/certificate.png ../resources/icons/error.png + ../resources/icons/throbber.gif ../resources/icons/avatar.png ../resources/icons/tray-standard.png ../resources/icons/new-chat.png diff --git a/Swift/resources/icons/throbber.gif b/Swift/resources/icons/throbber.gif new file mode 100644 index 0000000..d0bce15 Binary files /dev/null and b/Swift/resources/icons/throbber.gif differ diff --git a/Swiften/Client/Client.h b/Swiften/Client/Client.h index 10e7c38..57228ef 100644 --- a/Swiften/Client/Client.h +++ b/Swiften/Client/Client.h @@ -55,7 +55,6 @@ namespace Swift { boost::signal onConnected; boost::signal onDataRead; boost::signal onDataWritten; - boost::signal)> onStanzaAcked; private: void handleConnectorFinished(boost::shared_ptr, Connector::ref); diff --git a/Swiften/Client/DummyStanzaChannel.h b/Swiften/Client/DummyStanzaChannel.h index b35ed92..d43d68a 100644 --- a/Swiften/Client/DummyStanzaChannel.h +++ b/Swiften/Client/DummyStanzaChannel.h @@ -39,6 +39,10 @@ namespace Swift { return true; } + virtual bool getStreamManagementEnabled() const { + return false; + } + template bool isRequestAtIndex(int index, const JID& jid, IQ::Type type) { boost::shared_ptr iqStanza = boost::dynamic_pointer_cast(sentStanzas[index]); return iqStanza && iqStanza->getType() == type && iqStanza->getTo() == jid && iqStanza->getPayload(); diff --git a/Swiften/Client/StanzaChannel.h b/Swiften/Client/StanzaChannel.h index bfde05c..09a6db3 100644 --- a/Swiften/Client/StanzaChannel.h +++ b/Swiften/Client/StanzaChannel.h @@ -19,8 +19,10 @@ namespace Swift { virtual void sendMessage(boost::shared_ptr) = 0; virtual void sendPresence(boost::shared_ptr) = 0; virtual bool isAvailable() = 0; + virtual bool getStreamManagementEnabled() const = 0; boost::signal)> onMessageReceived; boost::signal) > onPresenceReceived; + boost::signal)> onStanzaAcked; }; } -- cgit v0.10.2-6-g49f6