diff options
30 files changed, 267 insertions, 101 deletions
| diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp index 5009588..250f02d 100644 --- a/Swift/Controllers/Chat/ChatsManager.cpp +++ b/Swift/Controllers/Chat/ChatsManager.cpp @@ -7,6 +7,7 @@  #include "Swift/Controllers/Chat/ChatController.h"  #include "Swift/Controllers/EventController.h"  #include "Swift/Controllers/Chat/MUCController.h" +#include "Swift/Controllers/UIEvents/RequestChatUIEvent.h"  #include "Swiften/Presence/PresenceSender.h"  #include "Swiften/Elements/ChatState.h" @@ -15,7 +16,7 @@ namespace Swift {  typedef std::pair<JID, ChatController*> JIDChatControllerPair;  typedef std::pair<JID, MUCController*> JIDMUCControllerPair; -ChatsManager::ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, TreeWidgetFactory* treeWidgetFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, boost::shared_ptr<DiscoInfo> serverDiscoInfo, PresenceSender* presenceSender) : jid_(jid) { +ChatsManager::ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, TreeWidgetFactory* treeWidgetFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, boost::shared_ptr<DiscoInfo> serverDiscoInfo, PresenceSender* presenceSender, UIEventStream* uiEventStream) : jid_(jid) {  	eventController_ = eventController;  	stanzaChannel_ = stanzaChannel;  	iqRouter_ = iqRouter; @@ -26,7 +27,9 @@ ChatsManager::ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRo  	avatarManager_ = NULL;  	serverDiscoInfo_ = serverDiscoInfo;  	presenceSender_ = presenceSender; +	uiEventStream_ = uiEventStream;  	presenceOracle_->onPresenceChange.connect(boost::bind(&ChatsManager::handlePresenceChange, this, _1, _2)); +	uiEventStream_->onUIEvent.connect(boost::bind(&ChatsManager::handleUIEvent, this, _1));  }  ChatsManager::~ChatsManager() { @@ -39,6 +42,13 @@ ChatsManager::~ChatsManager() {  } +void ChatsManager::handleUIEvent(boost::shared_ptr<UIEvent> event) { +	boost::shared_ptr<RequestChatUIEvent> chatEvent = boost::dynamic_pointer_cast<RequestChatUIEvent>(event); +	if (chatEvent) { +		handleChatRequest(chatEvent->getContact()); +	} +} +  /**   * If a resource goes offline, release bound chatdialog to that resource.   */ diff --git a/Swift/Controllers/Chat/ChatsManager.h b/Swift/Controllers/Chat/ChatsManager.h index dd80d95..04d9330 100644 --- a/Swift/Controllers/Chat/ChatsManager.h +++ b/Swift/Controllers/Chat/ChatsManager.h @@ -10,6 +10,7 @@  #include "Swiften/Elements/Presence.h"  #include "Swiften/JID/JID.h"  #include "Swiften/MUC/MUCRegistry.h" +#include "Swift/Controllers/UIEvents/UIEventStream.h"  namespace Swift {  	class EventController; @@ -23,9 +24,10 @@ namespace Swift {  	class StanzaChannel;  	class IQRouter;  	class PresenceSender; +  	class ChatsManager : public MUCRegistry {  		public: -			ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, TreeWidgetFactory* treeWidgetFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, boost::shared_ptr<DiscoInfo> serverDiscoInfo, PresenceSender* presenceSender); +			ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, TreeWidgetFactory* treeWidgetFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, boost::shared_ptr<DiscoInfo> serverDiscoInfo, PresenceSender* presenceSender, UIEventStream* uiEventStream);  			~ChatsManager();  			void setAvatarManager(AvatarManager* avatarManager);  			void setEnabled(bool enabled); @@ -36,6 +38,7 @@ namespace Swift {  		private:  			void rebindControllerJID(const JID& from, const JID& to);  			void handlePresenceChange(boost::shared_ptr<Presence> newPresence, boost::shared_ptr<Presence> lastPresence); +			void handleUIEvent(boost::shared_ptr<UIEvent> event);  			ChatController* getChatController(const JID &contact);  			virtual bool isMUC(const JID& muc) const; @@ -51,6 +54,7 @@ namespace Swift {  			PresenceOracle* presenceOracle_;  			AvatarManager* avatarManager_;  			PresenceSender* presenceSender_; +			UIEventStream* uiEventStream_;  			boost::shared_ptr<DiscoInfo> serverDiscoInfo_;  	};  } diff --git a/Swift/Controllers/EventController.cpp b/Swift/Controllers/EventController.cpp index 3849aa7..71ccaeb 100644 --- a/Swift/Controllers/EventController.cpp +++ b/Swift/Controllers/EventController.cpp @@ -3,23 +3,26 @@  #include <boost/bind.hpp>  #include <algorithm> +#include "Swiften/Events/MessageEvent.h" +#include "Swiften/Events/SubscriptionRequestEvent.h"  namespace Swift {  EventController::EventController() {  } -void EventController::handleIncomingEvent(boost::shared_ptr<Event> sourceEvent) { +void EventController::handleIncomingEvent(boost::shared_ptr<StanzaEvent> sourceEvent) {  	boost::shared_ptr<MessageEvent> messageEvent = boost::dynamic_pointer_cast<MessageEvent>(sourceEvent); -	if (messageEvent && messageEvent->isReadable()) { +	boost::shared_ptr<SubscriptionRequestEvent> subscriptionEvent = boost::dynamic_pointer_cast<SubscriptionRequestEvent>(sourceEvent); +	if ((messageEvent && messageEvent->isReadable()) || subscriptionEvent) {  		events_.push_back(sourceEvent); -		messageEvent->onConclusion.connect(boost::bind(&EventController::handleEventConcluded, this, messageEvent)); +		sourceEvent->onConclusion.connect(boost::bind(&EventController::handleEventConcluded, this, sourceEvent));  		onEventQueueLengthChange(events_.size());  		onEventQueueEventAdded(sourceEvent);  	}  } -void EventController::handleEventConcluded(boost::shared_ptr<Event> event) { +void EventController::handleEventConcluded(boost::shared_ptr<StanzaEvent> event) {  	events_.erase(std::remove(events_.begin(), events_.end(), event), events_.end());  	onEventQueueLengthChange(events_.size());  } diff --git a/Swift/Controllers/EventController.h b/Swift/Controllers/EventController.h index 482be58..1f4051c 100644 --- a/Swift/Controllers/EventController.h +++ b/Swift/Controllers/EventController.h @@ -6,20 +6,20 @@  #include <boost/shared_ptr.hpp>  #include <vector> -#include "Swiften/Events/Event.h" +#include "Swiften/Events/StanzaEvent.h"  #include "Swiften/Events/MessageEvent.h"  namespace Swift {  	class EventController {  		public:  			EventController(); -			void handleIncomingEvent(boost::shared_ptr<Event> sourceEvent); +			void handleIncomingEvent(boost::shared_ptr<StanzaEvent> sourceEvent);  			boost::signal<void (int)> onEventQueueLengthChange; -			boost::signal<void (boost::shared_ptr<Event>)> onEventQueueEventAdded; +			boost::signal<void (boost::shared_ptr<StanzaEvent>)> onEventQueueEventAdded;  		private: -			void handleEventConcluded(boost::shared_ptr<Event> event); -			std::vector<boost::shared_ptr<Event> > events_; +			void handleEventConcluded(boost::shared_ptr<StanzaEvent> event); +			std::vector<boost::shared_ptr<StanzaEvent> > events_;  	};  }  #endif diff --git a/Swift/Controllers/EventWindowController.cpp b/Swift/Controllers/EventWindowController.cpp index a6611fc..0f91db7 100644 --- a/Swift/Controllers/EventWindowController.cpp +++ b/Swift/Controllers/EventWindowController.cpp @@ -15,12 +15,13 @@ EventWindowController::~EventWindowController() {  	delete window_;  } -void EventWindowController::handleEventQueueEventAdded(boost::shared_ptr<Event> event) { +void EventWindowController::handleEventQueueEventAdded(boost::shared_ptr<StanzaEvent> event) {  	event->onConclusion.connect(boost::bind(&EventWindowController::handleEventConcluded, this, event)); +	fprintf(stderr, "Adding to ewc\n");  	window_->addEvent(event, true);  } -void EventWindowController::handleEventConcluded(boost::shared_ptr<Event> event) { +void EventWindowController::handleEventConcluded(boost::shared_ptr<StanzaEvent> event) {  	window_->removeEvent(event);  	window_->addEvent(event, false);  } diff --git a/Swift/Controllers/EventWindowController.h b/Swift/Controllers/EventWindowController.h index c612265..7c58be1 100644 --- a/Swift/Controllers/EventWindowController.h +++ b/Swift/Controllers/EventWindowController.h @@ -12,8 +12,8 @@ namespace Swift {  			EventWindowController(EventController* eventController, EventWindowFactory* windowFactory);  			~EventWindowController();  		private: -			void handleEventQueueEventAdded(boost::shared_ptr<Event> event); -			void handleEventConcluded(boost::shared_ptr<Event> event); +			void handleEventQueueEventAdded(boost::shared_ptr<StanzaEvent> event); +			void handleEventConcluded(boost::shared_ptr<StanzaEvent> event);  			EventController* eventController_;  			EventWindowFactory* windowFactory_; diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp index d013f5f..310d28f 100644 --- a/Swift/Controllers/MainController.cpp +++ b/Swift/Controllers/MainController.cpp @@ -134,10 +134,8 @@ void MainController::handleConnected() {  		presenceOracle_ = new PresenceOracle(client_);  		nickResolver_ = new NickResolver(xmppRoster_);		  		lastSentPresence_ = boost::shared_ptr<Presence>(); - -		client_->onPresenceReceived.connect(boost::bind(&MainController::handleIncomingPresence, this, _1)); - -		chatsManager_ = new ChatsManager(jid_, client_, client_, eventController_, chatWindowFactory_, treeWidgetFactory_, nickResolver_, presenceOracle_, serverDiscoInfo_, presenceSender_); +		 +		chatsManager_ = new ChatsManager(jid_, client_, client_, eventController_, chatWindowFactory_, treeWidgetFactory_, nickResolver_, presenceOracle_, serverDiscoInfo_, presenceSender_, uiEventStream_);  		client_->onMessageReceived.connect(boost::bind(&ChatsManager::handleIncomingMessage, chatsManager_, _1));  		avatarManager_ = new AvatarManager(client_, client_, avatarStorage_, chatsManager_); @@ -145,7 +143,7 @@ void MainController::handleConnected() {  		chatsManager_->setAvatarManager(avatarManager_); -		rosterController_ = new RosterController(jid_, xmppRoster_, avatarManager_, mainWindowFactory_, treeWidgetFactory_, nickResolver_); +		rosterController_ = new RosterController(jid_, xmppRoster_, avatarManager_, mainWindowFactory_, treeWidgetFactory_, nickResolver_, presenceOracle_, eventController_, uiEventStream_);  		rosterController_->onChangeStatusRequest.connect(boost::bind(&MainController::handleChangeStatusRequest, this, _1, _2));  		rosterController_->onSignOutRequest.connect(boost::bind(&MainController::signOut, this));  				rosterController_->onStartChatRequest.connect(boost::bind(&ChatsManager::handleChatRequest, chatsManager_, _1)); @@ -254,11 +252,6 @@ void MainController::handleInputIdleChanged(bool idle) {  	}  } -void MainController::handleIncomingPresence(boost::shared_ptr<Presence> presence) { -	//FIXME: subscribe, subscribed -	rosterController_->handleIncomingPresence(presence); -} -  void MainController::handleLoginRequest(const String &username, const String &password, const String& certificateFile, bool remember) {  	loginWindow_->setMessage("");  	ProfileSettingsProvider* profileSettings = new ProfileSettingsProvider(username, settings_); diff --git a/Swift/Controllers/MainController.h b/Swift/Controllers/MainController.h index 63be284..387fcb6 100644 --- a/Swift/Controllers/MainController.h +++ b/Swift/Controllers/MainController.h @@ -63,7 +63,6 @@ namespace Swift {  			void handleConnected();  			void handleLoginRequest(const String& username, const String& password, const String& certificateFile, bool remember);  			void handleCancelLoginRequest(); -			void handleIncomingPresence(boost::shared_ptr<Presence> presence);  			void handleChangeStatusRequest(StatusShow::Type show, const String &statusText);  			void handleError(const ClientError& error);  			void handleServerDiscoInfoResponse(boost::shared_ptr<DiscoInfo>, const boost::optional<ErrorPayload>&); diff --git a/Swift/Controllers/MainWindowFactory.h b/Swift/Controllers/MainWindowFactory.h index cf5a061..ce612b3 100644 --- a/Swift/Controllers/MainWindowFactory.h +++ b/Swift/Controllers/MainWindowFactory.h @@ -2,6 +2,7 @@  #define SWIFTEN_MainWindowFactory_H  #include "Swiften/JID/JID.h" +#include "Swift/Controllers/UIEvents/UIEventStream.h"  namespace Swift {  	class MainWindow; @@ -12,7 +13,7 @@ namespace Swift {  			/**  			 * Transfers ownership of result.  			 */ -			virtual MainWindow* createMainWindow() = 0; +			virtual MainWindow* createMainWindow(UIEventStream* eventStream) = 0;  	};  } diff --git a/Swift/Controllers/RosterController.cpp b/Swift/Controllers/RosterController.cpp index df3453d..4c55ea8 100644 --- a/Swift/Controllers/RosterController.cpp +++ b/Swift/Controllers/RosterController.cpp @@ -7,7 +7,9 @@  #include "Swift/Controllers/MainWindowFactory.h"  #include "Swift/Controllers/NickResolver.h"  #include "Swiften/Queries/Requests/GetRosterRequest.h" -#include "Swiften/EventLoop/MainEventLoop.h" +#include "Swiften/Events/SubscriptionRequestEvent.h" +#include "Swiften/Presence/PresenceOracle.h" +#include "Swift/Controllers/EventController.h"  #include "Swiften/Roster/Roster.h"  #include "Swiften/Roster/SetPresence.h"  #include "Swiften/Roster/AppearOffline.h" @@ -23,9 +25,10 @@ namespace Swift {  /**   * The controller does not gain ownership of these parameters.   */ -RosterController::RosterController(const JID& jid, boost::shared_ptr<XMPPRoster> xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, TreeWidgetFactory* treeWidgetFactory, NickResolver* nickResolver) - : myJID_(jid), xmppRoster_(xmppRoster), mainWindowFactory_(mainWindowFactory), treeWidgetFactory_(treeWidgetFactory), mainWindow_(mainWindowFactory_->createMainWindow()), roster_(new Roster(mainWindow_->getTreeWidget(), treeWidgetFactory_)), offlineFilter_(new OfflineRosterFilter()) { -	 +RosterController::RosterController(const JID& jid, boost::shared_ptr<XMPPRoster> xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, TreeWidgetFactory* treeWidgetFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, EventController* eventController, UIEventStream* uiEventStream) + : myJID_(jid), xmppRoster_(xmppRoster), mainWindowFactory_(mainWindowFactory), treeWidgetFactory_(treeWidgetFactory), mainWindow_(mainWindowFactory_->createMainWindow(uiEventStream)), roster_(new Roster(mainWindow_->getTreeWidget(), treeWidgetFactory_)), offlineFilter_(new OfflineRosterFilter()) { +	presenceOracle_ = presenceOracle; +	eventController_ = eventController;  	roster_->addFilter(offlineFilter_);  	mainWindow_->onJoinMUCRequest.connect(boost::bind(&RosterController::handleJoinMUCRequest, this, _1, _2)); @@ -36,6 +39,8 @@ RosterController::RosterController(const JID& jid, boost::shared_ptr<XMPPRoster>  	xmppRoster_->onJIDAdded.connect(boost::bind(&RosterController::handleOnJIDAdded, this, _1));  	xmppRoster_->onJIDUpdated.connect(boost::bind(&RosterController::handleOnJIDUpdated, this, _1, _2, _3));  	xmppRoster_->onJIDRemoved.connect(boost::bind(&RosterController::handleOnJIDRemoved, this, _1)); +	presenceOracle_->onPresenceSubscriptionRequest.connect(boost::bind(&RosterController::handleSubscriptionRequest, this, _1, _2)); +	presenceOracle_->onPresenceChange.connect(boost::bind(&RosterController::handleIncomingPresence, this, _1, _2));  	avatarManager_ = NULL;  	setAvatarManager(avatarManager);  	setNickResolver(nickResolver); @@ -132,8 +137,24 @@ void RosterController::handleOnJIDUpdated(const JID& jid, const String& oldName,  } -void RosterController::handleIncomingPresence(boost::shared_ptr<Presence> presence) { -	roster_->applyOnItems(SetPresence(presence)); +void RosterController::handleIncomingPresence(boost::shared_ptr<Presence> newPresence, boost::shared_ptr<Presence> /*oldPresence*/) { +	roster_->applyOnItems(SetPresence(newPresence)); +} + +void RosterController::handleSubscriptionRequest(const JID& jid, const String& message) { +	SubscriptionRequestEvent* eventPointer = new SubscriptionRequestEvent(jid, message); +	eventPointer->onAccept.connect(boost::bind(&RosterController::handleSubscriptionRequestAccepted, this, eventPointer)); +	eventPointer->onDecline.connect(boost::bind(&RosterController::handleSubscriptionRequestDeclined, this, eventPointer)); +	boost::shared_ptr<StanzaEvent> event(eventPointer); +	eventController_->handleIncomingEvent(event); +} + +void RosterController::handleSubscriptionRequestAccepted(SubscriptionRequestEvent* event) { +		//FIXME: do something +} + +void RosterController::handleSubscriptionRequestDeclined(SubscriptionRequestEvent* event) { +	//FIXME: do something  }  void RosterController::handleAvatarChanged(const JID& jid, const String&) { diff --git a/Swift/Controllers/RosterController.h b/Swift/Controllers/RosterController.h index f3d96e1..cef0e48 100644 --- a/Swift/Controllers/RosterController.h +++ b/Swift/Controllers/RosterController.h @@ -19,10 +19,14 @@ namespace Swift {  	class TreeWidgetFactory;  	class OfflineRosterFilter;  	class NickResolver; +	class PresenceOracle; +	class EventController; +	class SubscriptionRequestEvent; +	class UIEventStream;  	class RosterController {  		public: -			RosterController(const JID& jid, boost::shared_ptr<XMPPRoster> xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, TreeWidgetFactory* treeWidgetFactory, NickResolver* nickResolver); +			RosterController(const JID& jid, boost::shared_ptr<XMPPRoster> xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, TreeWidgetFactory* treeWidgetFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, EventController* eventController, UIEventStream* uiEventStream);  			~RosterController();  			void showRosterWindow();  			MainWindow* getWindow() {return mainWindow_;}; @@ -32,7 +36,6 @@ namespace Swift {  			boost::signal<void (const JID&, const String&)> onJoinMUCRequest;  			boost::signal<void (StatusShow::Type, const String&)> onChangeStatusRequest;  			boost::signal<void ()> onSignOutRequest; -			void handleIncomingPresence(boost::shared_ptr<Presence> presence);  			void handleAvatarChanged(const JID& jid, const String& hash);  			void setEnabled(bool enabled);  		private: @@ -44,6 +47,10 @@ namespace Swift {  			void handleUserAction(boost::shared_ptr<UserRosterAction> action);  			void handleChangeStatusRequest(StatusShow::Type show, const String &statusText);  			void handleShowOfflineToggled(bool state); +			void handleIncomingPresence(boost::shared_ptr<Presence> newPresence, boost::shared_ptr<Presence> oldPresence); +			void handleSubscriptionRequest(const JID& jid, const String& message); +			void handleSubscriptionRequestAccepted(SubscriptionRequestEvent* event); +			void handleSubscriptionRequestDeclined(SubscriptionRequestEvent* event);  			JID myJID_;  			boost::shared_ptr<XMPPRoster> xmppRoster_;  			MainWindowFactory* mainWindowFactory_; @@ -53,6 +60,8 @@ namespace Swift {  			OfflineRosterFilter* offlineFilter_;  			AvatarManager* avatarManager_;  			NickResolver* nickResolver_; +			PresenceOracle* presenceOracle_; +			EventController* eventController_;  	};  }  #endif diff --git a/Swift/Controllers/SoundEventController.cpp b/Swift/Controllers/SoundEventController.cpp index 392b4e9..456de44 100644 --- a/Swift/Controllers/SoundEventController.cpp +++ b/Swift/Controllers/SoundEventController.cpp @@ -14,7 +14,7 @@ SoundEventController::SoundEventController(EventController* eventController, Sou  	playSounds_ = playSounds;  } -void SoundEventController::handleEventQueueEventAdded(boost::shared_ptr<Event>) { +void SoundEventController::handleEventQueueEventAdded(boost::shared_ptr<StanzaEvent>) {  	if (playSounds_) soundPlayer_->playSound(SoundPlayer::MessageReceived);  } diff --git a/Swift/Controllers/SoundEventController.h b/Swift/Controllers/SoundEventController.h index 777e55f..07ac667 100644 --- a/Swift/Controllers/SoundEventController.h +++ b/Swift/Controllers/SoundEventController.h @@ -2,7 +2,7 @@  #include <boost/shared_ptr.hpp> -#include "Swiften/Events/Event.h" +#include "Swiften/Events/StanzaEvent.h"  namespace Swift {  	class EventController; @@ -12,7 +12,7 @@ namespace Swift {  			SoundEventController(EventController* eventController, SoundPlayer* soundPlayer, bool playSounds);  			void setPlaySounds(bool playSounds);  		private: -			void handleEventQueueEventAdded(boost::shared_ptr<Event> event); +			void handleEventQueueEventAdded(boost::shared_ptr<StanzaEvent> event);  			EventController* eventController_;  			SoundPlayer* soundPlayer_;  			bool playSounds_; diff --git a/Swift/Controllers/UIInterfaces/EventWindow.h b/Swift/Controllers/UIInterfaces/EventWindow.h index 95bd7dd..b85840b 100644 --- a/Swift/Controllers/UIInterfaces/EventWindow.h +++ b/Swift/Controllers/UIInterfaces/EventWindow.h @@ -1,13 +1,13 @@  #pragma once  #include "boost/shared_ptr.hpp" -#include "Swiften/Events/Event.h" +#include "Swiften/Events/StanzaEvent.h"  namespace Swift {  	class EventWindow {  		public:  			virtual ~EventWindow() {};	 -			virtual void addEvent(boost::shared_ptr<Event> event, bool active) = 0; -			virtual void removeEvent(boost::shared_ptr<Event> event) = 0; +			virtual void addEvent(boost::shared_ptr<StanzaEvent> event, bool active) = 0; +			virtual void removeEvent(boost::shared_ptr<StanzaEvent> event) = 0;  	};  } diff --git a/Swift/Controllers/UnitTest/RosterControllerTest.cpp b/Swift/Controllers/UnitTest/RosterControllerTest.cpp index 0296cdc..67884d0 100644 --- a/Swift/Controllers/UnitTest/RosterControllerTest.cpp +++ b/Swift/Controllers/UnitTest/RosterControllerTest.cpp @@ -8,8 +8,11 @@  // #include "Swiften/Elements/RosterItemPayload.h"  // #include "Swiften/Elements/RosterPayload.h"  #include "Swiften/Queries/DummyIQChannel.h" +#include "Swiften/Client/DummyStanzaChannel.h"  #include "Swiften/Queries/IQRouter.h"  #include "Swiften/Roster/XMPPRoster.h" +#include "Swift/Controllers/EventController.h" +#include "Swiften/Presence/PresenceOracle.h"  #include "Swift/Controllers/NickResolver.h"  using namespace Swift; @@ -30,10 +33,13 @@ class RosterControllerTest : public CppUnit::TestFixture  			treeWidgetFactory_ = new MockTreeWidgetFactory();  			mainWindowFactory_ = new MockMainWindowFactory(treeWidgetFactory_);  			nickResolver_ = new NickResolver(xmppRoster_); -			rosterController_ = new RosterController(jid_, xmppRoster_, avatarManager_, mainWindowFactory_, treeWidgetFactory_, nickResolver_); -  			channel_ = new DummyIQChannel();  			router_ = new IQRouter(channel_); +			stanzaChannel_ = new DummyStanzaChannel(); +			presenceOracle_ = new PresenceOracle(stanzaChannel_); +			eventController_ = new EventController(); +			rosterController_ = new RosterController(jid_, xmppRoster_, avatarManager_, mainWindowFactory_, treeWidgetFactory_, nickResolver_, presenceOracle_, eventController_); +  		}; @@ -45,6 +51,9 @@ class RosterControllerTest : public CppUnit::TestFixture  			delete avatarManager_;  			delete channel_;  			delete router_; +			delete eventController_; +			delete presenceOracle_; +			delete stanzaChannel_;  		};  		void testAdd() { @@ -66,6 +75,9 @@ class RosterControllerTest : public CppUnit::TestFixture  		NickResolver* nickResolver_;  		RosterController* rosterController_;  		DummyIQChannel* channel_; +		DummyStanzaChannel* stanzaChannel_;	  		IQRouter* router_; +		PresenceOracle* presenceOracle_; +		EventController* eventController_;  }; diff --git a/Swift/QtUI/EventViewer/EventModel.cpp b/Swift/QtUI/EventViewer/EventModel.cpp index f75fe74..902004b 100644 --- a/Swift/QtUI/EventViewer/EventModel.cpp +++ b/Swift/QtUI/EventViewer/EventModel.cpp @@ -16,14 +16,16 @@ EventModel::~EventModel() {  	}  } +QtEvent* EventModel::getItem(int row) const { +	return row < activeEvents_.size() ? activeEvents_[row] : inactiveEvents_[row - activeEvents_.size()]; +} +  QVariant EventModel::data(const QModelIndex& index, int role) const {  	if (!index.isValid()) {  		return QVariant();  	} -	int row = index.row(); -	QtEvent* item = index.row() < activeEvents_.size() ? activeEvents_[row] : inactiveEvents_[row - activeEvents_.size()]; +	QtEvent* item = getItem(index.row());  	QVariant result = item ? item->data(role) : QVariant(); -	qDebug() << "Asked for data of " << index << ", " << role << " returning " << result;  	return result;  } @@ -33,8 +35,7 @@ int EventModel::rowCount(const QModelIndex& parent) const {  	return count;  } -void EventModel::addEvent(boost::shared_ptr<Event> event, bool active) { -	qDebug() << " Adding Event"; +void EventModel::addEvent(boost::shared_ptr<StanzaEvent> event, bool active) {  	if (active) {  		activeEvents_.push_front(new QtEvent(event, active));  		emit dataChanged(createIndex(0, 0), createIndex(1, 0)); @@ -48,7 +49,7 @@ void EventModel::addEvent(boost::shared_ptr<Event> event, bool active) {  	emit layoutChanged();  } -void EventModel::removeEvent(boost::shared_ptr<Event> event) { +void EventModel::removeEvent(boost::shared_ptr<StanzaEvent> event) {  	for (int i = inactiveEvents_.size() - 1; i >= 0; i--) {  		if (event == inactiveEvents_[i]->getEvent()) {  			inactiveEvents_.removeAt(i); diff --git a/Swift/QtUI/EventViewer/EventModel.h b/Swift/QtUI/EventViewer/EventModel.h index bc54cf4..7882c6b 100644 --- a/Swift/QtUI/EventViewer/EventModel.h +++ b/Swift/QtUI/EventViewer/EventModel.h @@ -5,7 +5,7 @@  #include <QAbstractListModel>  #include <QList> -#include "Swiften/Events/Event.h" +#include "Swiften/Events/StanzaEvent.h"  #include "Swift/QtUI/EventViewer/QtEvent.h" @@ -15,10 +15,11 @@ Q_OBJECT  public:  	EventModel();  	~EventModel(); -	void addEvent(boost::shared_ptr<Event> event, bool active); -	void removeEvent(boost::shared_ptr<Event> event); +	void addEvent(boost::shared_ptr<StanzaEvent> event, bool active); +	void removeEvent(boost::shared_ptr<StanzaEvent> event);  	QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;  	int rowCount(const QModelIndex& parent = QModelIndex()) const; +	QtEvent* getItem(int row) const;  private:  	QList<QtEvent*> activeEvents_;  	QList<QtEvent*> inactiveEvents_; diff --git a/Swift/QtUI/EventViewer/QtEvent.cpp b/Swift/QtUI/EventViewer/QtEvent.cpp index 2dc1fb0..3aae213 100644 --- a/Swift/QtUI/EventViewer/QtEvent.cpp +++ b/Swift/QtUI/EventViewer/QtEvent.cpp @@ -1,22 +1,23 @@  #include "Swift/QtUI/EventViewer/QtEvent.h"  #include "Swiften/Events/MessageEvent.h" +#include "Swiften/Events/SubscriptionRequestEvent.h"  #include "Swift/QtUI/QtSwiftUtil.h"  namespace Swift { -QtEvent::QtEvent(boost::shared_ptr<Event> event, bool active) : event_(event) { +QtEvent::QtEvent(boost::shared_ptr<StanzaEvent> event, bool active) : event_(event) {  	active_ = active;  }  QVariant QtEvent::data(int role) {   	switch (role) { +		case Qt::ToolTipRole:  		case Qt::DisplayRole: return QVariant(text());  		case Qt::TextColorRole: return active_ ? Qt::black : Qt::darkGray;  		case Qt::BackgroundColorRole: return active_ ? Qt::white : Qt::lightGray; -			/*case Qt::ToolTipRole: return isContact() ? toolTipString() : QVariant(); -	 	case StatusTextRole: return statusText_; +			/*case StatusTextRole: return statusText_;  		case AvatarRole: return avatar_;  		case PresenceIconRole: return getPresenceIcon();*/  	 	default: return QVariant(); @@ -25,7 +26,16 @@ QVariant QtEvent::data(int role) {  QString QtEvent::text() {  	boost::shared_ptr<MessageEvent> messageEvent = boost::dynamic_pointer_cast<MessageEvent>(event_); -	return messageEvent ? P2QSTRING(messageEvent->getStanza()->getBody()) :  "Bob: "; +	if (messageEvent) { +		return P2QSTRING(messageEvent->getStanza()->getBody()); +	} +	boost::shared_ptr<SubscriptionRequestEvent> subscriptionRequestEvent = boost::dynamic_pointer_cast<SubscriptionRequestEvent>(event_); +	if (subscriptionRequestEvent) { +		String reason = subscriptionRequestEvent->getReason(); +		String message = subscriptionRequestEvent->getJID().toBare().toString() + " would like to add you to their roster" + (reason.isEmpty() ? "." : ", saying '" + reason + "'."); +		return P2QSTRING(message); +	} +	return "";  }  } diff --git a/Swift/QtUI/EventViewer/QtEvent.h b/Swift/QtUI/EventViewer/QtEvent.h index 7083c6e..6dec858 100644 --- a/Swift/QtUI/EventViewer/QtEvent.h +++ b/Swift/QtUI/EventViewer/QtEvent.h @@ -4,17 +4,17 @@  #include <QVariant> -#include "Swiften/Events/Event.h" +#include "Swiften/Events/StanzaEvent.h"  namespace Swift {  	class QtEvent {  		public: -			QtEvent(boost::shared_ptr<Event> event, bool active); +			QtEvent(boost::shared_ptr<StanzaEvent> event, bool active);  			QVariant data(int role); -			boost::shared_ptr<Event> getEvent() { return event_; }; +			boost::shared_ptr<StanzaEvent> getEvent() { return event_; };  		private:  			QString text(); -			boost::shared_ptr<Event> event_; +			boost::shared_ptr<StanzaEvent> event_;  			bool active_;  	};  } diff --git a/Swift/QtUI/EventViewer/QtEventWindow.cpp b/Swift/QtUI/EventViewer/QtEventWindow.cpp index fda957d..91eb2c1 100644 --- a/Swift/QtUI/EventViewer/QtEventWindow.cpp +++ b/Swift/QtUI/EventViewer/QtEventWindow.cpp @@ -1,10 +1,17 @@  #include "Swift/QtUI/EventViewer/QtEventWindow.h" +#include <qdebug> + +#include "Swiften/Events/MessageEvent.h" +#include "Swiften/Events/SubscriptionRequestEvent.h" +#include "Swift/Controllers/UIEvents/RequestChatUIEvent.h" +  #include "Swiften/Base/Platform.h"  namespace Swift { -QtEventWindow::QtEventWindow(QWidget* parent) : QTreeView(parent) { +QtEventWindow::QtEventWindow(UIEventStream* eventStream, QWidget* parent) : QTreeView(parent) { +	eventStream_ = eventStream;  	model_ = new EventModel();  	setModel(model_);  	delegate_ = new EventDelegate(); @@ -16,6 +23,7 @@ QtEventWindow::QtEventWindow(QWidget* parent) : QTreeView(parent) {  	setAnimated(true);  	setIndentation(0);  	setRootIsDecorated(true); +	connect(this, SIGNAL(activated(const QModelIndex&)), this, SLOT(handleItemActivated(const QModelIndex&)));  }  QtEventWindow::~QtEventWindow() { @@ -23,11 +31,27 @@ QtEventWindow::~QtEventWindow() {  	delete delegate_;  } -void QtEventWindow::addEvent(boost::shared_ptr<Event> event, bool active) { +void QtEventWindow::handleItemActivated(const QModelIndex& item) { +	QtEvent* event = model_->getItem(item.row()); +	boost::shared_ptr<MessageEvent> messageEvent = boost::dynamic_pointer_cast<MessageEvent>(event->getEvent()); +	boost::shared_ptr<SubscriptionRequestEvent> subscriptionEvent = boost::dynamic_pointer_cast<SubscriptionRequestEvent>(event->getEvent()); +	 +	if (messageEvent) { +		eventStream_->send(boost::shared_ptr<UIEvent>(new RequestChatUIEvent(messageEvent->getStanza()->getFrom()))); +	} else if (subscriptionEvent) { +		printf("Subscription activated\n"); +		//FIXME: do something +	} else { +		qWarning() << "Trying to activate an unexpected event"; +	} + +} + +void QtEventWindow::addEvent(boost::shared_ptr<StanzaEvent> event, bool active) {  	model_->addEvent(event, active);  } -void QtEventWindow::removeEvent(boost::shared_ptr<Event> event) { +void QtEventWindow::removeEvent(boost::shared_ptr<StanzaEvent> event) {  	model_->removeEvent(event);  } diff --git a/Swift/QtUI/EventViewer/QtEventWindow.h b/Swift/QtUI/EventViewer/QtEventWindow.h index cab50ef..283ba52 100644 --- a/Swift/QtUI/EventViewer/QtEventWindow.h +++ b/Swift/QtUI/EventViewer/QtEventWindow.h @@ -5,6 +5,7 @@  #include <QTreeView>  #include "Swift/Controllers/UIInterfaces/EventWindow.h" +#include "Swift/Controllers/UIEvents/UIEventStream.h"  #include "Swift/QtUI/EventViewer/EventView.h"  #include "Swift/QtUI/EventViewer/EventModel.h"  #include "Swift/QtUI/EventViewer/EventDelegate.h" @@ -13,13 +14,16 @@ namespace Swift {  	class QtEventWindow : public QTreeView, public EventWindow {  		Q_OBJECT  		public: -			QtEventWindow(QWidget* parent = 0); +			QtEventWindow(UIEventStream* eventStream, QWidget* parent = 0);  			~QtEventWindow(); -			void addEvent(boost::shared_ptr<Event> event, bool active); -			void removeEvent(boost::shared_ptr<Event> event); +			void addEvent(boost::shared_ptr<StanzaEvent> event, bool active); +			void removeEvent(boost::shared_ptr<StanzaEvent> event); +		private slots: +			void handleItemActivated(const QModelIndex& item);  		private:  			EventModel* model_;  			EventDelegate* delegate_; +			UIEventStream* eventStream_;  	};  } diff --git a/Swift/QtUI/QtMainWindow.cpp b/Swift/QtUI/QtMainWindow.cpp index 10dcfa6..ebafaff 100644 --- a/Swift/QtUI/QtMainWindow.cpp +++ b/Swift/QtUI/QtMainWindow.cpp @@ -19,7 +19,8 @@  namespace Swift { -QtMainWindow::QtMainWindow(QtTreeWidgetFactory *treeWidgetFactory) : QWidget() { +QtMainWindow::QtMainWindow(UIEventStream* uiEventStream, QtTreeWidgetFactory *treeWidgetFactory) : QWidget() { +	uiEventStream_ = uiEventStream;  	setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));  	QBoxLayout *mainLayout = new QBoxLayout(QBoxLayout::TopToBottom, this);  	mainLayout->setContentsMargins(0,0,0,0); @@ -45,7 +46,7 @@ QtMainWindow::QtMainWindow(QtTreeWidgetFactory *treeWidgetFactory) : QWidget() {  	tabs_->addTab(contactsTabWidget_, "Contacts"); -	eventWindow_ = new QtEventWindow(); +	eventWindow_ = new QtEventWindow(uiEventStream_);  	tabs_->addTab(eventWindow_, "Events"); diff --git a/Swift/QtUI/QtMainWindow.h b/Swift/QtUI/QtMainWindow.h index ce3272a..1c862e6 100644 --- a/Swift/QtUI/QtMainWindow.h +++ b/Swift/QtUI/QtMainWindow.h @@ -21,11 +21,12 @@ namespace Swift {  	class QtTreeWidget;  	class QtTreeWidgetFactory;  	class TreeWidget; +	class UIEventStream;  	class QtMainWindow : public QWidget, public MainWindow {  		Q_OBJECT  		public: -			QtMainWindow(QtTreeWidgetFactory *treeWidgetFactory); +			QtMainWindow(UIEventStream* eventStream, QtTreeWidgetFactory *treeWidgetFactory);  			TreeWidget* getTreeWidget();  			std::vector<QMenu*> getMenus() {return menus_;}  			void setMyName(const String& name); @@ -53,6 +54,7 @@ namespace Swift {  			QWidget* contactsTabWidget_;  			QWidget* eventsTabWidget_;  			QtEventWindow* eventWindow_; +			UIEventStream* uiEventStream_;  	};  } diff --git a/Swift/QtUI/QtMainWindowFactory.cpp b/Swift/QtUI/QtMainWindowFactory.cpp index 0794780..dc1949e 100644 --- a/Swift/QtUI/QtMainWindowFactory.cpp +++ b/Swift/QtUI/QtMainWindowFactory.cpp @@ -8,8 +8,8 @@ QtMainWindowFactory::QtMainWindowFactory(QtTreeWidgetFactory *treeWidgetFactory)  	lastWindow_ = NULL;  } -MainWindow* QtMainWindowFactory::createMainWindow() { -	QtMainWindow* window = new QtMainWindow(treeWidgetFactory_); +MainWindow* QtMainWindowFactory::createMainWindow(UIEventStream* eventStream) { +	QtMainWindow* window = new QtMainWindow(eventStream, treeWidgetFactory_);  	lastWindow_ = window;  	return window;  } diff --git a/Swift/QtUI/QtMainWindowFactory.h b/Swift/QtUI/QtMainWindowFactory.h index bd8342c..8567efd 100644 --- a/Swift/QtUI/QtMainWindowFactory.h +++ b/Swift/QtUI/QtMainWindowFactory.h @@ -8,7 +8,7 @@ namespace Swift {  	class QtMainWindowFactory : public MainWindowFactory{  		public:  			QtMainWindowFactory(QtTreeWidgetFactory *treeWidgetFactory); -			MainWindow* createMainWindow(); +			MainWindow* createMainWindow(UIEventStream* eventStream);  			MainWindow* getLastCreatedWindow();  		private:  			QtTreeWidgetFactory *treeWidgetFactory_; diff --git a/Swiften/Events/MessageEvent.h b/Swiften/Events/MessageEvent.h index 0adfa82..1f71493 100644 --- a/Swiften/Events/MessageEvent.h +++ b/Swiften/Events/MessageEvent.h @@ -6,11 +6,11 @@  #include <boost/signals.hpp>  #include <boost/shared_ptr.hpp> -#include "Swiften/Events/Event.h" +#include "Swiften/Events/StanzaEvent.h"  #include "Swiften/Elements/Message.h"  namespace Swift { -	class MessageEvent : public Event { +	class MessageEvent : public StanzaEvent {  		public:  			MessageEvent(boost::shared_ptr<Message> stanza) : stanza_(stanza){};  			virtual ~MessageEvent(){}; diff --git a/Swiften/Events/Event.h b/Swiften/Events/StanzaEvent.h index b4a71f6..adef112 100644 --- a/Swiften/Events/Event.h +++ b/Swiften/Events/StanzaEvent.h @@ -4,10 +4,10 @@  #include <boost/shared_ptr.hpp>  namespace Swift { -	class Event { +	class StanzaEvent {  		public: -			Event(){}; -			virtual ~Event() {}; +			StanzaEvent(){}; +			virtual ~StanzaEvent() {};  			boost::signal<void()> onConclusion;  	};  } diff --git a/Swiften/Events/SubscriptionRequestEvent.h b/Swiften/Events/SubscriptionRequestEvent.h new file mode 100644 index 0000000..fe41df7 --- /dev/null +++ b/Swiften/Events/SubscriptionRequestEvent.h @@ -0,0 +1,36 @@ +#pragma once + +#include <cassert> + +#include <boost/signals.hpp> +#include <boost/shared_ptr.hpp> + +#include "Swiften/Events/StanzaEvent.h" +#include "Swiften/Base/String.h" +#include "Swiften/JID/JID.h" + +namespace Swift { +	class SubscriptionRequestEvent : public StanzaEvent { +		public: +			SubscriptionRequestEvent(const JID& jid, const String& reason) : jid_(jid), reason_(reason){}; +			virtual ~SubscriptionRequestEvent(){}; +			const JID& getJID() const {return jid_;}; +			const String& getReason() const {return reason_;}; +			boost::signal<void()> onAccept; +			boost::signal<void()> onDecline; +			void accept() { +				onAccept(); +				onConclusion(); +			} + +			void decline() { +				onDecline(); +				onConclusion(); +			} + +		private: +			JID jid_; +			String reason_; +	}; +} + diff --git a/Swiften/Presence/PresenceOracle.cpp b/Swiften/Presence/PresenceOracle.cpp index af98510..f1e6adb 100644 --- a/Swiften/Presence/PresenceOracle.cpp +++ b/Swiften/Presence/PresenceOracle.cpp @@ -13,17 +13,23 @@ PresenceOracle::PresenceOracle(StanzaChannel* stanzaChannel) {  void PresenceOracle::handleIncomingPresence(boost::shared_ptr<Presence> presence) {  	JID bareJID = JID(presence->getFrom().toBare()); -	std::map<JID, boost::shared_ptr<Presence> > jidMap = entries_[bareJID]; -	boost::shared_ptr<Presence> last; -	foreach(JIDPresencePair pair, jidMap) { -		if (pair.first == presence->getFrom()) { -			last = pair.second; -			break; + +	if (presence->getType() == Presence::Subscribe) { +		fprintf(stderr, "rarr, sub\n"); +		onPresenceSubscriptionRequest(bareJID, presence->getStatus()); +	} else { +		std::map<JID, boost::shared_ptr<Presence> > jidMap = entries_[bareJID]; +		boost::shared_ptr<Presence> last; +		foreach(JIDPresencePair pair, jidMap) { +			if (pair.first == presence->getFrom()) { +				last = pair.second; +				break; +			}  		} +		jidMap[presence->getFrom()] = presence; +		entries_[bareJID] = jidMap; +		onPresenceChange(presence, last);  	} -	jidMap[presence->getFrom()] = presence; -	entries_[bareJID] = jidMap; -	onPresenceChange(presence, last);  }  } diff --git a/Swiften/Presence/UnitTest/PresenceOracleTest.cpp b/Swiften/Presence/UnitTest/PresenceOracleTest.cpp index e6f56b2..2c9c526 100644 --- a/Swiften/Presence/UnitTest/PresenceOracleTest.cpp +++ b/Swiften/Presence/UnitTest/PresenceOracleTest.cpp @@ -15,11 +15,18 @@ class PresencePointerPair {  		boost::shared_ptr<Presence> two;  }; +class SubscriptionRequestInfo { +	public: +		boost::optional<JID> jid; +		boost::optional<String> reason; +}; +  class PresenceOracleTest : public CppUnit::TestFixture  {  		CPPUNIT_TEST_SUITE(PresenceOracleTest);  		CPPUNIT_TEST(testFirstPresence);  		CPPUNIT_TEST(testSecondPresence); +		CPPUNIT_TEST(testSubscriptionRequest);  		CPPUNIT_TEST_SUITE_END();  	private: @@ -37,11 +44,11 @@ class PresenceOracleTest : public CppUnit::TestFixture  			CPPUNIT_ASSERT_EQUAL(newPresence, out->one);  		} -		void handlePresenceSubscriptionRequest(const JID& jid, const String& reason, boost::optional<JID>& outJID, boost::optional<String>& outReason) { -			CPPUNIT_ASSERT(!outJID); -			CPPUNIT_ASSERT(!outReason); -			outJID = jid; -			outReason = reason; +		void handlePresenceSubscriptionRequest(const JID& jid, const String& reason, SubscriptionRequestInfo* info) { +			CPPUNIT_ASSERT(!info->jid); +			CPPUNIT_ASSERT(!info->reason); +			info->jid = jid; +			info->reason = reason;  		}  		void setUp() { @@ -58,15 +65,14 @@ class PresenceOracleTest : public CppUnit::TestFixture  			PresencePointerPair out;  			oracle_->onPresenceChange.connect(boost::bind(&PresenceOracleTest::handlePresenceChange, this, _1, _2, &out)); -			boost::optional<JID> jid; -			boost::optional<String> reason; -			oracle_->onPresenceSubscriptionRequest.connect(boost::bind(&PresenceOracleTest::handlePresenceSubscriptionRequest, this, _1, _2, jid, reason)); +			SubscriptionRequestInfo info; +			oracle_->onPresenceSubscriptionRequest.connect(boost::bind(&PresenceOracleTest::handlePresenceSubscriptionRequest, this, _1, _2, &info));  			boost::shared_ptr<Presence> sentPresence(new Presence("blarb"));  			stanzaChannel_->onPresenceReceived(sentPresence); -			CPPUNIT_ASSERT(!jid); -			CPPUNIT_ASSERT(!reason); +			CPPUNIT_ASSERT(!info.jid); +			CPPUNIT_ASSERT(!info.reason);  			CPPUNIT_ASSERT(out.two.get() == NULL);  			CPPUNIT_ASSERT_EQUAL(sentPresence, out.one);  		} @@ -80,19 +86,41 @@ class PresenceOracleTest : public CppUnit::TestFixture  			CPPUNIT_ASSERT_EQUAL(sentPresence1, out.one);  			out.one = boost::shared_ptr<Presence>(); -			boost::optional<JID> jid; -			boost::optional<String> reason; -			oracle_->onPresenceSubscriptionRequest.connect(boost::bind(&PresenceOracleTest::handlePresenceSubscriptionRequest, this, _1, _2, jid, reason)); +			SubscriptionRequestInfo info; +			oracle_->onPresenceSubscriptionRequest.connect(boost::bind(&PresenceOracleTest::handlePresenceSubscriptionRequest, this, _1, _2, &info));  			boost::shared_ptr<Presence> sentPresence2(new Presence("test2"));  			stanzaChannel_->onPresenceReceived(sentPresence2); -			CPPUNIT_ASSERT(!jid); -			CPPUNIT_ASSERT(!reason); +			CPPUNIT_ASSERT(!info.jid); +			CPPUNIT_ASSERT(!info.reason);  			CPPUNIT_ASSERT_EQUAL(sentPresence1, out.two);  			CPPUNIT_ASSERT_EQUAL(sentPresence2, out.one);  		} +		void testSubscriptionRequest() { +			PresencePointerPair out; +			oracle_->onPresenceChange.connect(boost::bind(&PresenceOracleTest::handlePresenceChange, this, _1, _2, &out)); +			SubscriptionRequestInfo info; +			oracle_->onPresenceSubscriptionRequest.connect(boost::bind(&PresenceOracleTest::handlePresenceSubscriptionRequest, this, _1, _2, &info)); + +			String reasonText = "Because I want to"; +			JID sentJID = JID("me@example.com"); + +			boost::shared_ptr<Presence> sentPresence(new Presence()); +			sentPresence->setType(Presence::Subscribe); +			sentPresence->setFrom(sentJID); +			sentPresence->setStatus(reasonText); +			stanzaChannel_->onPresenceReceived(sentPresence); + +			CPPUNIT_ASSERT(info.jid); +			CPPUNIT_ASSERT(info.reason); +			CPPUNIT_ASSERT_EQUAL(sentJID, info.jid.get()); +			CPPUNIT_ASSERT_EQUAL(reasonText, info.reason.get()); + +			CPPUNIT_ASSERT(!out.two); +			CPPUNIT_ASSERT(!out.one); +		}  };  CPPUNIT_TEST_SUITE_REGISTRATION(PresenceOracleTest); | 
 Swift
 Swift