From edd726abb1d0f7532218efbb8067a75a313e9e98 Mon Sep 17 00:00:00 2001
From: Mateusz Piekos <mateuszpiekos@gmail.com>
Date: Tue, 12 Jun 2012 12:52:03 +0200
Subject: Improved whiteboard session handling


diff --git a/Swift/Controllers/UIInterfaces/WhiteboardWindow.h b/Swift/Controllers/UIInterfaces/WhiteboardWindow.h
index bedb057..ae736d7 100644
--- a/Swift/Controllers/UIInterfaces/WhiteboardWindow.h
+++ b/Swift/Controllers/UIInterfaces/WhiteboardWindow.h
@@ -11,6 +11,7 @@
 #include <string>
 
 namespace Swift {
+	class WhiteboardSession;
 
 	class WhiteboardWindow {
 	public:
@@ -18,6 +19,7 @@ namespace Swift {
 
 		virtual void show() = 0;
 		virtual void addItem(const std::string& item) = 0;
+		virtual void setSession(boost::shared_ptr<WhiteboardSession> session) = 0;
 
 		boost::signal<void (std::string)> onItemAdd;
 	};
diff --git a/Swift/Controllers/UIInterfaces/WhiteboardWindowFactory.h b/Swift/Controllers/UIInterfaces/WhiteboardWindowFactory.h
index 7e0fe81..c2d2f6c 100644
--- a/Swift/Controllers/UIInterfaces/WhiteboardWindowFactory.h
+++ b/Swift/Controllers/UIInterfaces/WhiteboardWindowFactory.h
@@ -14,6 +14,6 @@ namespace Swift {
 	public :
 		virtual ~WhiteboardWindowFactory() {};
 
-		virtual WhiteboardWindow* createWhiteboardWindow(WhiteboardSession* whiteboardSession) = 0;
+		virtual WhiteboardWindow* createWhiteboardWindow(boost::shared_ptr<WhiteboardSession> whiteboardSession) = 0;
 	};
 }
diff --git a/Swift/Controllers/WhiteboardManager.cpp b/Swift/Controllers/WhiteboardManager.cpp
index 37c3263..f6db4ff 100644
--- a/Swift/Controllers/WhiteboardManager.cpp
+++ b/Swift/Controllers/WhiteboardManager.cpp
@@ -20,7 +20,6 @@ namespace Swift {
 
 	WhiteboardManager::WhiteboardManager(WhiteboardWindowFactory* whiteboardWindowFactory, UIEventStream* uiEventStream, WhiteboardSessionManager* whiteboardSessionManager) : whiteboardWindowFactory_(whiteboardWindowFactory), uiEventStream_(uiEventStream), whiteboardSessionManager_(whiteboardSessionManager) {
 		uiEventConnection_ = uiEventStream_->onUIEvent.connect(boost::bind(&WhiteboardManager::handleUIEvent, this, _1));
-		whiteboardSessionManager_->onRequestAccepted.connect(boost::bind(&WhiteboardManager::handleAcceptedRequest, this, _1, _2));
 	}
 
 	WhiteboardManager::~WhiteboardManager() {
@@ -29,23 +28,30 @@ namespace Swift {
 		}
 	}
 
-	WhiteboardWindow* WhiteboardManager::createNewWhiteboardWindow(const JID& contact, WhiteboardSession* session) {
+	WhiteboardWindow* WhiteboardManager::createNewWhiteboardWindow(const JID& contact, WhiteboardSession::ref session) {
 		WhiteboardWindow *window = whiteboardWindowFactory_->createWhiteboardWindow(session);
-		whiteboardWindows_[contact] = window;
+		whiteboardWindows_[contact.toBare()] = window;
 		return window;
 	}
 
 	WhiteboardWindow* WhiteboardManager::findWhiteboardWindow(const JID& contact) {
-		if (whiteboardWindows_.find(contact) == whiteboardWindows_.end()) {
+		if (whiteboardWindows_.find(contact.toBare()) == whiteboardWindows_.end()) {
 			return NULL;
 		}
-		return whiteboardWindows_[contact];
+		return whiteboardWindows_[contact.toBare()];
 	}
 
 	void WhiteboardManager::handleUIEvent(boost::shared_ptr<UIEvent> event) {
-		boost::shared_ptr<RequestWhiteboardUIEvent> whiteboardEvent = boost::dynamic_pointer_cast<RequestWhiteboardUIEvent>(event);
-		if (whiteboardEvent) {
-			whiteboardSessionManager_->requestSession(whiteboardEvent->getContact());
+		boost::shared_ptr<RequestWhiteboardUIEvent> requestWhiteboardEvent = boost::dynamic_pointer_cast<RequestWhiteboardUIEvent>(event);
+		if (requestWhiteboardEvent) {
+			JID contact = requestWhiteboardEvent->getContact();
+			WhiteboardSession::ref session = whiteboardSessionManager_->requestSession(contact);
+			WhiteboardWindow* window = findWhiteboardWindow(contact);
+			if (window == NULL) {
+				createNewWhiteboardWindow(contact, session);
+			} else {
+				window->setSession(session);
+			}
 		}
 		boost::shared_ptr<AcceptWhiteboardSessionUIEvent> sessionAcceptEvent = boost::dynamic_pointer_cast<AcceptWhiteboardSessionUIEvent>(event);
 		if (sessionAcceptEvent) {
@@ -53,24 +59,28 @@ namespace Swift {
 		}
 		boost::shared_ptr<CancelWhiteboardSessionUIEvent> sessionCancelEvent = boost::dynamic_pointer_cast<CancelWhiteboardSessionUIEvent>(event);
 		if (sessionCancelEvent) {
-			whiteboardSessionManager_->cancelSession(sessionCancelEvent->getContact());
+			cancelSession(sessionCancelEvent->getContact());
 		}
 	}
 
 	void WhiteboardManager::acceptSession(const JID& from) {
-		WhiteboardSession* session = whiteboardSessionManager_->acceptSession(from);
-		WhiteboardWindow* window = findWhiteboardWindow(from);
-		if (window == NULL) {
-			window = createNewWhiteboardWindow(from, session);
+		IncomingWhiteboardSession::ref session = boost::dynamic_pointer_cast<IncomingWhiteboardSession>(whiteboardSessionManager_->getSession(from));
+		if (session) {
+			session->accept();
+			WhiteboardWindow* window = findWhiteboardWindow(from);
+			if (window == NULL) {
+				window = createNewWhiteboardWindow(from, session);
+			} else {
+				window->setSession(session);
+			}
+			window->show();
 		}
-		window->show();
 	}
 
-	void WhiteboardManager::handleAcceptedRequest(const JID& from, WhiteboardSession* session) {
-		WhiteboardWindow* window = findWhiteboardWindow(from);
-		if (window == NULL) {
-			window = createNewWhiteboardWindow(from, session);
+	void WhiteboardManager::cancelSession(const JID& from) {
+		IncomingWhiteboardSession::ref session = boost::dynamic_pointer_cast<IncomingWhiteboardSession>(whiteboardSessionManager_->getSession(from));
+		if (session) {
+			session->cancel();
 		}
-		window->show();
 	}
 }
diff --git a/Swift/Controllers/WhiteboardManager.h b/Swift/Controllers/WhiteboardManager.h
index 2690f36..52d9bae 100644
--- a/Swift/Controllers/WhiteboardManager.h
+++ b/Swift/Controllers/WhiteboardManager.h
@@ -16,6 +16,7 @@
 #include <Swift/Controllers/UIEvents/UIEventStream.h>
 #include <Swift/Controllers/UIInterfaces/WhiteboardWindowFactory.h>
 #include <Swift/Controllers/UIInterfaces/WhiteboardWindow.h>
+#include <Swiften/Whiteboard/WhiteboardSession.h>
 
 namespace Swift {
 	class WhiteboardSessionManager;
@@ -25,12 +26,12 @@ namespace Swift {
 		WhiteboardManager(WhiteboardWindowFactory* whiteboardWindowFactory, UIEventStream* uiEventStream, WhiteboardSessionManager* whiteboardSessionManager);
 		~WhiteboardManager();
 
-		WhiteboardWindow* createNewWhiteboardWindow(const JID& contact, WhiteboardSession* session);
+		WhiteboardWindow* createNewWhiteboardWindow(const JID& contact, WhiteboardSession::ref session);
 
 	private:
 		void handleUIEvent(boost::shared_ptr<UIEvent> event);
 		void acceptSession(const JID& from);
-		void handleAcceptedRequest(const JID& from, WhiteboardSession* session);
+		void cancelSession(const JID& from);
 		WhiteboardWindow* findWhiteboardWindow(const JID& contact);
 
 	private:
diff --git a/Swift/QtUI/QtUIFactory.cpp b/Swift/QtUI/QtUIFactory.cpp
index e0fc532..38e065c 100644
--- a/Swift/QtUI/QtUIFactory.cpp
+++ b/Swift/QtUI/QtUIFactory.cpp
@@ -136,7 +136,7 @@ ContactEditWindow* QtUIFactory::createContactEditWindow() {
 	return new QtContactEditWindow();
 }
 
-WhiteboardWindow* QtUIFactory::createWhiteboardWindow(WhiteboardSession* whiteboardSession) {
+WhiteboardWindow* QtUIFactory::createWhiteboardWindow(boost::shared_ptr<WhiteboardSession> whiteboardSession) {
 	return new QtWhiteboardWindow(whiteboardSession);
 }
 
diff --git a/Swift/QtUI/QtUIFactory.h b/Swift/QtUI/QtUIFactory.h
index 951b19c..d307759 100644
--- a/Swift/QtUI/QtUIFactory.h
+++ b/Swift/QtUI/QtUIFactory.h
@@ -43,7 +43,7 @@ namespace Swift {
 			virtual ProfileWindow* createProfileWindow();
 			virtual ContactEditWindow* createContactEditWindow();
 			virtual FileTransferListWidget* createFileTransferListWidget();
-			virtual WhiteboardWindow* createWhiteboardWindow(WhiteboardSession* whiteboardSession);
+			virtual WhiteboardWindow* createWhiteboardWindow(boost::shared_ptr<WhiteboardSession> whiteboardSession);
 			virtual void createAdHocCommandWindow(boost::shared_ptr<OutgoingAdHocCommandSession> command);
 
 		private slots:
diff --git a/Swift/QtUI/Whiteboard/QtWhiteboardWindow.cpp b/Swift/QtUI/Whiteboard/QtWhiteboardWindow.cpp
index e0e68ba..3527eba 100644
--- a/Swift/QtUI/Whiteboard/QtWhiteboardWindow.cpp
+++ b/Swift/QtUI/Whiteboard/QtWhiteboardWindow.cpp
@@ -13,10 +13,11 @@
 #include <Swiften/Whiteboard/WhiteboardSession.h>
 #include <Swiften/Elements/WhiteboardPayload.h>
 
+#include <QMessageBox>
 using namespace std;
 
 namespace Swift {
-	QtWhiteboardWindow::QtWhiteboardWindow(WhiteboardSession* whiteboardSession) : QWidget(), whiteboardSession_(whiteboardSession) {
+	QtWhiteboardWindow::QtWhiteboardWindow(WhiteboardSession::ref whiteboardSession) : QWidget() {
 		layout = new QVBoxLayout(this);
 		hLayout = new QHBoxLayout;
 		sidebarLayout = new QVBoxLayout;
@@ -121,7 +122,7 @@ namespace Swift {
 		layout->addLayout(hLayout);
 		this->setLayout(layout);
 
-		whiteboardSession_->onDataReceived.connect(boost::bind(&QtWhiteboardWindow::addItem, this, _1));		
+		setSession(whiteboardSession);
 	}
 
 	void QtWhiteboardWindow::addItem(const std::string& item) {
@@ -222,10 +223,19 @@ namespace Swift {
 	{
 		graphicsView->setMode(GView::Select);
 	}
+
 	void QtWhiteboardWindow::show()
 	{
 		QWidget::show();
 	}
+
+	void QtWhiteboardWindow::setSession(WhiteboardSession::ref session) {
+		whiteboardSession_ = session;
+		whiteboardSession_->onDataReceived.connect(boost::bind(&QtWhiteboardWindow::addItem, this, _1));		
+		whiteboardSession_->onRequestAccepted.connect(boost::bind(&QWidget::show, this));
+		whiteboardSession_->onSessionTerminateReceived.connect(boost::bind(&QtWhiteboardWindow::handleSessionTerminate, this));
+	}
+
 	void QtWhiteboardWindow::handleLastItemChanged(QGraphicsItem* item) {
 		std::string serialized;
 		QGraphicsLineItem* lineItem = qgraphicsitem_cast<QGraphicsLineItem*>(item);
@@ -261,6 +271,25 @@ namespace Swift {
 //			stanzaChannel_->sendMessage(mes);*/
 			whiteboardSession_->sendData(serialized);
 		}
+	}
 
+	void QtWhiteboardWindow::handleSessionTerminate() {
+		QMessageBox box(this);
+		box.setText(tr("Session was terminated by other user"));
+		box.setIcon(QMessageBox::Information);
+		box.exec();
+		hide();
+	}
+
+	void QtWhiteboardWindow::closeEvent(QCloseEvent* event) {
+		QMessageBox box(this);
+		box.setText(tr("Closing window is equivalent closing the session. Are you sure you want to do this?"));
+		box.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
+		box.setIcon(QMessageBox::Question);
+		if (box.exec() == QMessageBox::Yes) {
+			whiteboardSession_->cancel();
+		} else {
+			event->ignore();
+		}
 	}
 }
diff --git a/Swift/QtUI/Whiteboard/QtWhiteboardWindow.h b/Swift/QtUI/Whiteboard/QtWhiteboardWindow.h
index f1a9ed5..4c0a065 100644
--- a/Swift/QtUI/Whiteboard/QtWhiteboardWindow.h
+++ b/Swift/QtUI/Whiteboard/QtWhiteboardWindow.h
@@ -8,6 +8,7 @@
 
 #include <Swift/Controllers/UIInterfaces/WhiteboardWindow.h>
 #include <Swiften/Elements/Message.h>
+#include <Swiften/Whiteboard/WhiteboardSession.h>
 
 #include <QWidget>
 #include <QGraphicsView>
@@ -20,19 +21,19 @@
 #include <QSpinBox>
 #include <QColorDialog>
 #include <QToolButton>
+#include <QCloseEvent>
 
 #include "GView.h"
 
 namespace Swift {
-	class WhiteboardSession;
-
 	class QtWhiteboardWindow : public QWidget, public WhiteboardWindow
 	{
 		Q_OBJECT;
 	public:
-		QtWhiteboardWindow(WhiteboardSession* whiteboardSession);
+		QtWhiteboardWindow(WhiteboardSession::ref whiteboardSession);
 		void addItem(const std::string& item);
 		void show();
+		void setSession(WhiteboardSession::ref session);
 
 	private slots:
 		void changeLineWidth(int i);
@@ -50,6 +51,10 @@ namespace Swift {
 		void handleLastItemChanged(QGraphicsItem* item);
 
 	private:
+		void handleSessionTerminate();
+		void closeEvent(QCloseEvent* event);
+
+	private:
 		QGraphicsScene* scene;
 		GView* graphicsView;
 		QVBoxLayout* layout;
@@ -72,6 +77,6 @@ namespace Swift {
 		QToolButton* polygonButton;
 		QToolButton* selectButton;
 
-		WhiteboardSession* whiteboardSession_;
+		WhiteboardSession::ref whiteboardSession_;
 	};
 }
diff --git a/Swiften/Elements/WhiteboardPayload.h b/Swiften/Elements/WhiteboardPayload.h
index db261ca..3ad1706 100644
--- a/Swiften/Elements/WhiteboardPayload.h
+++ b/Swiften/Elements/WhiteboardPayload.h
@@ -15,7 +15,7 @@ namespace Swift {
 	public:
 		typedef boost::shared_ptr<WhiteboardPayload> ref;
 
-		enum Type {Data, SessionRequest};
+		enum Type {Data, SessionRequest, SessionAccept, SessionTerminate};
 
 		WhiteboardPayload(Type type = WhiteboardPayload::Data) : type_(type) {
 		}
diff --git a/Swiften/Jingle/#JingleSessionImpl.cpp# b/Swiften/Jingle/#JingleSessionImpl.cpp#
new file mode 100644
index 0000000..98c5196
--- /dev/null
+++ b/Swiften/Jingle/#JingleSessionImpl.cpp#
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/Jingle/JingleSessionImpl.h>
+
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Parser/PayloadParsers/JingleParser.h>
+#include <Swiften/Jingle/JingleContentID.h>
+#include <Swiften/Elements/JingleContentPayload.h>
+#include <Swiften/Queries/Request.h>
+#include <Swiften/Queries/GenericRequest.h>
+
+#include <Swiften/Base/Log.h>
+
+#include "Swiften/Serializer/PayloadSerializers/JinglePayloadSerializer.h"
+#include "Swiften/FileTransfer/JingleTransport.h"
+
+namespace Swift {
+
+JingleSessionImpl::JingleSessionImpl(const JID& initiator, const JID& peerJID, const std::string& id, IQRouter* router) : JingleSession(initiator, id), iqRouter(router), peerJID(peerJID) {
+	SWIFT_LOG(debug) << "initiator: " << initiator << ", peerJID: " << peerJID << std::endl;
+}
+
+void JingleSessionImpl::handleIncomingAction(JinglePayload::ref action) {
+	if (action->getAction() == JinglePayload::SessionTerminate) {
+		onSessionTerminateReceived(action->getReason());
+		return;
+	}
+	if (action->getAction() == JinglePayload::SessionInfo) {
+		onSessionInfoReceived(action);
+		return;
+	}
+
+	JingleContentPayload::ref content = action->getPayload<JingleContentPayload>();
+	if (!content) {
+		SWIFT_LOG(debug) << "no content payload!" << std::endl;
+		return;
+	}
+	JingleContentID contentID(content->getName(), content->getCreator());
+	JingleDescription::ref description = content->getDescriptions().empty() ? JingleDescription::ref() : content->getDescriptions()[0];
+	JingleTransportPayload::ref transport = content->getTransports().empty() ? JingleTransportPayload::ref() : content->getTransports()[0];
+	switch(action->getAction()) {
+		case JinglePayload::SessionAccept:
+			onSessionAcceptReceived(contentID, description, transport);
+			return;
+		case JinglePayload::TransportAccept:
+			onTransportAcceptReceived(contentID, transport);
+			return;
+		case JinglePayload::TransportInfo:
+			onTransportInfoReceived(contentID, transport);
+			return;
+		case JinglePayload::TransportReject:
+			onTransportRejectReceived(contentID, transport);
+			return;
+		case JinglePayload::TransportReplace:
+			onTransportReplaceReceived(contentID, transport);
+			return;
+		// following unused Jingle actions
+		case JinglePayload::ContentAccept:
+		case JinglePayload::ContentAdd:
+		case JinglePayload::ContentModify:
+		case JinglePayload::ContentReject:
+		case JinglePayload::ContentRemove:
+		case JinglePayload::DescriptionInfo:
+		case JinglePayload::SecurityInfo:
+
+		// handled elsewhere
+		case JinglePayload::SessionInitiate:
+		case JinglePayload::SessionInfo:
+		case JinglePayload::SessionTerminate:
+
+		case JinglePayload::UnknownAction:
+			return;
+	}
+	std::cerr << "Unhandled Jingle action!!! ACTION: " << action->getAction() << std::endl;
+}
+
+void JingleSessionImpl::sendInitiate(const JingleContentID& id, JingleDescription::ref description, JingleTransportPayload::ref transport) {
+	JinglePayload::ref payload = boost::make_shared<JinglePayload>(JinglePayload::SessionInitiate, getID());
+	payload->setInitiator(getInitiator());
+	JingleContentPayload::ref content = boost::make_shared<JingleContentPayload>();
+	content->setCreator(id.getCreator());
+	content->setName(id.getName());
+	content->addDescription(description);
+	content->addTransport(transport);
+	payload->addPayload(content);
+
+	sendSetRequest(payload);
+}
+
+void JingleSessionImpl::sendTerminate(JinglePayload::Reason::Type reason) {
+	JinglePayload::ref payload = boost::make_shared<JinglePayload>(JinglePayload::SessionTerminate, getID());
+	payload->setReason(JinglePayload::Reason(reason));
+	payload->setInitiator(getInitiator());
+	sendSetRequest(payload);
+}
+
+void JingleSessionImpl::sendInfo(boost::shared_ptr<Payload> info) {
+	JinglePayload::ref payload = boost::make_shared<JinglePayload>(JinglePayload::SessionInfo, getID());
+	payload->addPayload(info);
+
+	sendSetRequest(payload);
+}
+
+void JingleSessionImpl::sendAccept(const JingleContentID& id, JingleDescription::ref description, JingleTransportPayload::ref transPayload) {
+	JinglePayload::ref payload = createPayload();
+	
+	JingleContentPayload::ref content = boost::make_shared<JingleContentPayload>();
+	content->setCreator(id.getCreator());
+	content->setName(id.getName());
+	content->addTransport(transPayload);
+	content->addDescription(description);
+	payload->setAction(JinglePayload::SessionAccept);
+	payload->addPayload(content);
+	
+	// put into IQ:set and send it away
+	sendSetRequest(payload);
+}
+
+
+void JingleSessionImpl::sendTransportAccept(const JingleContentID& id, JingleTransportPayload::ref transPayload) {
+	JinglePayload::ref payload = createPayload();
+
+	JingleContentPayload::ref content = boost::make_shared<JingleContentPayload>();
+	content->setCreator(id.getCreator());
+	content->setName(id.getName());
+	content->addTransport(transPayload);
+	payload->setAction(JinglePayload::TransportAccept);
+	payload->addPayload(content);
+
+	// put into IQ:set and send it away
+	sendSetRequest(payload);
+}
+
+void JingleSessionImpl::sendTransportInfo(const JingleContentID& id, JingleTransportPayload::ref transPayload) {
+	JinglePayload::ref payload = createPayload();
+
+	JingleContentPayload::ref content = boost::make_shared<JingleContentPayload>();
+	content->setCreator(id.getCreator());
+	content->setName(id.getName());
+	content->addTransport(transPayload);
+	payload->setAction(JinglePayload::TransportInfo);
+	payload->addPayload(content);
+
+	sendSetRequest(payload);
+}
+
+void JingleSessionImpl::sendTransportReject(const JingleContentID& /* id */, JingleTransportPayload::ref /* transPayload */) {
+	SWIFT_LOG(debug) << "NOT IMPLEMENTED YET!!!!" << std::endl;
+}
+
+void JingleSessionImpl::sendTransportReplace(const JingleContentID& id, JingleTransportPayload::ref transPayload) {
+	JinglePayload::ref payload = createPayload();
+
+	JingleContentPayload::ref content = boost::make_shared<JingleContentPayload>();
+	content->setCreator(id.getCreator());
+	content->setName(id.getName());
+	content->addTransport(transPayload);
+	payload->setAction(JinglePayload::TransportReplace);
+	payload->addContent(content);
+
+	sendSetRequest(payload);
+}
+
+
+void JingleSessionImpl::sendSetRequest(JinglePayload::ref payload) {
+	boost::shared_ptr<GenericRequest<JinglePayload> > request = boost::make_shared<GenericRequest<JinglePayload> >(IQ::Set, peerJID, payload, iqRouter);
+	request->send();
+}
+
+
+JinglePayload::ref JingleSessionImpl::createPayload() const {
+	JinglePayload::ref payload = boost::make_shared<JinglePayload>();
+	payload->setSessionID(getID());
+	payload->setInitiator(getInitiator());
+	return payload;
+}
+
+
+
+}
diff --git a/Swiften/Parser/PayloadParsers/WhiteboardParser.cpp b/Swiften/Parser/PayloadParsers/WhiteboardParser.cpp
index 94b67e5..4306497 100644
--- a/Swiften/Parser/PayloadParsers/WhiteboardParser.cpp
+++ b/Swiften/Parser/PayloadParsers/WhiteboardParser.cpp
@@ -5,19 +5,16 @@
  */
 
 #include <Swiften/Parser/PayloadParsers/WhiteboardParser.h>
+#include <boost/optional.hpp>
 
 namespace Swift {
 	WhiteboardParser::WhiteboardParser() : level_(0) {
 	}
+
 	void WhiteboardParser::handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) {
 		if (level_ == 0) {
-			std::string type = attributes.getAttribute("type");
-			if (type.empty()) {
-				getPayloadInternal()->setType(WhiteboardPayload::Data);
-			}
-			else if (type == "request") {
-				getPayloadInternal()->setType(WhiteboardPayload::SessionRequest);
-			}
+//			std::string type = attributes.getAttribute("type");
+			getPayloadInternal()->setType(stringToType(attributes.getAttributeValue("type").get_value_or("")));
 		}
 		++level_;
 	}
@@ -32,4 +29,16 @@ namespace Swift {
 	void WhiteboardParser::handleCharacterData(const std::string& data) {
 		data_ += data;
 	}
+
+	WhiteboardPayload::Type WhiteboardParser::stringToType(const std::string& type) const {
+		if (type.empty()) {
+			return WhiteboardPayload::Data;
+		} else if (type == "session-request") {
+			return WhiteboardPayload::SessionRequest;
+		} else if (type == "session-accept") {
+			return WhiteboardPayload::SessionAccept;
+		} else if (type == "session-terminate") {
+			return WhiteboardPayload::SessionTerminate;
+		}
+	}
 }
diff --git a/Swiften/Parser/PayloadParsers/WhiteboardParser.h b/Swiften/Parser/PayloadParsers/WhiteboardParser.h
index 265e12d..faa698b 100644
--- a/Swiften/Parser/PayloadParsers/WhiteboardParser.h
+++ b/Swiften/Parser/PayloadParsers/WhiteboardParser.h
@@ -17,6 +17,10 @@ namespace Swift {
 		virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes);
 		virtual void handleEndElement(const std::string& element, const std::string&);
 		virtual void handleCharacterData(const std::string& data);
+
+	private:
+		WhiteboardPayload::Type stringToType(const std::string& type) const;
+
 	private:
 		int level_;
 		std::string data_;
diff --git a/Swiften/SConscript b/Swiften/SConscript
index 9b31304..1fa47ca 100644
--- a/Swiften/SConscript
+++ b/Swiften/SConscript
@@ -184,6 +184,7 @@ if env["SCONS_STAGE"] == "build" :
 			"Serializer/PayloadSerializers/StreamInitiationFileInfoSerializer.cpp",
 			"Serializer/PayloadSerializers/DeliveryReceiptSerializer.cpp",
 			"Serializer/PayloadSerializers/DeliveryReceiptRequestSerializer.cpp",
+			"Serializer/PayloadSerializers/WhiteboardSerializer.cpp",
 			"Serializer/PresenceSerializer.cpp",
 			"Serializer/StanzaSerializer.cpp",
 			"Serializer/StreamErrorSerializer.cpp",
@@ -202,6 +203,8 @@ if env["SCONS_STAGE"] == "build" :
 			"StringCodecs/Hexify.cpp",
 			"Whiteboard/WhiteboardResponder.cpp",
 			"Whiteboard/WhiteboardSession.cpp",
+			"Whiteboard/IncomingWhiteboardSession.cpp",
+			"Whiteboard/OutgoingWhiteboardSession.cpp",
 			"Whiteboard/WhiteboardSessionManager.cpp",
 		]
 
diff --git a/Swiften/Serializer/PayloadSerializers/WhiteboardSerializer.cpp b/Swiften/Serializer/PayloadSerializers/WhiteboardSerializer.cpp
new file mode 100644
index 0000000..578b0ab
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/WhiteboardSerializer.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2012 Mateusz Piękos
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <Swiften/Serializer/PayloadSerializers/WhiteboardSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+#include <Swiften/Serializer/XML/XMLTextNode.h>
+
+namespace Swift {
+	std::string WhiteboardSerializer::serializePayload(boost::shared_ptr<WhiteboardPayload> payload) const {
+		XMLElement element("wb");
+		element.addNode(XMLTextNode::ref(new XMLTextNode(payload->getData())));
+		element.setAttribute("type", typeToString(payload->getType()));
+		return element.serialize();
+	}
+
+	std::string WhiteboardSerializer::typeToString(WhiteboardPayload::Type type) const {
+		if(type == WhiteboardPayload::Data) {
+			return "";
+		} else if (type == WhiteboardPayload::SessionRequest) {
+			return "session-request";
+		} else if (type == WhiteboardPayload::SessionAccept) {
+			return "session-accept";
+		} else if (type == WhiteboardPayload::SessionTerminate) {
+			return "session-terminate";
+		}
+	}
+}
diff --git a/Swiften/Serializer/PayloadSerializers/WhiteboardSerializer.h b/Swiften/Serializer/PayloadSerializers/WhiteboardSerializer.h
index 9b7f905..975d537 100644
--- a/Swiften/Serializer/PayloadSerializers/WhiteboardSerializer.h
+++ b/Swiften/Serializer/PayloadSerializers/WhiteboardSerializer.h
@@ -12,13 +12,9 @@
 namespace Swift {
 	class WhiteboardSerializer : public GenericPayloadSerializer<WhiteboardPayload> {
 	public:
-		std::string serializePayload(boost::shared_ptr<WhiteboardPayload> payload) const {
-			XMLElement element("wb");
-			element.addNode(XMLTextNode::ref(new XMLTextNode(payload->getData())));
-			if (payload->getType() == WhiteboardPayload::SessionRequest) {
-				element.setAttribute("type", "request");
-			}
-			return element.serialize();
-		}
+		std::string serializePayload(boost::shared_ptr<WhiteboardPayload> payload) const;
+
+	private:
+		std::string typeToString(WhiteboardPayload::Type type) const;
 	};
 }
diff --git a/Swiften/Whiteboard/IncomingWhiteboardSession.cpp b/Swiften/Whiteboard/IncomingWhiteboardSession.cpp
new file mode 100644
index 0000000..92a86a1
--- /dev/null
+++ b/Swiften/Whiteboard/IncomingWhiteboardSession.cpp
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2012 Mateusz Piękos
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <Swiften/Whiteboard/IncomingWhiteboardSession.h>
+#include <Swiften/Elements/WhiteboardPayload.h>
+
+namespace Swift {
+	IncomingWhiteboardSession::IncomingWhiteboardSession(const JID& jid, IQRouter* router) : WhiteboardSession(jid, router) {
+	}
+
+	IncomingWhiteboardSession::~IncomingWhiteboardSession() {
+	}
+
+	void IncomingWhiteboardSession::accept() {
+		boost::shared_ptr<WhiteboardPayload> payload = boost::make_shared<WhiteboardPayload>(WhiteboardPayload::SessionAccept);
+		boost::shared_ptr<GenericRequest<WhiteboardPayload> > request = boost::make_shared<GenericRequest<WhiteboardPayload> >(IQ::Set, toJID_, payload, router_);
+		request->send();
+	}
+}
diff --git a/Swiften/Whiteboard/IncomingWhiteboardSession.h b/Swiften/Whiteboard/IncomingWhiteboardSession.h
new file mode 100644
index 0000000..3b15a49
--- /dev/null
+++ b/Swiften/Whiteboard/IncomingWhiteboardSession.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2012 Mateusz Piękos
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <Swiften/Whiteboard/WhiteboardSession.h>
+
+#include <boost/shared_ptr.hpp>
+
+#pragma once
+
+namespace Swift {
+	class IncomingWhiteboardSession : public WhiteboardSession {
+	public:
+		typedef boost::shared_ptr<IncomingWhiteboardSession> ref;
+
+	public:
+		IncomingWhiteboardSession(const JID& jid, IQRouter* router);
+		~IncomingWhiteboardSession();
+
+		void accept();
+	};
+}
diff --git a/Swiften/Whiteboard/OutgoingWhiteboardSession.cpp b/Swiften/Whiteboard/OutgoingWhiteboardSession.cpp
new file mode 100644
index 0000000..2693fcd
--- /dev/null
+++ b/Swiften/Whiteboard/OutgoingWhiteboardSession.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2012 Mateusz Piękos
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <Swiften/Whiteboard/OutgoingWhiteboardSession.h>
+
+#include <boost/bind.hpp>
+#include <Swiften/Elements/WhiteboardPayload.h>
+
+namespace Swift {
+	OutgoingWhiteboardSession::OutgoingWhiteboardSession(const JID& jid, IQRouter* router) : WhiteboardSession(jid, router) {
+	}
+
+	OutgoingWhiteboardSession::~OutgoingWhiteboardSession() {
+	}
+
+	void OutgoingWhiteboardSession::startSession() {
+		boost::shared_ptr<WhiteboardPayload> payload = boost::make_shared<WhiteboardPayload>(WhiteboardPayload::SessionRequest);
+		boost::shared_ptr<GenericRequest<WhiteboardPayload> > request = boost::make_shared<GenericRequest<WhiteboardPayload> >(IQ::Set, toJID_, payload, router_);
+		request->send();
+	}
+}
diff --git a/Swiften/Whiteboard/OutgoingWhiteboardSession.h b/Swiften/Whiteboard/OutgoingWhiteboardSession.h
new file mode 100644
index 0000000..dfbd200
--- /dev/null
+++ b/Swiften/Whiteboard/OutgoingWhiteboardSession.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2012 Mateusz Piękos
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Whiteboard/WhiteboardSession.h>
+
+#include <boost/shared_ptr.hpp>
+#include <Swiften/Queries/GenericRequest.h>
+
+namespace Swift {
+	class OutgoingWhiteboardSession : public WhiteboardSession {
+	public:
+		typedef boost::shared_ptr<OutgoingWhiteboardSession> ref;
+
+	public:
+		OutgoingWhiteboardSession(const JID& jid, IQRouter* router);
+		virtual ~OutgoingWhiteboardSession();
+		void startSession();
+	};
+}
diff --git a/Swiften/Whiteboard/WhiteboardResponder.cpp b/Swiften/Whiteboard/WhiteboardResponder.cpp
index 8a1b290..c947aec 100644
--- a/Swiften/Whiteboard/WhiteboardResponder.cpp
+++ b/Swiften/Whiteboard/WhiteboardResponder.cpp
@@ -7,6 +7,7 @@
 #include <Swiften/Whiteboard/WhiteboardResponder.h>
 
 #include <Swiften/Whiteboard/WhiteboardSessionManager.h>
+#include <Swiften/Whiteboard/IncomingWhiteboardSession.h>
 #include <Swiften/Whiteboard/WhiteboardSession.h>
 #include <Swiften/Queries/IQRouter.h>
 
@@ -16,27 +17,20 @@ namespace Swift {
 
 	bool WhiteboardResponder::handleSetRequest(const JID& from, const JID& to, const std::string& id, boost::shared_ptr<WhiteboardPayload> payload) {
 		if (payload->getType() == WhiteboardPayload::SessionRequest) {
-			sessionManager_->onRequestReceived(from);
-			sessionRequests_[from] = id;
+			if (sessionManager_->getSession(from.toBare())) {
+				sendError(from, id, ErrorPayload::Conflict, ErrorPayload::Cancel);
+			} else {
+				sendResponse(from, id, boost::shared_ptr<WhiteboardPayload>());
+				IncomingWhiteboardSession::ref session = boost::make_shared<IncomingWhiteboardSession>(from, router_);
+				sessionManager_->handleIncomingSession(session);
+			}
 		} else {
 			sendResponse(from, id, boost::shared_ptr<WhiteboardPayload>());
-			WhiteboardSession* session = sessionManager_->getSession(from.toBare());
+			WhiteboardSession::ref session = sessionManager_->getSession(from.toBare());
 			if (session != NULL) {
 				session->handleIncomingAction(payload);
 			}
 		}
 		return true;
 	}
-
-	void WhiteboardResponder::sendRequestResponse(const JID& contact, bool accepted) {
-		if (sessionRequests_.find(contact) == sessionRequests_.end()) {
-			return;
-		}
-		if (accepted ) {
-			sendResponse(contact, sessionRequests_[contact], boost::shared_ptr<WhiteboardPayload>());
-		} else {
-			sendError(contact, sessionRequests_[contact], ErrorPayload::Conflict, ErrorPayload::Cancel);
-		}
-		sessionRequests_.erase(contact);
-	}
 }
diff --git a/Swiften/Whiteboard/WhiteboardResponder.h b/Swiften/Whiteboard/WhiteboardResponder.h
index d1b712d..b171ef3 100644
--- a/Swiften/Whiteboard/WhiteboardResponder.h
+++ b/Swiften/Whiteboard/WhiteboardResponder.h
@@ -17,10 +17,8 @@ namespace Swift {
 	public:
 		WhiteboardResponder(WhiteboardSessionManager* sessionManager, IQRouter* router);
 		bool handleSetRequest(const JID& from, const JID& to, const std::string& id, boost::shared_ptr<WhiteboardPayload> payload);
-		void sendRequestResponse(const JID& contact, bool accepted);
 
 	private:
-		std::map<JID, std::string> sessionRequests_;
 		WhiteboardSessionManager* sessionManager_;
 		IQRouter* router_;
 	};
diff --git a/Swiften/Whiteboard/WhiteboardSession.cpp b/Swiften/Whiteboard/WhiteboardSession.cpp
index 859f2cd..bfef7c3 100644
--- a/Swiften/Whiteboard/WhiteboardSession.cpp
+++ b/Swiften/Whiteboard/WhiteboardSession.cpp
@@ -6,7 +6,6 @@
 
 #include <Swiften/Whiteboard/WhiteboardSession.h>
 
-#include <boost/bind.hpp>
 #include <boost/smart_ptr/make_shared.hpp>
 #include <Swiften/Elements/WhiteboardPayload.h>
 #include <Swiften/Elements/ErrorPayload.h>
@@ -17,8 +16,23 @@ namespace Swift {
 	WhiteboardSession::WhiteboardSession(const JID& jid, IQRouter* router) : toJID_(jid), router_(router) {
 	}
 
+	WhiteboardSession::~WhiteboardSession() {
+	}
+
 	void WhiteboardSession::handleIncomingAction(boost::shared_ptr<WhiteboardPayload> payload) {
-		onDataReceived(payload->getData());
+		if (payload->getType() == WhiteboardPayload::SessionTerminate) {
+			onSessionTerminateReceived(toJID_);
+			return;
+		}
+
+		switch (payload->getType()) {
+		case WhiteboardPayload::Data:
+			onDataReceived(payload->getData());
+			break;
+		case WhiteboardPayload::SessionAccept:
+			onRequestAccepted(toJID_);
+			break;
+		}
 	}
 
 	void WhiteboardSession::sendData(const std::string& data) {
@@ -28,17 +42,14 @@ namespace Swift {
 		request->send();
 	}
 
-	void WhiteboardSession::sendSessionRequest() {
-		boost::shared_ptr<WhiteboardPayload> payload = boost::make_shared<WhiteboardPayload>(WhiteboardPayload::SessionRequest);
-		sessionRequest = new GenericRequest<WhiteboardPayload>(IQ::Set, toJID_, payload, router_);
-		sessionRequest->onResponse.connect(boost::bind(&WhiteboardSession::handleSessionRequestResponse, this, _1, _2));
-		sessionRequest->send();
+	void WhiteboardSession::cancel() {
+		boost::shared_ptr<WhiteboardPayload> payload = boost::make_shared<WhiteboardPayload>(WhiteboardPayload::SessionTerminate);
+		boost::shared_ptr<GenericRequest<WhiteboardPayload> > request = boost::make_shared<GenericRequest<WhiteboardPayload> >(IQ::Set, toJID_, payload, router_);
+		request->send();
+		onSessionCancelled(toJID_);
 	}
 
-	void WhiteboardSession::handleSessionRequestResponse(boost::shared_ptr<WhiteboardPayload> whiteboardPayload, boost::shared_ptr<ErrorPayload> errorPayload) {
-		if (errorPayload.get() == 0) {
-			onRequestAccepted(toJID_, this);
-		}
-		delete sessionRequest;
+	const JID& WhiteboardSession::getTo() const {
+		return toJID_;
 	}
 }
diff --git a/Swiften/Whiteboard/WhiteboardSession.h b/Swiften/Whiteboard/WhiteboardSession.h
index 14d6778..7aa67ca 100644
--- a/Swiften/Whiteboard/WhiteboardSession.h
+++ b/Swiften/Whiteboard/WhiteboardSession.h
@@ -19,19 +19,24 @@ namespace Swift {
 
 	class WhiteboardSession {
 	public:
+		typedef boost::shared_ptr<WhiteboardSession> ref;
+
+	public:
 		WhiteboardSession(const JID& jid, IQRouter* router);
+		virtual ~WhiteboardSession();
 		void handleIncomingAction(boost::shared_ptr<WhiteboardPayload> payload);
 		void sendData(const std::string& data);
-		void sendSessionRequest();
-		void handleSessionRequestResponse(boost::shared_ptr<WhiteboardPayload> whiteboardPayload, boost::shared_ptr<ErrorPayload> errorPayload);
+		void cancel();
+		const JID& getTo() const;
 
 	public:
 		boost::signal< void(const std::string& data)> onDataReceived;
-		boost::signal< void(const JID& contact, WhiteboardSession* session)> onRequestAccepted;
+		boost::signal< void(const JID& contact)> onSessionTerminateReceived;
+		boost::signal< void(const JID& contact)> onRequestAccepted;
+		boost::signal< void(const JID& contact)> onSessionCancelled;
 
-	private:
+	protected:
 		JID toJID_;
 		IQRouter* router_;
-		GenericRequest<WhiteboardPayload>* sessionRequest;
 	};
 }
diff --git a/Swiften/Whiteboard/WhiteboardSessionManager.cpp b/Swiften/Whiteboard/WhiteboardSessionManager.cpp
index ccbc4d7..eae9e5b 100644
--- a/Swiften/Whiteboard/WhiteboardSessionManager.cpp
+++ b/Swiften/Whiteboard/WhiteboardSessionManager.cpp
@@ -9,7 +9,6 @@
 
 #include <boost/bind.hpp>
 #include <Swiften/Queries/IQRouter.h>
-#include <Swiften/Whiteboard/WhiteboardSession.h>
 #include <Swiften/Whiteboard/WhiteboardResponder.h>
 #include <Swiften/Presence/PresenceOracle.h>
 
@@ -24,48 +23,53 @@ namespace Swift {
 		delete responder;
 	}
 
-	WhiteboardSession* WhiteboardSessionManager::getSession(const JID& to) {
+	WhiteboardSession::ref WhiteboardSessionManager::getSession(const JID& to) {
 		if (sessions_.find(to.toBare()) == sessions_.end()) {
-			return NULL;
+			return boost::shared_ptr<WhiteboardSession>();
 		}
 		return sessions_[to.toBare()];
 	}
 
-	WhiteboardSession* WhiteboardSessionManager::createSession(const JID& to) {
+	OutgoingWhiteboardSession::ref WhiteboardSessionManager::createOutgoingSession(const JID& to) {
 		JID fullJID = to;
 		if (fullJID.isBare()) {
 			fullJID = getFullJID(fullJID);
 		}
-		WhiteboardSession* session = new WhiteboardSession(fullJID, router_);
+		OutgoingWhiteboardSession::ref session = boost::make_shared<OutgoingWhiteboardSession>(fullJID, router_);
 		sessions_[to.toBare()] = session;
+		session->onSessionTerminateReceived.connect(boost::bind(&WhiteboardSessionManager::handleSessionTerminate, this, _1));
+		session->onSessionCancelled.connect(boost::bind(&WhiteboardSessionManager::handleSessionCancelled, this, _1));
 		return session;
 	}
 
-	WhiteboardSession* WhiteboardSessionManager::acceptSession(const JID& to) {
-		responder->sendRequestResponse(to, true);
-		WhiteboardSession* session = getSession(to);
-		if (session == NULL) {
-			return createSession(to);
+	WhiteboardSession::ref WhiteboardSessionManager::requestSession(const JID& to) {
+		WhiteboardSession::ref session = getSession(to);
+		if (!session) {
+			OutgoingWhiteboardSession::ref outgoingSession = createOutgoingSession(to);
+			outgoingSession->startSession();
+			return outgoingSession;
+		} else {
+			return session;
 		}
-		return session;
 	}
 
-	void WhiteboardSessionManager::requestSession(const JID& to) {
-		WhiteboardSession* session = createSession(to);
-		session->onRequestAccepted.connect(boost::bind(&WhiteboardSessionManager::handleRequestAccepted, this, _1, _2));
-		session->sendSessionRequest();
+	void WhiteboardSessionManager::handleIncomingSession(IncomingWhiteboardSession::ref session) {
+		sessions_[session->getTo().toBare()] = session;
+		session->onSessionTerminateReceived.connect(boost::bind(&WhiteboardSessionManager::handleSessionTerminate, this, _1));
+		session->onSessionCancelled.connect(boost::bind(&WhiteboardSessionManager::handleSessionCancelled, this, _1));
+		onRequestReceived(session->getTo());
 	}
 
-	void WhiteboardSessionManager::cancelSession(const JID& to) {
-		responder->sendRequestResponse(to, false);
+	JID WhiteboardSessionManager::getFullJID(const JID& bareJID) {
+		std::vector<Presence::ref> presences = presenceOracle_->getAllPresence(bareJID);
+		return presences[0]->getFrom();
 	}
 
-	void WhiteboardSessionManager::handleRequestAccepted(const JID& contact, WhiteboardSession* session) {
-		onRequestAccepted(contact, session);
+	void WhiteboardSessionManager::handleSessionTerminate(const JID& contact) {
+		sessions_.erase(contact.toBare());
 	}
 
-	JID WhiteboardSessionManager::getFullJID(const JID& bareJID) {
-		std::vector<Presence::ref> presences = presenceOracle_->getAllPresence(bareJID);
-		return presences[0]->getFrom();
+	void WhiteboardSessionManager::handleSessionCancelled(const JID& contact) {
+		sessions_.erase(contact.toBare());
 	}
 }
diff --git a/Swiften/Whiteboard/WhiteboardSessionManager.h b/Swiften/Whiteboard/WhiteboardSessionManager.h
index 3cd3aab..d2a59e0 100644
--- a/Swiften/Whiteboard/WhiteboardSessionManager.h
+++ b/Swiften/Whiteboard/WhiteboardSessionManager.h
@@ -11,34 +11,35 @@
 #include <Swiften/Queries/IQRouter.h>
 #include <Swiften/JID/JID.h>
 #include <Swiften/Base/boost_bsignals.h>
+#include <Swiften/Whiteboard/WhiteboardSession.h>
+#include <Swiften/Whiteboard/IncomingWhiteboardSession.h>
+#include <Swiften/Whiteboard/OutgoingWhiteboardSession.h>
 
 namespace Swift {
 	class IQRouter;
-	class WhiteboardSession;
 	class WhiteboardResponder;
 	class PresenceOracle;
 
 	class WhiteboardSessionManager {
+		friend class WhiteboardResponder;
 	public:
 		WhiteboardSessionManager(IQRouter* router, PresenceOracle* presenceOracle);
 		~WhiteboardSessionManager();
-
-		WhiteboardSession* getSession(const JID& to);
-		WhiteboardSession* acceptSession(const JID& to);
-		void requestSession(const JID& to);
-		void cancelSession(const JID& to);
-		void handleRequestAccepted(const JID& contact, WhiteboardSession* session);
+		WhiteboardSession::ref getSession(const JID& to);
+		WhiteboardSession::ref requestSession(const JID& to);
 
 	public:
 		boost::signal< void (const JID&)> onRequestReceived;
-		boost::signal< void (const JID&, WhiteboardSession*)> onRequestAccepted;
 
 	private:
 		JID getFullJID(const JID& bareJID);
-		WhiteboardSession* createSession(const JID& to);
+		OutgoingWhiteboardSession::ref createOutgoingSession(const JID& to);
+		void handleIncomingSession(IncomingWhiteboardSession::ref session);
+		void handleSessionTerminate(const JID& contact);
+		void handleSessionCancelled(const JID& contact);
 
 	private:
-		std::map<JID, WhiteboardSession*> sessions_;
+		std::map<JID, boost::shared_ptr<WhiteboardSession> > sessions_;
 		IQRouter* router_;
 		PresenceOracle* presenceOracle_;
 		WhiteboardResponder* responder;
-- 
cgit v0.10.2-6-g49f6