From d509598b0f0edf5e103caedbab8662edc834445e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Remko=20Tron=C3=A7on?= Date: Sun, 31 Oct 2010 19:51:01 +0100 Subject: Refactoring Presence & MUC handling. diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp index 4a9e164..5a32ced 100644 --- a/Swift/Controllers/Chat/ChatsManager.cpp +++ b/Swift/Controllers/Chat/ChatsManager.cpp @@ -18,6 +18,7 @@ #include "Swift/Controllers/UIEvents/EditMUCBookmarkUIEvent.h" #include "Swift/Controllers/UIInterfaces/ChatListWindowFactory.h" #include "Swiften/Presence/PresenceSender.h" +#include "Swiften/MUC/MUCManager.h" #include "Swiften/Elements/ChatState.h" #include "Swiften/MUC/MUCBookmarkManager.h" @@ -26,7 +27,7 @@ namespace Swift { typedef std::pair JIDChatControllerPair; typedef std::pair JIDMUCControllerPair; -ChatsManager::ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, PresenceSender* presenceSender, UIEventStream* uiEventStream, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency, TimerFactory* timerFactory, MUCRegistry* mucRegistry, EntityCapsManager* entityCapsManager) : jid_(jid), useDelayForLatency_(useDelayForLatency), mucRegistry_(mucRegistry), entityCapsManager_(entityCapsManager) { +ChatsManager::ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, PresenceSender* presenceSender, UIEventStream* uiEventStream, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency, TimerFactory* timerFactory, MUCRegistry* mucRegistry, EntityCapsManager* entityCapsManager, MUCManager* mucManager) : jid_(jid), useDelayForLatency_(useDelayForLatency), mucRegistry_(mucRegistry), entityCapsManager_(entityCapsManager), mucManager(mucManager) { timerFactory_ = timerFactory; eventController_ = eventController; stanzaChannel_ = stanzaChannel; @@ -83,7 +84,6 @@ void ChatsManager::handleUserLeftMUC(MUCController* mucController) { std::map::iterator it; for (it = mucControllers_.begin(); it != mucControllers_.end(); it++) { if ((*it).second == mucController) { - mucRegistry_->removeMUC(it->first); mucControllers_.erase(it); delete mucController; return; @@ -214,19 +214,19 @@ void ChatsManager::rebindControllerJID(const JID& from, const JID& to) { chatControllers_[to]->setToJID(to); } -void ChatsManager::handleJoinMUCRequest(const JID &muc, const boost::optional& nickMaybe) { - std::map::iterator it = mucControllers_.find(muc); +void ChatsManager::handleJoinMUCRequest(const JID &mucJID, const boost::optional& nickMaybe) { + std::map::iterator it = mucControllers_.find(mucJID); if (it != mucControllers_.end()) { it->second->rejoin(); } else { String nick = nickMaybe ? nickMaybe.get() : jid_.getNode(); - MUCController* controller = new MUCController(jid_, muc, nick, stanzaChannel_, presenceSender_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory_, eventController_); - mucControllers_[muc] = controller; + MUC::ref muc = mucManager->createMUC(mucJID); + MUCController* controller = new MUCController(jid_, muc, nick, stanzaChannel_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory_, eventController_); + mucControllers_[mucJID] = controller; controller->setAvailableServerFeatures(serverDiscoInfo_); controller->onUserLeft.connect(boost::bind(&ChatsManager::handleUserLeftMUC, this, controller)); - mucRegistry_->addMUC(muc); } - mucControllers_[muc]->activateChatWindow(); + mucControllers_[mucJID]->activateChatWindow(); } void ChatsManager::handleIncomingMessage(boost::shared_ptr message) { diff --git a/Swift/Controllers/Chat/ChatsManager.h b/Swift/Controllers/Chat/ChatsManager.h index 724701c..0880f80 100644 --- a/Swift/Controllers/Chat/ChatsManager.h +++ b/Swift/Controllers/Chat/ChatsManager.h @@ -23,6 +23,7 @@ namespace Swift { class EventController; class ChatController; class MUCController; + class MUCManager; class ChatWindowFactory; class NickResolver; class PresenceOracle; @@ -35,10 +36,11 @@ namespace Swift { class ChatListWindowFactory; class TimerFactory; class EntityCapsManager; + class DirectedPresenceSender; class ChatsManager { public: - ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, PresenceSender* presenceSender, UIEventStream* uiEventStream, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency, TimerFactory* timerFactory, MUCRegistry* mucRegistry, EntityCapsManager* entityCapsManager); + ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, PresenceSender* presenceSender, UIEventStream* uiEventStream, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency, TimerFactory* timerFactory, MUCRegistry* mucRegistry, EntityCapsManager* entityCapsManager, MUCManager* mucManager); virtual ~ChatsManager(); void setAvatarManager(AvatarManager* avatarManager); void setOnline(bool enabled); @@ -78,5 +80,6 @@ namespace Swift { TimerFactory* timerFactory_; MUCRegistry* mucRegistry_; EntityCapsManager* entityCapsManager_; + MUCManager* mucManager; }; } diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp index ff102e7..259b715 100644 --- a/Swift/Controllers/Chat/MUCController.cpp +++ b/Swift/Controllers/Chat/MUCController.cpp @@ -36,10 +36,9 @@ namespace Swift { */ MUCController::MUCController ( const JID& self, - const JID &muc, + MUC::ref muc, const String &nick, StanzaChannel* stanzaChannel, - PresenceSender* presenceSender, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, PresenceOracle* presenceOracle, @@ -48,7 +47,7 @@ MUCController::MUCController ( bool useDelayForLatency, TimerFactory* timerFactory, EventController* eventController) : - ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, muc, presenceOracle, avatarManager, useDelayForLatency, uiEventStream, eventController, timerFactory), muc_(new MUC(stanzaChannel, iqRouter, presenceSender, muc)), nick_(nick) { + ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, muc->getJID(), presenceOracle, avatarManager, useDelayForLatency, uiEventStream, eventController, timerFactory), muc_(muc), nick_(nick) { parting_ = true; joined_ = false; lastWasPresence_ = false; @@ -59,7 +58,7 @@ MUCController::MUCController ( completer_ = new TabComplete(); chatWindow_->setRosterModel(roster_); chatWindow_->setTabComplete(completer_); - chatWindow_->setName(muc.getNode()); + chatWindow_->setName(muc->getJID().getNode()); chatWindow_->onClosed.connect(boost::bind(&MUCController::handleWindowClosed, this)); muc_->onJoinComplete.connect(boost::bind(&MUCController::handleJoinComplete, this, _1)); muc_->onJoinFailed.connect(boost::bind(&MUCController::handleJoinFailed, this, _1)); @@ -80,7 +79,6 @@ MUCController::MUCController ( } MUCController::~MUCController() { - delete muc_; chatWindow_->setRosterModel(NULL); delete roster_; if (loginCheckTimer_) { diff --git a/Swift/Controllers/Chat/MUCController.h b/Swift/Controllers/Chat/MUCController.h index 2a6536c..1af9c58 100644 --- a/Swift/Controllers/Chat/MUCController.h +++ b/Swift/Controllers/Chat/MUCController.h @@ -41,7 +41,7 @@ namespace Swift { class MUCController : public ChatControllerBase { public: - MUCController(const JID& self, const JID &muc, const String &nick, StanzaChannel* stanzaChannel, PresenceSender* presenceSender, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, PresenceOracle* presenceOracle, AvatarManager* avatarManager, UIEventStream* events, bool useDelayForLatency, TimerFactory* timerFactory, EventController* eventController); + MUCController(const JID& self, MUC::ref muc, const String &nick, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, PresenceOracle* presenceOracle, AvatarManager* avatarManager, UIEventStream* events, bool useDelayForLatency, TimerFactory* timerFactory, EventController* eventController); ~MUCController(); boost::signal onUserLeft; virtual void setOnline(bool online); @@ -80,7 +80,7 @@ namespace Swift { void processUserPart(); private: - MUC* muc_; + MUC::ref muc_; UIEventStream* events_; String nick_; Roster* roster_; diff --git a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp index 44fbcfe..08106e6 100644 --- a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp +++ b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp @@ -16,15 +16,17 @@ #include "Swiften/Client/Client.h" #include "Swiften/Disco/EntityCapsManager.h" #include "Swiften/Disco/CapsProvider.h" +#include "Swiften/MUC/MUCManager.h" #include "Swift/Controllers/Chat/ChatController.h" #include "Swift/Controllers/XMPPEvents/EventController.h" #include "Swift/Controllers/Chat/MUCController.h" -#include "Swiften/Presence/PresenceSender.h" +#include "Swiften/Presence/StanzaChannelPresenceSender.h" #include "Swiften/Avatars/NullAvatarManager.h" #include "Swiften/Avatars/AvatarMemoryStorage.h" #include "Swiften/VCards/VCardManager.h" #include "Swiften/VCards/VCardMemoryStorage.h" #include "Swiften/Client/NickResolver.h" +#include "Swiften/Presence/DirectedPresenceSender.h" #include "Swiften/Roster/XMPPRosterImpl.h" #include "Swift/Controllers/UnitTest/MockChatWindow.h" #include "Swiften/Client/DummyStanzaChannel.h" @@ -71,12 +73,14 @@ public: nickResolver_ = new NickResolver(jid_.toBare(), xmppRoster_, NULL, mucRegistry_); presenceOracle_ = new PresenceOracle(stanzaChannel_); serverDiscoInfo_ = boost::shared_ptr(new DiscoInfo()); - presenceSender_ = new PresenceSender(stanzaChannel_); + presenceSender_ = new StanzaChannelPresenceSender(stanzaChannel_); + directedPresenceSender_ = new DirectedPresenceSender(presenceSender_); + mucManager_ = new MUCManager(stanzaChannel_, iqRouter_, directedPresenceSender_, mucRegistry_); uiEventStream_ = new UIEventStream(); entityCapsManager_ = new EntityCapsManager(capsProvider_, stanzaChannel_); chatListWindowFactory_ = mocks_->InterfaceMock(); mocks_->ExpectCall(chatListWindowFactory_, ChatListWindowFactory::createWindow).With(uiEventStream_).Return(NULL); - manager_ = new ChatsManager(jid_, stanzaChannel_, iqRouter_, eventController_, chatWindowFactory_, nickResolver_, presenceOracle_, presenceSender_, uiEventStream_, chatListWindowFactory_, true, NULL, mucRegistry_, entityCapsManager_); + manager_ = new ChatsManager(jid_, stanzaChannel_, iqRouter_, eventController_, chatWindowFactory_, nickResolver_, presenceOracle_, directedPresenceSender_, uiEventStream_, chatListWindowFactory_, true, NULL, mucRegistry_, entityCapsManager_, mucManager_); avatarManager_ = new NullAvatarManager(); manager_->setAvatarManager(avatarManager_); @@ -87,6 +91,7 @@ public: delete mocks_; delete avatarManager_; delete manager_; + delete directedPresenceSender_; delete presenceSender_; delete presenceOracle_; delete nickResolver_; @@ -96,6 +101,7 @@ public: delete iqChannel_; delete iqRouter_; delete uiEventStream_; + delete mucManager_; delete xmppRoster_; delete entityCapsManager_; delete capsProvider_; @@ -329,8 +335,10 @@ private: UIEventStream* uiEventStream_; ChatListWindowFactory* chatListWindowFactory_; MUCRegistry* mucRegistry_; + DirectedPresenceSender* directedPresenceSender_; EntityCapsManager* entityCapsManager_; CapsProvider* capsProvider_; + MUCManager* mucManager_; }; CPPUNIT_TEST_SUITE_REGISTRATION(ChatsManagerTest); diff --git a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp index ea5a705..fb3a0ee 100644 --- a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp +++ b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp @@ -9,7 +9,8 @@ #include "3rdParty/hippomocks.h" #include "Swift/Controllers/XMPPEvents/EventController.h" -#include "Swiften/Presence/PresenceSender.h" +#include "Swiften/Presence/DirectedPresenceSender.h" +#include "Swiften/Presence/StanzaChannelPresenceSender.h" #include "Swiften/Avatars/NullAvatarManager.h" #include "Swift/Controllers/Chat/MUCController.h" #include "Swift/Controllers/UIInterfaces/ChatWindow.h" @@ -42,7 +43,6 @@ public: void setUp() { self_ = JID("girl@wonderland.lit/rabbithole"); - muc_ = JID("teaparty@rooms.wonderland.lit"); nick_ = "aLiCe"; mocks_ = new MockRepository(); stanzaChannel_ = new DummyStanzaChannel(); @@ -51,14 +51,16 @@ public: eventController_ = new EventController(); chatWindowFactory_ = mocks_->InterfaceMock(); presenceOracle_ = new PresenceOracle(stanzaChannel_); - presenceSender_ = new PresenceSender(stanzaChannel_); + presenceSender_ = new StanzaChannelPresenceSender(stanzaChannel_); + directedPresenceSender_ = new DirectedPresenceSender(presenceSender_); uiEventStream_ = new UIEventStream(); avatarManager_ = new NullAvatarManager(); TimerFactory* timerFactory = NULL; window_ = new MockChatWindow();//mocks_->InterfaceMock(); - mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(muc_, uiEventStream_).Return(window_); - controller_ = new MUCController (self_, muc_, nick_, stanzaChannel_, presenceSender_, - iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory, eventController_); + mucRegistry_ = new MUCRegistry(); + muc_ = MUC::ref(new MUC(stanzaChannel_, iqRouter_, directedPresenceSender_, JID("teaparty@rooms.wonderland.lit"), mucRegistry_)); + mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(muc_->getJID(), uiEventStream_).Return(window_); + controller_ = new MUCController (self_, muc_, nick_, stanzaChannel_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory, eventController_); }; void tearDown() { @@ -69,14 +71,16 @@ public: 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_.toString() + "/" + nick_)); + presence->setFrom(JID(muc_->getJID().toString() + "/" + nick_)); MUCUserPayload::ref status(new MUCUserPayload()); MUCUserPayload::StatusCode code; code.code = 110; @@ -90,20 +94,20 @@ public: Message::ref message(new Message()); message = Message::ref(new Message()); - message->setFrom(JID(muc_.toString() + "/otherperson")); + 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)1, eventController_->getEvents().size()); - message->setFrom(JID(muc_.toString() + "/other")); + 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)2, eventController_->getEvents().size()); message = Message::ref(new Message()); - message->setFrom(JID(muc_.toString() + "/other2")); + message->setFrom(JID(muc_->getJID().toString() + "/other2")); message->setBody("Hi " + nick_.getLowerCase()); message->setType(Message::Groupchat); controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message))); @@ -113,7 +117,7 @@ public: void testNotAddressedToSelf() { finishJoin(); Message::ref message(new Message()); - message->setFrom(JID(muc_.toString() + "/other3")); + message->setFrom(JID(muc_->getJID().toString() + "/other3")); message->setBody("Hi there Hatter"); message->setType(Message::Groupchat); controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message))); @@ -123,7 +127,7 @@ public: void testAddressedToSelfBySelf() { finishJoin(); Message::ref message(new Message()); - message->setFrom(JID(muc_.toString() + "/" + nick_)); + message->setFrom(JID(muc_->getJID().toString() + "/" + nick_)); message->setBody("Hi there " + nick_); message->setType(Message::Groupchat); controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message))); @@ -200,7 +204,7 @@ public: private: JID self_; - JID muc_; + MUC::ref muc_; String nick_; StanzaChannel* stanzaChannel_; IQChannel* iqChannel_; @@ -211,10 +215,12 @@ private: // NickResolver* nickResolver_; PresenceOracle* presenceOracle_; AvatarManager* avatarManager_; - PresenceSender* presenceSender_; + StanzaChannelPresenceSender* presenceSender_; + DirectedPresenceSender* directedPresenceSender_; MockRepository* mocks_; UIEventStream* uiEventStream_; MockChatWindow* window_; + MUCRegistry* mucRegistry_; }; CPPUNIT_TEST_SUITE_REGISTRATION(MUCControllerTest); diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp index 4501f2c..f3b9977 100644 --- a/Swift/Controllers/MainController.cpp +++ b/Swift/Controllers/MainController.cpp @@ -231,11 +231,11 @@ void MainController::handleConnected() { bool freshLogin = rosterController_ == NULL; myStatusLooksOnline_ = true; if (freshLogin) { - rosterController_ = new RosterController(jid_, client_->getRoster(), client_->getAvatarManager(), mainWindowFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), eventController_, uiEventStream_, client_->getIQRouter(), settings_); + rosterController_ = new RosterController(jid_, client_->getRoster(), client_->getAvatarManager(), mainWindowFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getSubscriptionManager(), eventController_, uiEventStream_, client_->getIQRouter(), settings_); rosterController_->onChangeStatusRequest.connect(boost::bind(&MainController::handleChangeStatusRequest, this, _1, _2)); rosterController_->onSignOutRequest.connect(boost::bind(&MainController::signOut, this)); - chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, chatWindowFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, chatListWindowFactory_, useDelayForLatency_, &timerFactory_, client_->getMUCRegistry(), client_->getEntityCapsManager()); + chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, chatWindowFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, chatListWindowFactory_, useDelayForLatency_, &timerFactory_, client_->getMUCRegistry(), client_->getEntityCapsManager(), client_->getMUCManager()); client_->onMessageReceived.connect(boost::bind(&ChatsManager::handleIncomingMessage, chatsManager_, _1)); chatsManager_->setAvatarManager(client_->getAvatarManager()); diff --git a/Swift/Controllers/RosterController.cpp b/Swift/Controllers/RosterController.cpp index 1ce3266..242f974 100644 --- a/Swift/Controllers/RosterController.cpp +++ b/Swift/Controllers/RosterController.cpp @@ -17,7 +17,7 @@ #include "Swift/Controllers/XMPPEvents/SubscriptionRequestEvent.h" #include "Swift/Controllers/XMPPEvents/ErrorEvent.h" #include "Swiften/Presence/PresenceOracle.h" -#include "Swiften/Presence/PresenceSender.h" +#include "Swiften/Presence/SubscriptionManager.h" #include "Swift/Controllers/XMPPEvents/EventController.h" #include "Swiften/Queries/IQRouter.h" #include "Swiften/Roster/Roster.h" @@ -37,11 +37,11 @@ namespace Swift { /** * The controller does not gain ownership of these parameters. */ -RosterController::RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, PresenceSender* presenceSender, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter, SettingsProvider* settings) +RosterController::RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, SubscriptionManager* subscriptionManager, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter, SettingsProvider* settings) : myJID_(jid), xmppRoster_(xmppRoster), mainWindowFactory_(mainWindowFactory), mainWindow_(mainWindowFactory_->createMainWindow(uiEventStream)), roster_(new Roster()), offlineFilter_(new OfflineRosterFilter()) { iqRouter_ = iqRouter; presenceOracle_ = presenceOracle; - presenceSender_ = presenceSender; + subscriptionManager_ = subscriptionManager; eventController_ = eventController; expandiness_ = new RosterGroupExpandinessPersister(roster_, settings); roster_->addFilter(offlineFilter_); @@ -54,7 +54,7 @@ RosterController::RosterController(const JID& jid, XMPPRoster* xmppRoster, Avata xmppRoster_->onJIDUpdated.connect(boost::bind(&RosterController::handleOnJIDUpdated, this, _1, _2, _3)); xmppRoster_->onJIDRemoved.connect(boost::bind(&RosterController::handleOnJIDRemoved, this, _1)); xmppRoster_->onRosterCleared.connect(boost::bind(&RosterController::handleRosterCleared, this)); - presenceOracle_->onPresenceSubscriptionRequest.connect(boost::bind(&RosterController::handleSubscriptionRequest, this, _1, _2)); + subscriptionManager_->onPresenceSubscriptionRequest.connect(boost::bind(&RosterController::handleSubscriptionRequest, this, _1, _2)); presenceOracle_->onPresenceChange.connect(boost::bind(&RosterController::handleIncomingPresence, this, _1)); uiEventConnection_ = uiEventStream->onUIEvent.connect(boost::bind(&RosterController::handleUIEvent, this, _1)); avatarManager_ = avatarManager; @@ -167,7 +167,7 @@ void RosterController::handleUIEvent(boost::shared_ptr event) { SetRosterRequest::ref request = SetRosterRequest::create(roster, iqRouter_); request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster)); request->send(); - presenceSender_->requestSubscription(addContactEvent->getJID()); + subscriptionManager_->requestSubscription(addContactEvent->getJID()); return; } boost::shared_ptr removeEvent = boost::dynamic_pointer_cast(event); @@ -240,7 +240,7 @@ void RosterController::handleIncomingPresence(Presence::ref newPresence) { void RosterController::handleSubscriptionRequest(const JID& jid, const String& message) { if (xmppRoster_->containsJID(jid) && (xmppRoster_->getSubscriptionStateForJID(jid) == RosterItemPayload::To || xmppRoster_->getSubscriptionStateForJID(jid) == RosterItemPayload::Both)) { - presenceSender_->confirmSubscription(jid); + subscriptionManager_->confirmSubscription(jid); return; } SubscriptionRequestEvent* eventPointer = new SubscriptionRequestEvent(jid, message); @@ -251,14 +251,14 @@ void RosterController::handleSubscriptionRequest(const JID& jid, const String& m } void RosterController::handleSubscriptionRequestAccepted(SubscriptionRequestEvent* event) { - presenceSender_->confirmSubscription(event->getJID()); + subscriptionManager_->confirmSubscription(event->getJID()); if (!xmppRoster_->containsJID(event->getJID()) || xmppRoster_->getSubscriptionStateForJID(event->getJID()) == RosterItemPayload::None || xmppRoster_->getSubscriptionStateForJID(event->getJID()) == RosterItemPayload::From) { - presenceSender_->requestSubscription(event->getJID()); + subscriptionManager_->requestSubscription(event->getJID()); } } void RosterController::handleSubscriptionRequestDeclined(SubscriptionRequestEvent* event) { - presenceSender_->cancelSubscription(event->getJID()); + subscriptionManager_->cancelSubscription(event->getJID()); } void RosterController::handleAvatarChanged(const JID& jid) { diff --git a/Swift/Controllers/RosterController.h b/Swift/Controllers/RosterController.h index 3cb3812..cc51d23 100644 --- a/Swift/Controllers/RosterController.h +++ b/Swift/Controllers/RosterController.h @@ -4,8 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_RosterController_H -#define SWIFTEN_RosterController_H +#pragma once #include "Swiften/JID/JID.h" #include "Swiften/Base/String.h" @@ -28,7 +27,7 @@ namespace Swift { class OfflineRosterFilter; class NickResolver; class PresenceOracle; - class PresenceSender; + class SubscriptionManager; class EventController; class SubscriptionRequestEvent; class UIEventStream; @@ -37,7 +36,7 @@ namespace Swift { class RosterController { public: - RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, PresenceSender* presenceSender, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter_, SettingsProvider* settings); + RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, SubscriptionManager* subscriptionManager, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter_, SettingsProvider* settings); ~RosterController(); void showRosterWindow(); MainWindow* getWindow() {return mainWindow_;}; @@ -70,7 +69,7 @@ namespace Swift { AvatarManager* avatarManager_; NickResolver* nickResolver_; PresenceOracle* presenceOracle_; - PresenceSender* presenceSender_; + SubscriptionManager* subscriptionManager_; EventController* eventController_; RosterGroupExpandinessPersister* expandiness_; IQRouter* iqRouter_; @@ -80,5 +79,3 @@ namespace Swift { boost::bsignals::scoped_connection uiEventConnection_; }; } -#endif - diff --git a/Swift/Controllers/UnitTest/RosterControllerTest.cpp b/Swift/Controllers/UnitTest/RosterControllerTest.cpp index c0c0319..50419f9 100644 --- a/Swift/Controllers/UnitTest/RosterControllerTest.cpp +++ b/Swift/Controllers/UnitTest/RosterControllerTest.cpp @@ -24,7 +24,7 @@ #include "Swiften/Avatars/NullAvatarManager.h" #include "Swift/Controllers/XMPPEvents/EventController.h" #include "Swiften/Presence/PresenceOracle.h" -#include "Swiften/Presence/PresenceSender.h" +#include "Swiften/Presence/SubscriptionManager.h" #include "Swiften/Client/NickResolver.h" #include "Swift/Controllers/UIEvents/UIEventStream.h" #include "Swift/Controllers/UIEvents/RenameRosterItemUIEvent.h" @@ -63,11 +63,11 @@ class RosterControllerTest : public CppUnit::TestFixture router_ = new IQRouter(channel_); stanzaChannel_ = new DummyStanzaChannel(); presenceOracle_ = new PresenceOracle(stanzaChannel_); - presenceSender_ = new PresenceSender(stanzaChannel_); + subscriptionManager_ = new SubscriptionManager(stanzaChannel_); eventController_ = new EventController(); uiEventStream_ = new UIEventStream(); settings_ = new DummySettingsProvider(); - rosterController_ = new RosterController(jid_, xmppRoster_, avatarManager_, mainWindowFactory_, nickResolver_, presenceOracle_, presenceSender_, eventController_, uiEventStream_, router_, settings_); + rosterController_ = new RosterController(jid_, xmppRoster_, avatarManager_, mainWindowFactory_, nickResolver_, presenceOracle_, subscriptionManager_, eventController_, uiEventStream_, router_, settings_); mainWindow_ = mainWindowFactory_->last; }; @@ -80,7 +80,7 @@ class RosterControllerTest : public CppUnit::TestFixture delete channel_; delete router_; delete eventController_; - delete presenceSender_; + delete subscriptionManager_; delete presenceOracle_; delete stanzaChannel_; delete uiEventStream_; @@ -310,7 +310,7 @@ class RosterControllerTest : public CppUnit::TestFixture DummyStanzaChannel* stanzaChannel_; IQRouter* router_; PresenceOracle* presenceOracle_; - PresenceSender* presenceSender_; + SubscriptionManager* subscriptionManager_; EventController* eventController_; UIEventStream* uiEventStream_; MockMainWindow* mainWindow_; diff --git a/Swiften/Client/Client.cpp b/Swiften/Client/Client.cpp index 45eeeff..7dbcb70 100644 --- a/Swiften/Client/Client.cpp +++ b/Swiften/Client/Client.cpp @@ -10,8 +10,10 @@ #include "Swiften/Roster/XMPPRosterImpl.h" #include "Swiften/Roster/XMPPRosterController.h" #include "Swiften/Presence/PresenceOracle.h" -#include "Swiften/Presence/PresenceSender.h" +#include "Swiften/Presence/StanzaChannelPresenceSender.h" +#include "Swiften/Presence/DirectedPresenceSender.h" #include "Swiften/MUC/MUCRegistry.h" +#include "Swiften/MUC/MUCManager.h" #include "Swiften/Client/MemoryStorages.h" #include "Swiften/VCards/VCardManager.h" #include "Swiften/VCards/VCardManager.h" @@ -19,6 +21,7 @@ #include "Swiften/Disco/CapsManager.h" #include "Swiften/Disco/EntityCapsManager.h" #include "Swiften/Client/NickResolver.h" +#include "Swiften/Presence/SubscriptionManager.h" namespace Swift { @@ -31,13 +34,16 @@ Client::Client(EventLoop* eventLoop, const JID& jid, const String& password, Sto roster = new XMPPRosterImpl(); rosterController = new XMPPRosterController(getIQRouter(), roster); + subscriptionManager = new SubscriptionManager(getStanzaChannel()); + presenceOracle = new PresenceOracle(getStanzaChannel()); presenceOracle->onPresenceChange.connect(boost::ref(onPresenceChange)); - presenceOracle->onPresenceSubscriptionRequest.connect(boost::ref(onPresenceSubscriptionRequest)); - presenceSender = new PresenceSender(getStanzaChannel()); + stanzaChannelPresenceSender = new StanzaChannelPresenceSender(getStanzaChannel()); + directedPresenceSender = new DirectedPresenceSender(stanzaChannelPresenceSender); mucRegistry = new MUCRegistry(); + mucManager = new MUCManager(getStanzaChannel(), getIQRouter(), directedPresenceSender, mucRegistry); vcardManager = new VCardManager(jid, getIQRouter(), getStorages()->getVCardStorage()); avatarManager = new AvatarManagerImpl(vcardManager, getStanzaChannel(), getStorages()->getAvatarStorage(), mucRegistry); @@ -55,11 +61,14 @@ Client::~Client() { delete avatarManager; delete vcardManager; + delete mucManager; delete mucRegistry; - delete presenceSender; + delete directedPresenceSender; + delete stanzaChannelPresenceSender; delete presenceOracle; + delete subscriptionManager; delete rosterController; delete roster; @@ -81,7 +90,6 @@ void Client::requestRoster() { rosterController->requestRoster(); } - Presence::ref Client::getLastPresence(const JID& jid) const { return presenceOracle->getLastPresence(jid); } @@ -97,5 +105,8 @@ Storages* Client::getStorages() const { return memoryStorages; } +PresenceSender* Client::getPresenceSender() const { + return directedPresenceSender; +} } diff --git a/Swiften/Client/Client.h b/Swiften/Client/Client.h index 7e11df9..adfd549 100644 --- a/Swiften/Client/Client.h +++ b/Swiften/Client/Client.h @@ -12,9 +12,12 @@ namespace Swift { class SoftwareVersionResponder; class XMPPRoster; class XMPPRosterImpl; + class MUCManager; class XMPPRosterController; class PresenceOracle; class PresenceSender; + class DirectedPresenceSender; + class StanzaChannelPresenceSender; class MUCRegistry; class Storages; class MemoryStorages; @@ -23,6 +26,7 @@ namespace Swift { class CapsManager; class EntityCapsManager; class NickResolver; + class SubscriptionManager; /** * Provides the core functionality for writing XMPP client software. @@ -88,8 +92,10 @@ namespace Swift { return presenceOracle; } - PresenceSender* getPresenceSender() const { - return presenceSender; + PresenceSender* getPresenceSender() const; + + MUCManager* getMUCManager() const { + return mucManager; } MUCRegistry* getMUCRegistry() const { @@ -112,15 +118,17 @@ namespace Swift { return nickResolver; } + SubscriptionManager* getSubscriptionManager() const { + return subscriptionManager; + } + public: /** * This signal is emitted when a JID changes presence. */ boost::signal onPresenceChange; - /** - * This signal is emitted when a presence subscription request is received. - */ + boost::signal onPresenceSubscriptionRequest; private: @@ -133,12 +141,15 @@ namespace Swift { XMPPRosterImpl* roster; XMPPRosterController* rosterController; PresenceOracle* presenceOracle; - PresenceSender* presenceSender; + DirectedPresenceSender* directedPresenceSender; + StanzaChannelPresenceSender* stanzaChannelPresenceSender; MUCRegistry* mucRegistry; VCardManager* vcardManager; AvatarManager* avatarManager; CapsManager* capsManager; EntityCapsManager* entityCapsManager; NickResolver* nickResolver; + SubscriptionManager* subscriptionManager; + MUCManager* mucManager; }; } diff --git a/Swiften/MUC/MUC.cpp b/Swiften/MUC/MUC.cpp index cfd468c..9f7c500 100644 --- a/Swiften/MUC/MUC.cpp +++ b/Swiften/MUC/MUC.cpp @@ -9,7 +9,7 @@ #include #include -#include "Swiften/Presence/PresenceSender.h" +#include "Swiften/Presence/DirectedPresenceSender.h" #include "Swiften/Client/StanzaChannel.h" #include "Swiften/Queries/IQRouter.h" #include "Swiften/Elements/Form.h" @@ -17,13 +17,15 @@ #include "Swiften/Elements/MUCUserPayload.h" #include "Swiften/Elements/MUCOwnerPayload.h" #include "Swiften/Elements/MUCPayload.h" +#include "Swiften/MUC/MUCRegistry.h" namespace Swift { typedef std::pair StringMUCOccupantPair; -MUC::MUC(StanzaChannel* stanzaChannel, IQRouter* iqRouter, PresenceSender* presenceSender, const JID &muc) : ownMUCJID(muc), stanzaChannel(stanzaChannel), iqRouter_(iqRouter), presenceSender(presenceSender), muc_(muc) { +MUC::MUC(StanzaChannel* stanzaChannel, IQRouter* iqRouter, DirectedPresenceSender* presenceSender, const JID &muc, MUCRegistry* mucRegistry) : ownMUCJID(muc), stanzaChannel(stanzaChannel), iqRouter_(iqRouter), presenceSender(presenceSender), mucRegistry(mucRegistry) { scopedConnection_ = stanzaChannel->onPresenceReceived.connect(boost::bind(&MUC::handleIncomingPresence, this, _1)); + mucRegistry->addMUC(getJID()); } //FIXME: discover reserved nickname @@ -57,6 +59,7 @@ void MUC::joinWithContextSince(const String &nick) { void MUC::part() { presenceSender->removeDirectedPresenceReceiver(ownMUCJID); + mucRegistry->removeMUC(getJID()); } void MUC::handleUserLeft(LeavingType type) { @@ -157,7 +160,7 @@ void MUC::handleIncomingPresence(boost::shared_ptr presence) { /* Currently deal with this by making an instant room */ boost::shared_ptr mucPayload(new MUCOwnerPayload()); mucPayload->setPayload(boost::shared_ptr(new Form(Form::SubmitType))); - boost::shared_ptr iq(IQ::createRequest(IQ::Set, muc_, iqRouter_->getNewIQID(), mucPayload)); + boost::shared_ptr iq(IQ::createRequest(IQ::Set, getJID(), iqRouter_->getNewIQID(), mucPayload)); iqRouter_->sendIQ(iq); } } diff --git a/Swiften/MUC/MUC.h b/Swiften/MUC/MUC.h index ea20ac4..29dbbe1 100644 --- a/Swiften/MUC/MUC.h +++ b/Swiften/MUC/MUC.h @@ -11,6 +11,7 @@ #include "Swiften/Elements/Message.h" #include "Swiften/Elements/Presence.h" #include "Swiften/MUC/MUCOccupant.h" +#include "Swiften/MUC/MUCRegistry.h" #include #include "Swiften/Base/boost_bsignals.h" @@ -21,15 +22,24 @@ namespace Swift { class StanzaChannel; class IQRouter; - class PresenceSender; + class DirectedPresenceSender; class MUC { public: + typedef boost::shared_ptr ref; + enum JoinResult { JoinSucceeded, JoinFailed }; - enum LeavingType { Part, Disconnect }; + enum LeavingType { Part, Disconnect }; public: - MUC(StanzaChannel* stanzaChannel, IQRouter* iqRouter, PresenceSender* presenceSender, const JID &muc); + MUC(StanzaChannel* stanzaChannel, IQRouter* iqRouter, DirectedPresenceSender* presenceSender, const JID &muc, MUCRegistry* mucRegistry); + + /** + * Returns the (bare) JID of the MUC. + */ + JID getJID() const { + return ownMUCJID.toBare(); + } void joinAs(const String &nick); void joinWithContextSince(const String &nick); @@ -70,8 +80,8 @@ namespace Swift { JID ownMUCJID; StanzaChannel* stanzaChannel; IQRouter* iqRouter_; - PresenceSender* presenceSender; - JID muc_; + DirectedPresenceSender* presenceSender; + MUCRegistry* mucRegistry; std::map occupants; bool joinComplete_; boost::bsignals::scoped_connection scopedConnection_; diff --git a/Swiften/MUC/MUCManager.cpp b/Swiften/MUC/MUCManager.cpp new file mode 100644 index 0000000..8950029 --- /dev/null +++ b/Swiften/MUC/MUCManager.cpp @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include "Swiften/MUC/MUCManager.h" + +namespace Swift { + +MUCManager::MUCManager(StanzaChannel* stanzaChannel, IQRouter* iqRouter, DirectedPresenceSender* presenceSender, MUCRegistry* mucRegistry) : stanzaChannel(stanzaChannel), iqRouter(iqRouter), presenceSender(presenceSender), mucRegistry(mucRegistry) { +} + +MUC::ref MUCManager::createMUC(const JID& jid) { + return MUC::ref(new MUC(stanzaChannel, iqRouter, presenceSender, jid, mucRegistry)); +} + +} diff --git a/Swiften/MUC/MUCManager.h b/Swiften/MUC/MUCManager.h new file mode 100644 index 0000000..0efdf9a --- /dev/null +++ b/Swiften/MUC/MUCManager.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include "Swiften/MUC/MUC.h" + +namespace Swift { + class IQRouter; + class StanzaChannel; + class DirectedPresenceSender; + class MUCRegistry; + + class MUCManager { + public: + MUCManager(StanzaChannel* stanzaChannel, IQRouter* iqRouter, DirectedPresenceSender* presenceSender, MUCRegistry* mucRegistry); + + MUC::ref createMUC(const JID&); + + private: + StanzaChannel* stanzaChannel; + IQRouter* iqRouter; + DirectedPresenceSender* presenceSender; + MUCRegistry* mucRegistry; + }; +} diff --git a/Swiften/Presence/DirectedPresenceSender.cpp b/Swiften/Presence/DirectedPresenceSender.cpp new file mode 100644 index 0000000..aade6cf --- /dev/null +++ b/Swiften/Presence/DirectedPresenceSender.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include "Swiften/Presence/DirectedPresenceSender.h" +#include "Swiften/Base/foreach.h" + +namespace Swift { + +DirectedPresenceSender::DirectedPresenceSender(PresenceSender* sender) : sender(sender) { +} + +void DirectedPresenceSender::sendPresence(boost::shared_ptr presence) { + if (!sender->isAvailable()) { + return; + } + + sender->sendPresence(presence); + + if (!presence->getTo().isValid()) { + boost::shared_ptr presenceCopy(new Presence(*presence)); + foreach(const JID& jid, directedPresenceReceivers) { + presenceCopy->setTo(jid); + sender->sendPresence(presenceCopy); + } + + lastSentUndirectedPresence = presence; + } +} + +/** + * Gets either the last broadcast presence, or an empty stanza if none has been sent. + */ +boost::shared_ptr DirectedPresenceSender::getLastSentUndirectedPresence() { + boost::shared_ptr presenceCopy(lastSentUndirectedPresence ? new Presence(*lastSentUndirectedPresence) : new Presence()); + return presenceCopy; +} + +void DirectedPresenceSender::addDirectedPresenceReceiver(const JID& jid) { + directedPresenceReceivers.insert(jid); + if (sender->isAvailable()) { + if (lastSentUndirectedPresence && lastSentUndirectedPresence->getType() == Presence::Available) { + boost::shared_ptr presenceCopy(new Presence(*lastSentUndirectedPresence)); + presenceCopy->setTo(jid); + sender->sendPresence(presenceCopy); + } + } +} + +void DirectedPresenceSender::removeDirectedPresenceReceiver(const JID& jid) { + directedPresenceReceivers.erase(jid); + if (sender->isAvailable()) { + boost::shared_ptr presence(new Presence()); + presence->setType(Presence::Unavailable); + presence->setTo(jid); + sender->sendPresence(presence); + } +} + +bool DirectedPresenceSender::isAvailable() const { + return sender->isAvailable(); +} + +} diff --git a/Swiften/Presence/DirectedPresenceSender.h b/Swiften/Presence/DirectedPresenceSender.h new file mode 100644 index 0000000..b63a50e --- /dev/null +++ b/Swiften/Presence/DirectedPresenceSender.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include + +#include "Swiften/Elements/Presence.h" +#include "Swiften/Presence/PresenceSender.h" + +namespace Swift { + class DirectedPresenceSender : public PresenceSender { + public: + DirectedPresenceSender(PresenceSender*); + + void addDirectedPresenceReceiver(const JID&); + void removeDirectedPresenceReceiver(const JID&); + + void sendPresence(Presence::ref); + + Presence::ref getLastSentUndirectedPresence(); + + bool isAvailable() const; + + private: + Presence::ref lastSentUndirectedPresence; + PresenceSender* sender; + std::set directedPresenceReceivers; + }; +} diff --git a/Swiften/Presence/PresenceOracle.cpp b/Swiften/Presence/PresenceOracle.cpp index fb4be3f..387ad42 100644 --- a/Swiften/Presence/PresenceOracle.cpp +++ b/Swiften/Presence/PresenceOracle.cpp @@ -33,12 +33,11 @@ void PresenceOracle::handleStanzaChannelAvailableChanged(bool available) { void PresenceOracle::handleIncomingPresence(Presence::ref presence) { JID bareJID(presence->getFrom().toBare()); if (presence->getType() == Presence::Subscribe) { - onPresenceSubscriptionRequest(bareJID, presence->getStatus()); - } else { + } + else { Presence::ref passedPresence = presence; if (presence->getType() == Presence::Unsubscribe) { /* 3921bis says that we don't follow up with an unavailable, so simulate this ourselves */ - onPresenceSubscriptionRevoked(bareJID, presence->getStatus()); passedPresence = Presence::ref(new Presence()); passedPresence->setType(Presence::Unavailable); passedPresence->setFrom(bareJID); diff --git a/Swiften/Presence/PresenceOracle.h b/Swiften/Presence/PresenceOracle.h index f30d05d..e846984 100644 --- a/Swiften/Presence/PresenceOracle.h +++ b/Swiften/Presence/PresenceOracle.h @@ -25,8 +25,6 @@ class StanzaChannel; public: boost::signal onPresenceChange; - boost::signal onPresenceSubscriptionRequest; - boost::signal onPresenceSubscriptionRevoked; private: void handleIncomingPresence(Presence::ref presence); diff --git a/Swiften/Presence/PresenceSender.cpp b/Swiften/Presence/PresenceSender.cpp index 6df02b8..50d75eb 100644 --- a/Swiften/Presence/PresenceSender.cpp +++ b/Swiften/Presence/PresenceSender.cpp @@ -5,81 +5,10 @@ */ #include "Swiften/Presence/PresenceSender.h" -#include "Swiften/Base/foreach.h" -#include "Swiften/Client/StanzaChannel.h" namespace Swift { -PresenceSender::PresenceSender(StanzaChannel* channel) : channel(channel) { -} - -void PresenceSender::sendPresence(boost::shared_ptr presence) { - if (!channel->isAvailable()) { - return; - } - - channel->sendPresence(presence); - - if (!presence->getTo().isValid()) { - boost::shared_ptr presenceCopy(new Presence(*presence)); - foreach(const JID& jid, directedPresenceReceivers) { - presenceCopy->setTo(jid); - channel->sendPresence(presenceCopy); - } - - lastSentUndirectedPresence = presence; - } -} - -/** - * Gets either the last broadcast presence, or an empty stanza if none has been sent. - */ -boost::shared_ptr PresenceSender::getLastSentUndirectedPresence() { - boost::shared_ptr presenceCopy(lastSentUndirectedPresence ? new Presence(*lastSentUndirectedPresence) : new Presence()); - return presenceCopy; -} - -void PresenceSender::addDirectedPresenceReceiver(const JID& jid) { - directedPresenceReceivers.insert(jid); - if (channel->isAvailable()) { - if (lastSentUndirectedPresence && lastSentUndirectedPresence->getType() == Presence::Available) { - boost::shared_ptr presenceCopy(new Presence(*lastSentUndirectedPresence)); - presenceCopy->setTo(jid); - channel->sendPresence(presenceCopy); - } - } -} - -void PresenceSender::removeDirectedPresenceReceiver(const JID& jid) { - directedPresenceReceivers.erase(jid); - if (channel->isAvailable()) { - boost::shared_ptr presence(new Presence()); - presence->setType(Presence::Unavailable); - presence->setTo(jid); - channel->sendPresence(presence); - } -} - -void PresenceSender::cancelSubscription(const JID& jid) { - boost::shared_ptr stanza(new Presence()); - stanza->setType(Presence::Unsubscribed); - stanza->setTo(jid); - channel->sendPresence(stanza); -} - -void PresenceSender::confirmSubscription(const JID& jid) { - boost::shared_ptr stanza(new Presence()); - stanza->setType(Presence::Subscribed); - stanza->setTo(jid); - channel->sendPresence(stanza); -} - - -void PresenceSender::requestSubscription(const JID& jid) { - boost::shared_ptr stanza(new Presence()); - stanza->setType(Presence::Subscribe); - stanza->setTo(jid); - channel->sendPresence(stanza); +PresenceSender::~PresenceSender() { } } diff --git a/Swiften/Presence/PresenceSender.h b/Swiften/Presence/PresenceSender.h index 3336523..5abf2f3 100644 --- a/Swiften/Presence/PresenceSender.h +++ b/Swiften/Presence/PresenceSender.h @@ -6,31 +6,15 @@ #pragma once -#include - #include "Swiften/Elements/Presence.h" namespace Swift { - class StanzaChannel; - class PresenceSender { public: - PresenceSender(StanzaChannel*); - - void addDirectedPresenceReceiver(const JID&); - void removeDirectedPresenceReceiver(const JID&); - - void sendPresence(boost::shared_ptr); - - void cancelSubscription(const JID& jid); - void confirmSubscription(const JID& jid); - void requestSubscription(const JID& jid); + virtual ~PresenceSender(); - boost::shared_ptr getLastSentUndirectedPresence(); + virtual void sendPresence(Presence::ref) = 0; - private: - boost::shared_ptr lastSentUndirectedPresence; - StanzaChannel* channel; - std::set directedPresenceReceivers; + virtual bool isAvailable() const = 0; }; } diff --git a/Swiften/Presence/StanzaChannelPresenceSender.cpp b/Swiften/Presence/StanzaChannelPresenceSender.cpp new file mode 100644 index 0000000..654b7e7 --- /dev/null +++ b/Swiften/Presence/StanzaChannelPresenceSender.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include "Swiften/Presence/StanzaChannelPresenceSender.h" +#include "Swiften/Client/StanzaChannel.h" + +namespace Swift { + +StanzaChannelPresenceSender::StanzaChannelPresenceSender(StanzaChannel* channel) : channel(channel) { +} + +void StanzaChannelPresenceSender::sendPresence(Presence::ref presence) { + channel->sendPresence(presence); +} + +bool StanzaChannelPresenceSender::isAvailable() const { + return channel->isAvailable(); +} + +} diff --git a/Swiften/Presence/StanzaChannelPresenceSender.h b/Swiften/Presence/StanzaChannelPresenceSender.h new file mode 100644 index 0000000..23230ab --- /dev/null +++ b/Swiften/Presence/StanzaChannelPresenceSender.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include "Swiften/Presence/PresenceSender.h" + +namespace Swift { + class StanzaChannel; + + class StanzaChannelPresenceSender : public PresenceSender { + public: + StanzaChannelPresenceSender(StanzaChannel*); + + void sendPresence(Presence::ref); + + bool isAvailable() const; + + private: + StanzaChannel* channel; + }; +} diff --git a/Swiften/Presence/SubscriptionManager.cpp b/Swiften/Presence/SubscriptionManager.cpp new file mode 100644 index 0000000..12534dc --- /dev/null +++ b/Swiften/Presence/SubscriptionManager.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include "Swiften/Presence/SubscriptionManager.h" + +#include + +#include "Swiften/Base/foreach.h" +#include "Swiften/Client/StanzaChannel.h" + +namespace Swift { + +SubscriptionManager::SubscriptionManager(StanzaChannel* channel) : stanzaChannel(channel) { + stanzaChannel->onPresenceReceived.connect(boost::bind(&SubscriptionManager::handleIncomingPresence, this, _1)); +} + +SubscriptionManager::~SubscriptionManager() { + stanzaChannel->onPresenceReceived.disconnect(boost::bind(&SubscriptionManager::handleIncomingPresence, this, _1)); +} + +void SubscriptionManager::cancelSubscription(const JID& jid) { + Presence::ref stanza(new Presence()); + stanza->setType(Presence::Unsubscribed); + stanza->setTo(jid); + stanzaChannel->sendPresence(stanza); +} + +void SubscriptionManager::confirmSubscription(const JID& jid) { + Presence::ref stanza(new Presence()); + stanza->setType(Presence::Subscribed); + stanza->setTo(jid); + stanzaChannel->sendPresence(stanza); +} + + +void SubscriptionManager::requestSubscription(const JID& jid) { + Presence::ref stanza(new Presence()); + stanza->setType(Presence::Subscribe); + stanza->setTo(jid); + stanzaChannel->sendPresence(stanza); +} + +void SubscriptionManager::handleIncomingPresence(Presence::ref presence) { + JID bareJID(presence->getFrom().toBare()); + if (presence->getType() == Presence::Subscribe) { + onPresenceSubscriptionRequest(bareJID, presence->getStatus()); + } + else if (presence->getType() == Presence::Unsubscribe) { + onPresenceSubscriptionRevoked(bareJID, presence->getStatus()); + } +} + + +} diff --git a/Swiften/Presence/SubscriptionManager.h b/Swiften/Presence/SubscriptionManager.h new file mode 100644 index 0000000..477a2fd --- /dev/null +++ b/Swiften/Presence/SubscriptionManager.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include + +#include "Swiften/Base/String.h" +#include "Swiften/JID/JID.h" +#include "Swiften/Base/boost_bsignals.h" +#include "Swiften/Elements/Presence.h" + +namespace Swift { + class StanzaChannel; + + class SubscriptionManager { + public: + SubscriptionManager(StanzaChannel* stanzaChannel); + ~SubscriptionManager(); + + void cancelSubscription(const JID& jid); + void confirmSubscription(const JID& jid); + void requestSubscription(const JID& jid); + + /** + * This signal is emitted when a presence subscription request is received. + */ + boost::signal onPresenceSubscriptionRequest; + + boost::signal onPresenceSubscriptionRevoked; + + private: + void handleIncomingPresence(Presence::ref presence); + + private: + StanzaChannel* stanzaChannel; + }; +} diff --git a/Swiften/Presence/UnitTest/DirectedPresenceSenderTest.cpp b/Swiften/Presence/UnitTest/DirectedPresenceSenderTest.cpp new file mode 100644 index 0000000..a60c429 --- /dev/null +++ b/Swiften/Presence/UnitTest/DirectedPresenceSenderTest.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include +#include + +#include "Swiften/Client/DummyStanzaChannel.h" +#include "Swiften/Presence/DirectedPresenceSender.h" +#include "Swiften/Presence/StanzaChannelPresenceSender.h" + +using namespace Swift; + +class DirectedPresenceSenderTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(DirectedPresenceSenderTest); + CPPUNIT_TEST(testSendPresence); + CPPUNIT_TEST(testSendPresence_UndirectedPresenceWithDirectedPresenceReceivers); + CPPUNIT_TEST(testSendPresence_DirectedPresenceWithDirectedPresenceReceivers); + CPPUNIT_TEST(testAddDirectedPresenceReceiver); + CPPUNIT_TEST(testAddDirectedPresenceReceiver_AfterSendingDirectedPresence); + CPPUNIT_TEST(testRemoveDirectedPresenceReceiver); + CPPUNIT_TEST_SUITE_END(); + + public: + void setUp() { + channel = new DummyStanzaChannel(); + testPresence = boost::shared_ptr(new Presence()); + testPresence->setStatus("Foo"); + secondTestPresence = boost::shared_ptr(new Presence()); + secondTestPresence->setStatus("Bar"); + stanzaChannelPresenceSender = new StanzaChannelPresenceSender(channel); + } + + void tearDown() { + delete stanzaChannelPresenceSender; + delete channel; + } + + void testSendPresence() { + std::auto_ptr testling(createPresenceSender()); + testling->sendPresence(testPresence); + + CPPUNIT_ASSERT_EQUAL(1, static_cast(channel->sentStanzas.size())); + boost::shared_ptr presence = boost::dynamic_pointer_cast(channel->sentStanzas[0]); + CPPUNIT_ASSERT(testPresence == presence); + } + + void testSendPresence_UndirectedPresenceWithDirectedPresenceReceivers() { + std::auto_ptr testling(createPresenceSender()); + testling->addDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty")); + + testling->sendPresence(testPresence); + + CPPUNIT_ASSERT_EQUAL(2, static_cast(channel->sentStanzas.size())); + boost::shared_ptr presence = boost::dynamic_pointer_cast(channel->sentStanzas[0]); + CPPUNIT_ASSERT(testPresence == presence); + presence = boost::dynamic_pointer_cast(channel->sentStanzas[1]); + CPPUNIT_ASSERT_EQUAL(testPresence->getStatus(), presence->getStatus()); + CPPUNIT_ASSERT_EQUAL(JID("alice@wonderland.lit/teaparty"), presence->getTo()); + } + + void testSendPresence_DirectedPresenceWithDirectedPresenceReceivers() { + std::auto_ptr testling(createPresenceSender()); + testling->addDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty")); + channel->sentStanzas.clear(); + + testPresence->setTo(JID("foo@bar.com")); + testling->sendPresence(testPresence); + + CPPUNIT_ASSERT_EQUAL(1, static_cast(channel->sentStanzas.size())); + boost::shared_ptr presence = boost::dynamic_pointer_cast(channel->sentStanzas[0]); + CPPUNIT_ASSERT(testPresence == presence); + } + + void testAddDirectedPresenceReceiver() { + std::auto_ptr testling(createPresenceSender()); + testling->sendPresence(testPresence); + channel->sentStanzas.clear(); + + testling->addDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty")); + + CPPUNIT_ASSERT_EQUAL(1, static_cast(channel->sentStanzas.size())); + boost::shared_ptr presence = boost::dynamic_pointer_cast(channel->sentStanzas[0]); + CPPUNIT_ASSERT_EQUAL(testPresence->getStatus(), presence->getStatus()); + CPPUNIT_ASSERT_EQUAL(JID("alice@wonderland.lit/teaparty"), presence->getTo()); + } + + void testAddDirectedPresenceReceiver_AfterSendingDirectedPresence() { + std::auto_ptr testling(createPresenceSender()); + testling->sendPresence(testPresence); + secondTestPresence->setTo(JID("foo@bar.com")); + testling->sendPresence(secondTestPresence); + channel->sentStanzas.clear(); + + testling->addDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty")); + + CPPUNIT_ASSERT_EQUAL(1, static_cast(channel->sentStanzas.size())); + boost::shared_ptr presence = boost::dynamic_pointer_cast(channel->sentStanzas[0]); + CPPUNIT_ASSERT_EQUAL(testPresence->getStatus(), presence->getStatus()); + CPPUNIT_ASSERT_EQUAL(JID("alice@wonderland.lit/teaparty"), presence->getTo()); + } + + void testRemoveDirectedPresenceReceiver() { + std::auto_ptr testling(createPresenceSender()); + testling->addDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty")); + channel->sentStanzas.clear(); + + testling->removeDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty")); + testling->sendPresence(testPresence); + + CPPUNIT_ASSERT_EQUAL(2, static_cast(channel->sentStanzas.size())); + CPPUNIT_ASSERT_EQUAL(boost::dynamic_pointer_cast(channel->sentStanzas[0])->getType(), Presence::Unavailable); + CPPUNIT_ASSERT(channel->sentStanzas[1] == testPresence); + } + + private: + DirectedPresenceSender* createPresenceSender() { + return new DirectedPresenceSender(stanzaChannelPresenceSender); + } + + private: + DummyStanzaChannel* channel; + StanzaChannelPresenceSender* stanzaChannelPresenceSender; + boost::shared_ptr testPresence; + boost::shared_ptr secondTestPresence; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(DirectedPresenceSenderTest); diff --git a/Swiften/Presence/UnitTest/PresenceOracleTest.cpp b/Swiften/Presence/UnitTest/PresenceOracleTest.cpp index d3b4b20..aa450a2 100644 --- a/Swiften/Presence/UnitTest/PresenceOracleTest.cpp +++ b/Swiften/Presence/UnitTest/PresenceOracleTest.cpp @@ -11,6 +11,7 @@ #include "Swiften/Presence/PresenceOracle.h" #include "Swiften/Client/DummyStanzaChannel.h" +#include "Swiften/Presence/SubscriptionManager.h" using namespace Swift; @@ -31,13 +32,15 @@ class PresenceOracleTest : public CppUnit::TestFixture { stanzaChannel_ = new DummyStanzaChannel(); oracle_ = new PresenceOracle(stanzaChannel_); oracle_->onPresenceChange.connect(boost::bind(&PresenceOracleTest::handlePresenceChange, this, _1)); - oracle_->onPresenceSubscriptionRequest.connect(boost::bind(&PresenceOracleTest::handlePresenceSubscriptionRequest, this, _1, _2)); + subscriptionManager_ = new SubscriptionManager(stanzaChannel_); + subscriptionManager_->onPresenceSubscriptionRequest.connect(boost::bind(&PresenceOracleTest::handlePresenceSubscriptionRequest, this, _1, _2)); user1 = JID("user1@foo.com/Foo"); user1alt = JID("user1@foo.com/Bar"); user2 = JID("user2@bar.com/Bar"); } void tearDown() { + delete subscriptionManager_; delete oracle_; delete stanzaChannel_; } @@ -181,6 +184,7 @@ class PresenceOracleTest : public CppUnit::TestFixture { String reason; }; PresenceOracle* oracle_; + SubscriptionManager* subscriptionManager_; DummyStanzaChannel* stanzaChannel_; std::vector changes; std::vector subscriptionRequests; diff --git a/Swiften/Presence/UnitTest/PresenceSenderTest.cpp b/Swiften/Presence/UnitTest/PresenceSenderTest.cpp deleted file mode 100644 index 737f317..0000000 --- a/Swiften/Presence/UnitTest/PresenceSenderTest.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include -#include - -#include "Swiften/Client/DummyStanzaChannel.h" -#include "Swiften/Presence/PresenceSender.h" - -using namespace Swift; - -class PresenceSenderTest : public CppUnit::TestFixture { - CPPUNIT_TEST_SUITE(PresenceSenderTest); - CPPUNIT_TEST(testSendPresence); - CPPUNIT_TEST(testSendPresence_UndirectedPresenceWithDirectedPresenceReceivers); - CPPUNIT_TEST(testSendPresence_DirectedPresenceWithDirectedPresenceReceivers); - CPPUNIT_TEST(testAddDirectedPresenceReceiver); - CPPUNIT_TEST(testAddDirectedPresenceReceiver_AfterSendingDirectedPresence); - CPPUNIT_TEST(testRemoveDirectedPresenceReceiver); - CPPUNIT_TEST_SUITE_END(); - - public: - void setUp() { - channel = new DummyStanzaChannel(); - testPresence = boost::shared_ptr(new Presence()); - testPresence->setStatus("Foo"); - secondTestPresence = boost::shared_ptr(new Presence()); - secondTestPresence->setStatus("Bar"); - } - - void tearDown() { - delete channel; - } - - void testSendPresence() { - std::auto_ptr testling(createPresenceSender()); - testling->sendPresence(testPresence); - - CPPUNIT_ASSERT_EQUAL(1, static_cast(channel->sentStanzas.size())); - boost::shared_ptr presence = boost::dynamic_pointer_cast(channel->sentStanzas[0]); - CPPUNIT_ASSERT(testPresence == presence); - } - - void testSendPresence_UndirectedPresenceWithDirectedPresenceReceivers() { - std::auto_ptr testling(createPresenceSender()); - testling->addDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty")); - - testling->sendPresence(testPresence); - - CPPUNIT_ASSERT_EQUAL(2, static_cast(channel->sentStanzas.size())); - boost::shared_ptr presence = boost::dynamic_pointer_cast(channel->sentStanzas[0]); - CPPUNIT_ASSERT(testPresence == presence); - presence = boost::dynamic_pointer_cast(channel->sentStanzas[1]); - CPPUNIT_ASSERT_EQUAL(testPresence->getStatus(), presence->getStatus()); - CPPUNIT_ASSERT_EQUAL(JID("alice@wonderland.lit/teaparty"), presence->getTo()); - } - - void testSendPresence_DirectedPresenceWithDirectedPresenceReceivers() { - std::auto_ptr testling(createPresenceSender()); - testling->addDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty")); - channel->sentStanzas.clear(); - - testPresence->setTo(JID("foo@bar.com")); - testling->sendPresence(testPresence); - - CPPUNIT_ASSERT_EQUAL(1, static_cast(channel->sentStanzas.size())); - boost::shared_ptr presence = boost::dynamic_pointer_cast(channel->sentStanzas[0]); - CPPUNIT_ASSERT(testPresence == presence); - } - - void testAddDirectedPresenceReceiver() { - std::auto_ptr testling(createPresenceSender()); - testling->sendPresence(testPresence); - channel->sentStanzas.clear(); - - testling->addDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty")); - - CPPUNIT_ASSERT_EQUAL(1, static_cast(channel->sentStanzas.size())); - boost::shared_ptr presence = boost::dynamic_pointer_cast(channel->sentStanzas[0]); - CPPUNIT_ASSERT_EQUAL(testPresence->getStatus(), presence->getStatus()); - CPPUNIT_ASSERT_EQUAL(JID("alice@wonderland.lit/teaparty"), presence->getTo()); - } - - void testAddDirectedPresenceReceiver_AfterSendingDirectedPresence() { - std::auto_ptr testling(createPresenceSender()); - testling->sendPresence(testPresence); - secondTestPresence->setTo(JID("foo@bar.com")); - testling->sendPresence(secondTestPresence); - channel->sentStanzas.clear(); - - testling->addDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty")); - - CPPUNIT_ASSERT_EQUAL(1, static_cast(channel->sentStanzas.size())); - boost::shared_ptr presence = boost::dynamic_pointer_cast(channel->sentStanzas[0]); - CPPUNIT_ASSERT_EQUAL(testPresence->getStatus(), presence->getStatus()); - CPPUNIT_ASSERT_EQUAL(JID("alice@wonderland.lit/teaparty"), presence->getTo()); - } - - void testRemoveDirectedPresenceReceiver() { - std::auto_ptr testling(createPresenceSender()); - testling->addDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty")); - channel->sentStanzas.clear(); - - testling->removeDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty")); - testling->sendPresence(testPresence); - - CPPUNIT_ASSERT_EQUAL(2, static_cast(channel->sentStanzas.size())); - CPPUNIT_ASSERT_EQUAL(boost::dynamic_pointer_cast(channel->sentStanzas[0])->getType(), Presence::Unavailable); - CPPUNIT_ASSERT(channel->sentStanzas[1] == testPresence); - } - - private: - PresenceSender* createPresenceSender() { - return new PresenceSender(channel); - } - - private: - DummyStanzaChannel* channel; - boost::shared_ptr testPresence; - boost::shared_ptr secondTestPresence; -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(PresenceSenderTest); diff --git a/Swiften/SConscript b/Swiften/SConscript index 886051f..5790672 100644 --- a/Swiften/SConscript +++ b/Swiften/SConscript @@ -47,11 +47,15 @@ if env["SCONS_STAGE"] == "build" : "Elements/Stanza.cpp", "Elements/VCard.cpp", "MUC/MUC.cpp", + "MUC/MUCManager.cpp", "MUC/MUCOccupant.cpp", "MUC/MUCRegistry.cpp", "MUC/MUCBookmarkManager.cpp", "Presence/PresenceOracle.cpp", "Presence/PresenceSender.cpp", + "Presence/DirectedPresenceSender.cpp", + "Presence/StanzaChannelPresenceSender.cpp", + "Presence/SubscriptionManager.cpp", "Queries/IQChannel.cpp", "Queries/IQHandler.cpp", "Queries/IQRouter.cpp", @@ -218,7 +222,7 @@ if env["SCONS_STAGE"] == "build" : File("Parser/UnitTest/XMLParserTest.cpp"), File("Parser/UnitTest/XMPPParserTest.cpp"), File("Presence/UnitTest/PresenceOracleTest.cpp"), - File("Presence/UnitTest/PresenceSenderTest.cpp"), + File("Presence/UnitTest/DirectedPresenceSenderTest.cpp"), File("Queries/Requests/UnitTest/GetPrivateStorageRequestTest.cpp"), File("Disco/UnitTest/DiscoInfoResponderTest.cpp"), File("Queries/UnitTest/IQRouterTest.cpp"), -- cgit v0.10.2-6-g49f6