From bb37c9f89e4135f3128fc98c23ea19eea945c4cd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Sat, 26 Mar 2011 11:09:46 +0100
Subject: Jingle refactoring.


diff --git a/Swiften/Base/ByteArray.cpp b/Swiften/Base/ByteArray.cpp
index 928e145..c3869fc 100644
--- a/Swiften/Base/ByteArray.cpp
+++ b/Swiften/Base/ByteArray.cpp
@@ -9,6 +9,10 @@
 #include <fstream>
 
 std::ostream& operator<<(std::ostream& os, const Swift::ByteArray& s) {
+	return operator<<(os, s.getDataVector());
+}
+
+std::ostream& operator<<(std::ostream& os, const std::vector<unsigned char>& s) {
 	std::ios::fmtflags oldFlags = os.flags(); 
 	os << std::hex;
 	for (Swift::ByteArray::const_iterator i = s.begin(); i != s.end(); ++i) {
@@ -37,4 +41,35 @@ void ByteArray::readFromFile(const std::string& file) {
 	input.close();
 }
 
+std::vector<unsigned char> ByteArray::create(const std::string& s) {
+	return std::vector<unsigned char>(s.begin(), s.end());
+}
+
+std::vector<unsigned char> ByteArray::create(const char* c) {
+	std::vector<unsigned char> data;
+	while (*c) {
+		data.push_back(static_cast<unsigned char>(*c));
+		++c;
+	}
+	return data;
+}
+
+std::vector<unsigned char> ByteArray::create(const char* c, size_t n) {
+	std::vector<unsigned char> data;
+	if (n > 0) {
+		data.resize(n);
+		memcpy(&data[0], c, n);
+	}
+	return data;
+}
+
+std::vector<unsigned char> ByteArray::create(const unsigned char* c, size_t n) {
+	std::vector<unsigned char> data;
+	if (n > 0) {
+		data.resize(n);
+		memcpy(&data[0], c, n);
+	}
+	return data;
+}
+
 }
diff --git a/Swiften/Base/ByteArray.h b/Swiften/Base/ByteArray.h
index 2059052..9e7a928 100644
--- a/Swiften/Base/ByteArray.h
+++ b/Swiften/Base/ByteArray.h
@@ -130,9 +130,19 @@ namespace Swift {
 				data_.clear();
 			}
 
+			const std::vector<unsigned char>& getDataVector() const {
+				return data_;
+			}
+
+			static std::vector<unsigned char> create(const std::string& s);
+			static std::vector<unsigned char> create(const char* c);
+			static std::vector<unsigned char> create(const unsigned char* c, size_t n);
+			static std::vector<unsigned char> create(const char* c, size_t n);
+
 		private:
 			std::vector<unsigned char> data_;
 	};
 }
 
 std::ostream& operator<<(std::ostream& os, const Swift::ByteArray& s);
+std::ostream& operator<<(std::ostream& os, const std::vector<unsigned char>& s);
diff --git a/Swiften/Client/DummyStanzaChannel.h b/Swiften/Client/DummyStanzaChannel.h
index b9f05c3..306e2b4 100644
--- a/Swiften/Client/DummyStanzaChannel.h
+++ b/Swiften/Client/DummyStanzaChannel.h
@@ -56,6 +56,22 @@ namespace Swift {
 				return iqStanza && iqStanza->getType() == type && iqStanza->getTo() == jid && iqStanza->getPayload<T>();
 			}
 
+			bool isResultAtIndex(size_t index, const std::string& id) {
+				if (index >= sentStanzas.size()) {
+					return false;
+				}
+				boost::shared_ptr<IQ> iqStanza = boost::dynamic_pointer_cast<IQ>(sentStanzas[index]);
+				return iqStanza && iqStanza->getType() == IQ::Result && iqStanza->getID() == id;
+			}
+
+			bool isErrorAtIndex(size_t index, const std::string& id) {
+				if (index >= sentStanzas.size()) {
+					return false;
+				}
+				boost::shared_ptr<IQ> iqStanza = boost::dynamic_pointer_cast<IQ>(sentStanzas[index]);
+				return iqStanza && iqStanza->getType() == IQ::Error && iqStanza->getID() == id;
+			}
+
 			template<typename T> boost::shared_ptr<T> getStanzaAtIndex(size_t index) {
 				if (sentStanzas.size() <= index) {
 					return boost::shared_ptr<T>();
diff --git a/Swiften/Elements/IBB.h b/Swiften/Elements/IBB.h
index faee71d..8138e83 100644
--- a/Swiften/Elements/IBB.h
+++ b/Swiften/Elements/IBB.h
@@ -6,11 +6,11 @@
 
 #pragma once
 
-#include <boost/shared_ptr.hpp>
 #include <string>
+#include <vector>
+#include <boost/shared_ptr.hpp>
 
-#include "Swiften/Base/ByteArray.h"
-#include "Swiften/Elements/Payload.h"
+#include <Swiften/Elements/Payload.h>
 
 namespace Swift {
 	class IBB : public Payload {
@@ -36,7 +36,7 @@ namespace Swift {
 				return result;
 			}
 
-			static IBB::ref createIBBData(const std::string& streamID, int sequenceNumber, const ByteArray& data) {
+			static IBB::ref createIBBData(const std::string& streamID, int sequenceNumber, const std::vector<unsigned char>& data) {
 				IBB::ref result(new IBB(Data, streamID));
 				result->setSequenceNumber(sequenceNumber);
 				result->setData(data);
@@ -71,11 +71,11 @@ namespace Swift {
 				return streamID;
 			}
 
-			const ByteArray& getData() const {
+			const std::vector<unsigned char>& getData() const {
 				return data;
 			}
 
-			void setData(const ByteArray& data) {
+			void setData(const std::vector<unsigned char>& data) {
 				this->data = data;
 			}
 
@@ -98,7 +98,7 @@ namespace Swift {
 		private:
 			Action action;
 			std::string streamID;
-			ByteArray data;
+			std::vector<unsigned char> data;
 			StanzaType stanzaType;
 			int blockSize;
 			int sequenceNumber;
diff --git a/Swiften/Elements/JingleContent.h b/Swiften/Elements/JingleContent.h
deleted file mode 100644
index 97b071f..0000000
--- a/Swiften/Elements/JingleContent.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (c) 2011 Remko Tronçon
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
- */
-
-#pragma once
-
-#include <vector>
-#include <boost/optional.hpp>
-#include <string>
-
-#include <Swiften/JID/JID.h>
-#include <Swiften/Elements/Payload.h>
-#include <Swiften/Elements/JingleDescription.h>
-#include <Swiften/Elements/JingleTransport.h>
-
-namespace Swift {
-	class JingleContent : public Payload {
-		public:
-			typedef boost::shared_ptr<JingleContent> ref;
-
-			enum Creator {
-				InitiatorCreator,
-				ResponderCreator,
-			};
-
-			/*enum Senders {
-				NoSenders,
-				InitiatorSender,
-				ResponderSender,
-				BothSenders,
-			};*/
-
-			void setCreator(Creator creator) {
-				this->creator = creator;
-			}
-
-			void setName(const std::string& name) {
-				this->name = name;
-			}
-
-			const std::vector<JingleDescription::ref>& getDescriptions() const {
-				return descriptions;
-			}
-
-			void addDescription(JingleDescription::ref description) {
-				descriptions.push_back(description);
-			}
-
-			const std::vector<boost::shared_ptr<JingleTransportPayload> >& getTransports() const {
-				return transports;
-			}
-
-			void addTransport(boost::shared_ptr<JingleTransportPayload>  transport) {
-				transports.push_back(transport);
-			}
-
-			template<typename T>
-			boost::shared_ptr<T> getDescription() const {
-				for (size_t i = 0; i < descriptions.size(); ++i) {
-					boost::shared_ptr<T> result(boost::dynamic_pointer_cast<T>(descriptions[i]));
-					if (result) {
-						return result;
-					}
-				}
-				return boost::shared_ptr<T>();
-			}
-
-			template<typename T>
-			boost::shared_ptr<T> getTransport() const {
-				for (size_t i = 0; i < transports.size(); ++i) {
-					boost::shared_ptr<T> result(boost::dynamic_pointer_cast<T>(transports[i]));
-					if (result) {
-						return result;
-					}
-				}
-				return boost::shared_ptr<T>();
-			}
-
-		private:
-			Creator creator;
-			std::string name;
-			//Senders senders;
-			std::vector<JingleDescription::ref> descriptions;
-<<<<<<< HEAD:Swiften/Elements/JingleContent.h
-			std::vector<JingleTransport::ref> transports;
-=======
-			std::vector<boost::shared_ptr<JingleTransportPayload> > transports;
->>>>>>> 7c05f3f... Cleaned up headers.:Swiften/Elements/JingleContentPayload.h
-	};
-}
diff --git a/Swiften/Elements/JingleContentPayload.h b/Swiften/Elements/JingleContentPayload.h
new file mode 100644
index 0000000..c44a806
--- /dev/null
+++ b/Swiften/Elements/JingleContentPayload.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <vector>
+#include <boost/optional.hpp>
+#include <string>
+
+#include <Swiften/JID/JID.h>
+#include <Swiften/Elements/Payload.h>
+#include <Swiften/Elements/JingleDescription.h>
+#include <Swiften/Elements/JingleTransportPayload.h>
+
+namespace Swift {
+	class JingleContentPayload : public Payload {
+		public:
+			typedef boost::shared_ptr<JingleContentPayload> ref;
+
+			enum Creator {
+				InitiatorCreator,
+				ResponderCreator,
+			};
+
+			/*enum Senders {
+				NoSenders,
+				InitiatorSender,
+				ResponderSender,
+				BothSenders,
+			};*/
+
+			Creator getCreator() const {
+				return creator;
+			}
+
+			void setCreator(Creator creator) {
+				this->creator = creator;
+			}
+
+			const std::string& getName() const {
+				return name;
+			}
+
+			void setName(const std::string& name) {
+				this->name = name;
+			}
+
+			const std::vector<JingleDescription::ref>& getDescriptions() const {
+				return descriptions;
+			}
+
+			void addDescription(JingleDescription::ref description) {
+				descriptions.push_back(description);
+			}
+
+			const std::vector<boost::shared_ptr<JingleTransportPayload> >& getTransports() const {
+				return transports;
+			}
+
+			void addTransport(boost::shared_ptr<JingleTransportPayload>  transport) {
+				transports.push_back(transport);
+			}
+
+			template<typename T>
+			boost::shared_ptr<T> getDescription() const {
+				for (size_t i = 0; i < descriptions.size(); ++i) {
+					boost::shared_ptr<T> result(boost::dynamic_pointer_cast<T>(descriptions[i]));
+					if (result) {
+						return result;
+					}
+				}
+				return boost::shared_ptr<T>();
+			}
+
+			template<typename T>
+			boost::shared_ptr<T> getTransport() const {
+				for (size_t i = 0; i < transports.size(); ++i) {
+					boost::shared_ptr<T> result(boost::dynamic_pointer_cast<T>(transports[i]));
+					if (result) {
+						return result;
+					}
+				}
+				return boost::shared_ptr<T>();
+			}
+
+		private:
+			Creator creator;
+			std::string name;
+			//Senders senders;
+			std::vector<JingleDescription::ref> descriptions;
+			std::vector<boost::shared_ptr<JingleTransportPayload> > transports;
+	};
+}
diff --git a/Swiften/Elements/JingleIBBTransport.h b/Swiften/Elements/JingleIBBTransport.h
deleted file mode 100644
index faa5af3..0000000
--- a/Swiften/Elements/JingleIBBTransport.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2011 Remko Tronçon
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
- */
-
-#pragma once
-
-#include <string>
-#include <Swiften/Elements/JingleTransport.h>
-
-namespace Swift {
-	class JingleIBBTransport : public JingleTransport {
-		public:
-			enum StanzaType {
-				IQStanza,
-				MessageStanza,
-			};
-
-			void setStanzaType(StanzaType stanzaType) {
-				this->stanzaType = stanzaType;
-			}
-
-			StanzaType getStanzaType() const {
-				return stanzaType;
-			}
-
-			void setSessionID(const std::string& id) {
-				sessionID = id;
-			}
-
-			const std::string& getSessionID() const {
-				return sessionID;
-			}
-
-			int getBlockSize() const {
-				return blockSize;
-			}
-
-			void setBlockSize(int blockSize) {
-				this->blockSize = blockSize;
-			}
-
-		private:
-			std::string sessionID;
-			int blockSize;
-			StanzaType stanzaType;
-	};
-}
diff --git a/Swiften/Elements/JingleIBBTransportPayload.h b/Swiften/Elements/JingleIBBTransportPayload.h
new file mode 100644
index 0000000..67aab09
--- /dev/null
+++ b/Swiften/Elements/JingleIBBTransportPayload.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+#include <string>
+
+#include <Swiften/Elements/JingleTransportPayload.h>
+
+namespace Swift {
+	class JingleIBBTransportPayload : public JingleTransportPayload {
+		public:
+			typedef boost::shared_ptr<JingleIBBTransportPayload> ref;
+
+			enum StanzaType {
+				IQStanza,
+				MessageStanza,
+			};
+
+			void setStanzaType(StanzaType stanzaType) {
+				this->stanzaType = stanzaType;
+			}
+
+			StanzaType getStanzaType() const {
+				return stanzaType;
+			}
+
+			void setSessionID(const std::string& id) {
+				sessionID = id;
+			}
+
+			const std::string& getSessionID() const {
+				return sessionID;
+			}
+
+			int getBlockSize() const {
+				return blockSize;
+			}
+
+			void setBlockSize(int blockSize) {
+				this->blockSize = blockSize;
+			}
+
+		private:
+			std::string sessionID;
+			int blockSize;
+			StanzaType stanzaType;
+	};
+}
diff --git a/Swiften/Elements/JinglePayload.h b/Swiften/Elements/JinglePayload.h
index 59d3c99..be02543 100644
--- a/Swiften/Elements/JinglePayload.h
+++ b/Swiften/Elements/JinglePayload.h
@@ -12,7 +12,7 @@
 #include <string>
 #include <Swiften/JID/JID.h>
 #include <Swiften/Elements/Payload.h>
-#include <Swiften/Elements/JingleContent.h>
+#include <Swiften/Elements/JingleContentPayload.h>
 
 
 namespace Swift {
@@ -98,11 +98,11 @@ namespace Swift {
 				return sessionID;
 			}
 
-			void addContent(JingleContent::ref content) {
+			void addContent(JingleContentPayload::ref content) {
 				this->contents.push_back(content);
 			}
 
-			const std::vector<JingleContent::ref> getContents() const {
+			const std::vector<JingleContentPayload::ref> getContents() const {
 				return contents;
 			}
 
@@ -119,7 +119,7 @@ namespace Swift {
 			JID initiator;
 			JID responder;
 			std::string sessionID;
-			std::vector<JingleContent::ref> contents;
+			std::vector<JingleContentPayload::ref> contents;
 			boost::optional<Reason> reason;
 	};
 }
diff --git a/Swiften/Elements/JingleS5BTransport.h b/Swiften/Elements/JingleS5BTransport.h
deleted file mode 100644
index 4522417..0000000
--- a/Swiften/Elements/JingleS5BTransport.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2011 Remko Tronçon
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
- */
-
-#pragma once
-
-#include <Swiften/Elements/JingleTransport.h>
-#include <Swiften/Elements/Bytestreams.h>
-
-namespace Swift {
-	class JingleS5BTransport : public JingleTransport {
-		public:
-			const Bytestreams& getInfo() const {
-				return info;
-			}
-
-			void setInfo(const Bytestreams& info) {
-				this->info = info;
-			}
-
-		private:
-			Bytestreams info;
-	};
-}
diff --git a/Swiften/Elements/JingleS5BTransportPayload.h b/Swiften/Elements/JingleS5BTransportPayload.h
new file mode 100644
index 0000000..7b3089f
--- /dev/null
+++ b/Swiften/Elements/JingleS5BTransportPayload.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Elements/JingleTransportPayload.h>
+#include <Swiften/Elements/Bytestreams.h>
+
+// FIXME: Remove Bytestreams, and replace by our own candidate
+
+namespace Swift {
+	class JingleS5BTransportPayload : public JingleTransportPayload {
+		public:
+			const Bytestreams& getInfo() const {
+				return info;
+			}
+
+			void setInfo(const Bytestreams& info) {
+				this->info = info;
+			}
+
+		private:
+			Bytestreams info;
+	};
+}
diff --git a/Swiften/Elements/JingleTransport.h b/Swiften/Elements/JingleTransport.h
deleted file mode 100644
index 7a9ea29..0000000
--- a/Swiften/Elements/JingleTransport.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (c) 2011 Remko Tronçon
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
- */
-
-#pragma once
-
-#include <boost/shared_ptr.hpp>
-
-#include <Swiften/Elements/Payload.h>
-
-namespace Swift {
-	class JingleTransportPayload : public Payload {
-		public:
-			typedef boost::shared_ptr<JingleTransportPayload> ref;
-	};
-}
diff --git a/Swiften/Elements/JingleTransportPayload.h b/Swiften/Elements/JingleTransportPayload.h
new file mode 100644
index 0000000..7a9ea29
--- /dev/null
+++ b/Swiften/Elements/JingleTransportPayload.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Elements/Payload.h>
+
+namespace Swift {
+	class JingleTransportPayload : public Payload {
+		public:
+			typedef boost::shared_ptr<JingleTransportPayload> ref;
+	};
+}
diff --git a/Swiften/Examples/SendFile/SendFile.cpp b/Swiften/Examples/SendFile/SendFile.cpp
index 565c51f..d8300be 100644
--- a/Swiften/Examples/SendFile/SendFile.cpp
+++ b/Swiften/Examples/SendFile/SendFile.cpp
@@ -16,7 +16,7 @@
 #include "Swiften/EventLoop/EventLoop.h"
 #include "Swiften/Client/ClientXMLTracer.h"
 #include "Swiften/EventLoop/SimpleEventLoop.h"
-#include "Swiften/FileTransfer/OutgoingFileTransfer.h"
+#include "Swiften/FileTransfer/OutgoingSIFileTransfer.h"
 #include "Swiften/FileTransfer/FileReadBytestream.h"
 #include "Swiften/FileTransfer/SOCKS5BytestreamServer.h"
 #include "Swiften/Network/BoostConnectionServer.h"
@@ -66,7 +66,7 @@ class FileSender {
 	private:
 		void handleConnected() {
 			client->sendPresence(Presence::create());
-			transfer = new OutgoingFileTransfer("myid",	client->getJID(), recipient, file.filename(), boost::filesystem::file_size(file), "A file", boost::shared_ptr<FileReadBytestream>(new FileReadBytestream(file)), client->getIQRouter(), socksBytestreamServer);
+			transfer = new OutgoingSIFileTransfer("myid",	client->getJID(), recipient, file.filename(), boost::filesystem::file_size(file), "A file", boost::shared_ptr<FileReadBytestream>(new FileReadBytestream(file)), client->getIQRouter(), socksBytestreamServer);
 			transfer->onFinished.connect(boost::bind(&FileSender::handleFileTransferFinished, this, _1));
 			transfer->start();
 		}
@@ -101,7 +101,7 @@ class FileSender {
 		boost::filesystem::path file;
 		Client* client;
 		ClientXMLTracer* tracer;
-		OutgoingFileTransfer* transfer;
+		OutgoingSIFileTransfer* transfer;
 };
 
 
diff --git a/Swiften/FileTransfer/ByteArrayReadBytestream.h b/Swiften/FileTransfer/ByteArrayReadBytestream.h
index d459658..4704db6 100644
--- a/Swiften/FileTransfer/ByteArrayReadBytestream.h
+++ b/Swiften/FileTransfer/ByteArrayReadBytestream.h
@@ -6,31 +6,32 @@
 
 #pragma once
 
-#include "Swiften/FileTransfer/ReadBytestream.h"
-#include "Swiften/Base/ByteArray.h"
+#include <vector>
+
+#include <Swiften/FileTransfer/ReadBytestream.h>
 
 namespace Swift {
 	class ByteArrayReadBytestream : public ReadBytestream {
 		public:
-			ByteArrayReadBytestream(const ByteArray& data) : data(data), position(0) {
+			ByteArrayReadBytestream(const std::vector<unsigned char>& data) : data(data), position(0) {
 			}
 
-			virtual ByteArray read(size_t size) {
+			virtual std::vector<unsigned char> read(size_t size) {
 				size_t readSize = size;
-				if (position + readSize > data.getSize()) {
-					readSize = data.getSize() - position;
+				if (position + readSize > data.size()) {
+					readSize = data.size() - position;
 				}
-				ByteArray result(data.getData() + position, readSize);
+				std::vector<unsigned char> result(data.begin() + position, data.begin() + position + readSize);
 				position += readSize;
 				return result;
 			}
 
 			virtual bool isFinished() const {
-				return position >= data.getSize();
+				return position >= data.size();
 			}
 
 		private:
-			ByteArray data;
+			std::vector<unsigned char> data;
 			size_t position;
 	};
 }
diff --git a/Swiften/FileTransfer/ByteArrayWriteBytestream.h b/Swiften/FileTransfer/ByteArrayWriteBytestream.h
new file mode 100644
index 0000000..6c360e6
--- /dev/null
+++ b/Swiften/FileTransfer/ByteArrayWriteBytestream.h
@@ -0,0 +1,28 @@
+/*
+ * 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/FileTransfer/WriteBytestream.h>
+
+namespace Swift {
+	class ByteArrayWriteBytestream : public WriteBytestream {
+		public:
+			ByteArrayWriteBytestream() {
+			}
+
+			virtual void write(const std::vector<unsigned char>& bytes) {
+				data.insert(data.end(), bytes.begin(), bytes.end());
+			}
+
+			const std::vector<unsigned char>& getData() const {
+				return data;
+			}
+
+		private:
+			std::vector<unsigned char> data;
+	};
+}
diff --git a/Swiften/FileTransfer/FileReadBytestream.cpp b/Swiften/FileTransfer/FileReadBytestream.cpp
index c08747b..e997366 100644
--- a/Swiften/FileTransfer/FileReadBytestream.cpp
+++ b/Swiften/FileTransfer/FileReadBytestream.cpp
@@ -21,14 +21,14 @@ FileReadBytestream::~FileReadBytestream() {
 	}
 }
 
-ByteArray FileReadBytestream::read(size_t size)  {
+std::vector<unsigned char> FileReadBytestream::read(size_t size)  {
 	if (!stream) {
 		stream = new boost::filesystem::ifstream(file, std::ios_base::in|std::ios_base::binary);
 	}
-	ByteArray result;
+	std::vector<unsigned char> result;
 	result.resize(size);
 	assert(stream->good());
-	stream->read(reinterpret_cast<char*>(result.getData()), size);
+	stream->read(reinterpret_cast<char*>(&result[0]), size);
 	result.resize(stream->gcount());
 	return result;
 }
diff --git a/Swiften/FileTransfer/FileReadBytestream.h b/Swiften/FileTransfer/FileReadBytestream.h
index 4027c43..f136a68 100644
--- a/Swiften/FileTransfer/FileReadBytestream.h
+++ b/Swiften/FileTransfer/FileReadBytestream.h
@@ -17,7 +17,7 @@ namespace Swift {
 			FileReadBytestream(const boost::filesystem::path& file);
 			~FileReadBytestream();
 
-			virtual ByteArray read(size_t size) ;
+			virtual std::vector<unsigned char> read(size_t size);
 			virtual bool isFinished() const;
 
 		private:
diff --git a/Swiften/FileTransfer/FileWriteBytestream.cpp b/Swiften/FileTransfer/FileWriteBytestream.cpp
index 4d29bd1..803a10b 100644
--- a/Swiften/FileTransfer/FileWriteBytestream.cpp
+++ b/Swiften/FileTransfer/FileWriteBytestream.cpp
@@ -21,12 +21,12 @@ FileWriteBytestream::~FileWriteBytestream() {
 	}
 }
 
-void FileWriteBytestream::write(const ByteArray& data) {
+void FileWriteBytestream::write(const std::vector<unsigned char>& data) {
 	if (!stream) {
 		stream = new boost::filesystem::ofstream(file, std::ios_base::out|std::ios_base::binary);
 	}
 	assert(stream->good());
-	stream->write(reinterpret_cast<const char*>(data.getData()), data.getSize());
+	stream->write(reinterpret_cast<const char*>(&data[0]), data.size());
 }
 
 }
diff --git a/Swiften/FileTransfer/FileWriteBytestream.h b/Swiften/FileTransfer/FileWriteBytestream.h
index 16f4b1f..8cfa718 100644
--- a/Swiften/FileTransfer/FileWriteBytestream.h
+++ b/Swiften/FileTransfer/FileWriteBytestream.h
@@ -9,7 +9,7 @@
 #include <boost/filesystem/path.hpp>
 #include <boost/filesystem/fstream.hpp>
 
-#include "Swiften/FileTransfer/WriteBytestream.h"
+#include <Swiften/FileTransfer/WriteBytestream.h>
 
 namespace Swift {
 	class FileWriteBytestream : public WriteBytestream {
@@ -17,7 +17,7 @@ namespace Swift {
 			FileWriteBytestream(const boost::filesystem::path& file);
 			~FileWriteBytestream();
 
-			virtual void write(const ByteArray&);
+			virtual void write(const std::vector<unsigned char>&);
 
 		private:
 			boost::filesystem::path file;
diff --git a/Swiften/FileTransfer/IBBReceiveSession.cpp b/Swiften/FileTransfer/IBBReceiveSession.cpp
index f980c47..566dcca 100644
--- a/Swiften/FileTransfer/IBBReceiveSession.cpp
+++ b/Swiften/FileTransfer/IBBReceiveSession.cpp
@@ -4,32 +4,96 @@
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
 
-#include "Swiften/FileTransfer/IBBReceiveSession.h"
+#include <Swiften/FileTransfer/IBBReceiveSession.h>
 
 #include <boost/bind.hpp>
-#include <iostream>
 
-#include "Swiften/Queries/IQRouter.h"
-#include "Swiften/FileTransfer/IBBRequest.h"
-#include "Swiften/FileTransfer/BytestreamException.h"
+#include <Swiften/Base/Log.h>
+#include <Swiften/Queries/IQRouter.h>
+#include <Swiften/FileTransfer/IBBRequest.h>
+#include <Swiften/FileTransfer/BytestreamException.h>
+#include <Swiften/Queries/SetResponder.h>
 
 namespace Swift {
 
-IBBReceiveSession::IBBReceiveSession(const std::string& id, const JID& from, size_t size, WriteBytestream::ref bytestream, IQRouter* router) : SetResponder<IBB>(router), id(id), from(from), size(size), bytestream(bytestream), router(router), sequenceNumber(0), active(false), receivedSize(0) {
+class IBBReceiveSession::IBBResponder : public SetResponder<IBB> {
+	public:
+		IBBResponder(IBBReceiveSession* session, IQRouter* router) : SetResponder<IBB>(router), session(session), sequenceNumber(0), receivedSize(0) {
+		}
+
+		virtual bool handleSetRequest(const JID& from, const JID&, const std::string& id, IBB::ref ibb) {
+			if (from == session->from && ibb->getStreamID() == session->id) {
+				if (ibb->getAction() == IBB::Data) {
+					if (sequenceNumber == ibb->getSequenceNumber()) {
+						session->onDataReceived(ibb->getData());
+						receivedSize += ibb->getData().size();
+						sequenceNumber++;
+						sendResponse(from, id, IBB::ref());
+						if (receivedSize >= session->size) {
+							if (receivedSize > session->size) {
+								std::cerr << "Warning: Received more data than expected" << std::endl;
+							}
+							session->finish(boost::optional<FileTransferError>());
+						}
+					}
+					else {
+						SWIFT_LOG(warning) << "Received data out of order" << std::endl;
+						sendError(from, id, ErrorPayload::NotAcceptable, ErrorPayload::Cancel);
+						session->finish(FileTransferError(FileTransferError::ClosedError));
+					}
+				}
+				else if (ibb->getAction() == IBB::Open) {
+					sendResponse(from, id, IBB::ref());
+				}
+				else if (ibb->getAction() == IBB::Close) {
+					sendResponse(from, id, IBB::ref());
+					session->finish(FileTransferError(FileTransferError::ClosedError));
+				}
+				return true;
+			}
+			return false;
+		}
+
+	private:
+		IBBReceiveSession* session;
+		int sequenceNumber;
+		size_t receivedSize;
+};
+
+
+IBBReceiveSession::IBBReceiveSession(
+		const std::string& id, 
+		const JID& from, 
+		size_t size, 
+		IQRouter* router) : 
+			id(id), 
+			from(from), 
+			size(size), 
+			router(router), 
+			active(false) {
+	responder = new IBBResponder(this, router);
 }
 
 IBBReceiveSession::~IBBReceiveSession() {
+	if (active) {
+		SWIFT_LOG(warning) << "Session still active" << std::endl;
+	}
+	delete responder;
 }
 
 void IBBReceiveSession::start() {
 	active = true;
+	responder->start();
 }
 
 void IBBReceiveSession::stop() {
-	if (active && router->isAvailable()) {
-		IBBRequest::create(from, IBB::createIBBClose(id), router)->send();
+	responder->stop();
+	if (active) {
+		if (router->isAvailable()) {
+			IBBRequest::create(from, IBB::createIBBClose(id), router)->send();
+		}
+		finish(boost::optional<FileTransferError>());
 	}
-	finish(boost::optional<FileTransferError>());
 }
 
 void IBBReceiveSession::finish(boost::optional<FileTransferError> error) {
@@ -37,34 +101,4 @@ void IBBReceiveSession::finish(boost::optional<FileTransferError> error) {
 	onFinished(error);
 }
 
-bool IBBReceiveSession::handleSetRequest(const JID& from, const JID&, const std::string& id, IBB::ref ibb) {
-	if (from == this->from && ibb->getStreamID() == id) {
-		if (ibb->getAction() == IBB::Data) {
-			if (sequenceNumber == ibb->getSequenceNumber()) {
-				bytestream->write(ibb->getData());
-				receivedSize += ibb->getData().getSize();
-				if (receivedSize >= size) {
-					if (receivedSize > size) {
-						std::cerr << "Warning: Received more data than expected" << std::endl;
-					}
-					finish(boost::optional<FileTransferError>());
-				}
-			}
-			else {
-				sendError(from, id, ErrorPayload::NotAcceptable, ErrorPayload::Cancel);
-				finish(FileTransferError(FileTransferError::ClosedError));
-			}
-		}
-		else if (ibb->getAction() == IBB::Open) {
-			sendResponse(from, id, IBB::ref());
-		}
-		else if (ibb->getAction() == IBB::Close) {
-			sendResponse(from, id, IBB::ref());
-			finish(FileTransferError(FileTransferError::ClosedError));
-		}
-		return true;
-	}
-	return false;
-}
-
 }
diff --git a/Swiften/FileTransfer/IBBReceiveSession.h b/Swiften/FileTransfer/IBBReceiveSession.h
index 6d936de..d512025 100644
--- a/Swiften/FileTransfer/IBBReceiveSession.h
+++ b/Swiften/FileTransfer/IBBReceiveSession.h
@@ -7,27 +7,30 @@
 #pragma once
 
 #include <boost/shared_ptr.hpp>
-#include <boost/optional.hpp>
+#include <boost/optional/optional_fwd.hpp>
 
 #include "Swiften/Base/boost_bsignals.h"
 #include "Swiften/FileTransfer/WriteBytestream.h"
 #include "Swiften/JID/JID.h"
 #include "Swiften/Elements/IBB.h"
-#include "Swiften/Elements/ErrorPayload.h"
 #include "Swiften/FileTransfer/FileTransferError.h"
-#include "Swiften/Queries/SetResponder.h"
 
 namespace Swift {
 	class IQRouter;
 
-	class IBBReceiveSession : public SetResponder<IBB> {
+	class IBBReceiveSession {
 		public:
-			IBBReceiveSession(const std::string& id, const JID& from, size_t size, WriteBytestream::ref bytestream, IQRouter* router);
+			IBBReceiveSession(
+					const std::string& id, 
+					const JID& from, 
+					size_t size, 
+					IQRouter* router);
 			~IBBReceiveSession();
 
 			void start();
 			void stop();
 
+			boost::signal<void (const std::vector<unsigned char>&)> onDataReceived;
 			boost::signal<void (boost::optional<FileTransferError>)> onFinished;
 
 		private:
@@ -35,13 +38,14 @@ namespace Swift {
 			void finish(boost::optional<FileTransferError>);
 
 		private:
+			class IBBResponder;
+			friend class IBBResponder;
+
 			std::string id;
 			JID from;
 			size_t size;
-			WriteBytestream::ref bytestream;
 			IQRouter* router;
-			int sequenceNumber;
+			IBBResponder* responder;
 			bool active;
-			size_t receivedSize;
 	};
 }
diff --git a/Swiften/FileTransfer/IBBSendSession.cpp b/Swiften/FileTransfer/IBBSendSession.cpp
index 52949c4..c31fe4a 100644
--- a/Swiften/FileTransfer/IBBSendSession.cpp
+++ b/Swiften/FileTransfer/IBBSendSession.cpp
@@ -38,7 +38,7 @@ void IBBSendSession::handleIBBResponse(IBB::ref, ErrorPayload::ref error) {
 	if (!error) {
 		if (!bytestream->isFinished()) {
 			try {
-				ByteArray data = bytestream->read(blockSize);
+				std::vector<unsigned char> data = bytestream->read(blockSize);
 				IBBRequest::ref request = IBBRequest::create(to, IBB::createIBBData(id, sequenceNumber, data), router);
 				sequenceNumber++;
 				request->onResponse.connect(boost::bind(&IBBSendSession::handleIBBResponse, this, _1, _2));
diff --git a/Swiften/FileTransfer/IncomingFileTransfer.cpp b/Swiften/FileTransfer/IncomingFileTransfer.cpp
index 238ccce..7c97e4d 100644
--- a/Swiften/FileTransfer/IncomingFileTransfer.cpp
+++ b/Swiften/FileTransfer/IncomingFileTransfer.cpp
@@ -4,20 +4,11 @@
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
 
-#include "Swiften/FileTransfer/IncomingFileTransfer.h"
+#include <Swiften/FileTransfer/IncomingFileTransfer.h>
 
 namespace Swift {
 
 IncomingFileTransfer::~IncomingFileTransfer() {
-
-}
-
-/*void IncomingFileTransfer::accept(WriteBytestream::ref) {
-
 }
 
-void IncomingFileTransfer::stop() {
-
-}*/
-
 }
diff --git a/Swiften/FileTransfer/IncomingFileTransferManager.cpp b/Swiften/FileTransfer/IncomingFileTransferManager.cpp
index 5535840..79d2391 100644
--- a/Swiften/FileTransfer/IncomingFileTransferManager.cpp
+++ b/Swiften/FileTransfer/IncomingFileTransferManager.cpp
@@ -10,8 +10,10 @@
 
 #include <Swiften/Elements/JingleDescription.h>
 #include <Swiften/Elements/JingleFileTransferDescription.h>
-#include <Swiften/Elements/JingleIBBTransport.h>
+#include <Swiften/Elements/JingleIBBTransportPayload.h>
+#include <Swiften/Elements/JingleS5BTransportPayload.h>
 #include <Swiften/Jingle/JingleSessionManager.h>
+#include <Swiften/Jingle/Jingle.h>
 #include <Swiften/FileTransfer/IncomingJingleFileTransfer.h>
 
 namespace Swift {
@@ -24,12 +26,12 @@ IncomingFileTransferManager::~IncomingFileTransferManager() {
 	jingleSessionManager->removeIncomingSessionHandler(this);
 }
 
-bool IncomingFileTransferManager::handleIncomingJingleSession(IncomingJingleSession::ref session) {
-	JingleContent::ref content = session->getContentWithDescription<JingleFileTransferDescription>();
-	if (content) {
-		// Check for supported transports
-		if (content->getTransport<JingleIBBTransport>()) {
-			IncomingJingleFileTransfer::ref transfer = boost::make_shared<IncomingJingleFileTransfer>(session);
+bool IncomingFileTransferManager::handleIncomingJingleSession(JingleSession::ref session, const std::vector<JingleContentPayload::ref>& contents) {
+	if (JingleContentPayload::ref content = Jingle::getContentWithDescription<JingleFileTransferDescription>(contents)) {
+		if (content->getTransport<JingleIBBTransportPayload>() || content->getTransport<JingleS5BTransportPayload>()) {
+			RemoteJingleTransportCandidateSelectorFactory* a;
+			LocalJingleTransportCandidateGeneratorFactory* b;
+			IncomingJingleFileTransfer::ref transfer = boost::make_shared<IncomingJingleFileTransfer>(session, content, a, b, router);
 			onIncomingFileTransfer(transfer);
 		}
 		else {
diff --git a/Swiften/FileTransfer/IncomingFileTransferManager.h b/Swiften/FileTransfer/IncomingFileTransferManager.h
index a54b5cd..428a838 100644
--- a/Swiften/FileTransfer/IncomingFileTransferManager.h
+++ b/Swiften/FileTransfer/IncomingFileTransferManager.h
@@ -15,6 +15,8 @@
 namespace Swift {
 	class IQRouter;
 	class JingleSessionManager;
+	class RemoteJingleTransportCandidateSelectorFactory;
+	class LocalJingleTransportCandidateGeneratorFactory;
 
 	class IncomingFileTransferManager : public IncomingJingleSessionHandler {
 		public:
@@ -24,7 +26,7 @@ namespace Swift {
 			boost::signal<void (IncomingFileTransfer::ref)> onIncomingFileTransfer;
 
 		private:
-			bool handleIncomingJingleSession(IncomingJingleSession::ref session);
+			bool handleIncomingJingleSession(JingleSession::ref session, const std::vector<JingleContentPayload::ref>& contents);
 
 		private:
 			JingleSessionManager* jingleSessionManager;
diff --git a/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp b/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp
index cb2f65c..904b53e 100644
--- a/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp
+++ b/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp
@@ -6,14 +6,164 @@
 
 #include <Swiften/FileTransfer/IncomingJingleFileTransfer.h>
 
+#include <boost/bind.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h>
+#include <Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h>
+#include <Swiften/FileTransfer/JingleIncomingIBBTransport.h>
+#include <Swiften/Elements/JingleIBBTransportPayload.h>
+#include <Swiften/Elements/JingleS5BTransportPayload.h>
+#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h>
+#include <Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h>
+
 namespace Swift {
 
-IncomingJingleFileTransfer::IncomingJingleFileTransfer(IncomingJingleSession::ref session) : session(session) {
+IncomingJingleFileTransfer::IncomingJingleFileTransfer(
+		JingleSession::ref session,
+		JingleContentPayload::ref content,
+		RemoteJingleTransportCandidateSelectorFactory* candidateSelectorFactory,
+		LocalJingleTransportCandidateGeneratorFactory* candidateGeneratorFactory,
+		IQRouter* router) :
+			session(session),
+			router(router),
+			initialContent(content),
+			contentID(content->getName(), content->getCreator()),
+			state(Initial),
+			remoteTransportCandidateSelectFinished(false),
+			localTransportCandidateSelectFinished(false) {
+	
+	candidateSelector = candidateSelectorFactory->createCandidateSelector();
+	candidateSelector->onRemoteTransportCandidateSelectFinished.connect(boost::bind(&IncomingJingleFileTransfer::handleRemoteTransportCandidateSelectFinished, this, _1));
+
+	candidateGenerator = candidateGeneratorFactory->createCandidateGenerator();
+	candidateGenerator->onLocalTransportCandidatesGenerated.connect(boost::bind(&IncomingJingleFileTransfer::handleLocalTransportCandidatesGenerated, this, _1));
+
+	session->onTransportInfoReceived.connect(boost::bind(&IncomingJingleFileTransfer::handleTransportInfoReceived, this, _1, _2));
+	session->onTransportReplaceReceived.connect(boost::bind(&IncomingJingleFileTransfer::handleTransportReplaceReceived, this, _1, _2));
+	session->onSessionTerminateReceived.connect(boost::bind(&IncomingJingleFileTransfer::handleSessionTerminateReceived, this));
+
+	description = initialContent->getDescription<JingleFileTransferDescription>();
+	assert(description);
+}
+
+IncomingJingleFileTransfer::~IncomingJingleFileTransfer() {
+	session->onSessionTerminateReceived.disconnect(boost::bind(&IncomingJingleFileTransfer::handleSessionTerminateReceived, this));
+	session->onTransportReplaceReceived.disconnect(boost::bind(&IncomingJingleFileTransfer::handleTransportReplaceReceived, this, _1, _2));
+	session->onTransportInfoReceived.disconnect(boost::bind(&IncomingJingleFileTransfer::handleTransportInfoReceived, this, _1, _2));
+
+	candidateGenerator->onLocalTransportCandidatesGenerated.disconnect(boost::bind(&IncomingJingleFileTransfer::handleLocalTransportCandidatesGenerated, this, _1));
+	delete candidateGenerator;
 
+	candidateSelector->onRemoteTransportCandidateSelectFinished.disconnect(boost::bind(&IncomingJingleFileTransfer::handleRemoteTransportCandidateSelectFinished, this, _1));
+	delete candidateSelector;
 }
 
 void IncomingJingleFileTransfer::accept(WriteBytestream::ref stream) {
+	assert(!stream);
 	this->stream = stream;
+
+	if (JingleIBBTransportPayload::ref ibbTransport = initialContent->getTransport<JingleIBBTransportPayload>()) {
+		setActiveTransport(createIBBTransport(ibbTransport));
+		session->accept();
+	}
+	else if (JingleS5BTransportPayload::ref s5bTransport = initialContent->getTransport<JingleS5BTransportPayload>()) {
+		state = CreatingInitialTransports;
+		candidateSelector->addRemoteTransportCandidates(s5bTransport);
+		candidateGenerator->generateLocalTransportCandidates();
+	}
+	else {
+		assert(false);
+	}
+}
+
+
+void IncomingJingleFileTransfer::handleLocalTransportCandidatesGenerated(JingleTransportPayload::ref candidates) {
+	if (state == CreatingInitialTransports) {
+		if (!candidates) {
+			localTransportCandidateSelectFinished = true;
+		}
+		session->accept(candidates);
+		state = NegotiatingTransport;
+		candidateSelector->selectCandidate();
+	}
+}
+
+
+void IncomingJingleFileTransfer::handleRemoteTransportCandidateSelectFinished(JingleTransportPayload::ref transport) {
+	remoteTransportCandidateSelectFinished = true;
+	selectedRemoteTransportCandidate = transport;
+	session->sendTransportInfo(contentID, transport);
+	checkCandidateSelected();
+}
+
+void IncomingJingleFileTransfer::checkCandidateSelected() {
+	if (localTransportCandidateSelectFinished && remoteTransportCandidateSelectFinished) {
+		if (candidateGenerator->isActualCandidate(selectedLocalTransportCandidate) && candidateSelector->isActualCandidate(selectedRemoteTransportCandidate)) {
+			if (candidateGenerator->getPriority(selectedLocalTransportCandidate) > candidateSelector->getPriority(selectedRemoteTransportCandidate)) {
+				setActiveTransport(candidateGenerator->selectTransport(selectedLocalTransportCandidate));
+			}
+			else {
+				setActiveTransport(candidateSelector->selectTransport(selectedRemoteTransportCandidate));
+			}
+		}
+		else if (candidateSelector->isActualCandidate(selectedRemoteTransportCandidate)) {
+			setActiveTransport(candidateSelector->selectTransport(selectedRemoteTransportCandidate));
+		}
+		else if (candidateGenerator->isActualCandidate(selectedLocalTransportCandidate)) {
+			setActiveTransport(candidateGenerator->selectTransport(selectedLocalTransportCandidate));
+		}
+		else {
+			state = WaitingForFallbackOrTerminate;
+		}
+	}
+}
+
+void IncomingJingleFileTransfer::setActiveTransport(JingleTransport::ref transport) {
+	state = Transferring;
+	activeTransport = transport;
+	activeTransport->onDataReceived.connect(boost::bind(&IncomingJingleFileTransfer::handleTransportDataReceived, this, _1));
+	activeTransport->start();
+}
+
+void IncomingJingleFileTransfer::handleSessionTerminateReceived() {
+	// TODO
+	state = Terminated;
+}
+
+void IncomingJingleFileTransfer::handleTransportDataReceived(const std::vector<unsigned char>& data) {
+	stream->write(data);
+}
+
+
+void IncomingJingleFileTransfer::handleTransportInfoReceived(const JingleContentID&, JingleTransportPayload::ref transport) {
+	localTransportCandidateSelectFinished = true;
+	selectedLocalTransportCandidate = transport;
+	if (candidateGenerator->isActualCandidate(transport)) {
+		candidateSelector->setMinimumPriority(candidateGenerator->getPriority(transport));
+	}
+	checkCandidateSelected();
+}
+
+void IncomingJingleFileTransfer::handleTransportReplaceReceived(const JingleContentID& content, JingleTransportPayload::ref transport) {
+	if (JingleIBBTransportPayload::ref ibbTransport = boost::dynamic_pointer_cast<JingleIBBTransportPayload>(transport)) {
+		setActiveTransport(createIBBTransport(ibbTransport));
+		session->acceptTransport(content, transport);
+	}
+	else {
+		session->rejectTransport(content, transport);
+	}
+}
+
+void IncomingJingleFileTransfer::stopActiveTransport() {
+	if (activeTransport) {
+		activeTransport->stop();
+		activeTransport->onDataReceived.disconnect(boost::bind(&IncomingJingleFileTransfer::handleTransportDataReceived, this, _1));
+	}
+}
+
+JingleIncomingIBBTransport::ref IncomingJingleFileTransfer::createIBBTransport(JingleIBBTransportPayload::ref ibbTransport) {
+	return boost::make_shared<JingleIncomingIBBTransport>(session->getInitiator(), ibbTransport->getSessionID(), description->getOffer()->size, router);
 }
 
 }
diff --git a/Swiften/FileTransfer/IncomingJingleFileTransfer.h b/Swiften/FileTransfer/IncomingJingleFileTransfer.h
index d69449e..164d868 100644
--- a/Swiften/FileTransfer/IncomingJingleFileTransfer.h
+++ b/Swiften/FileTransfer/IncomingJingleFileTransfer.h
@@ -8,20 +8,71 @@
 
 #include <boost/shared_ptr.hpp>
 
-#include <Swiften/Jingle/IncomingJingleSession.h>
+#include <Swiften/Jingle/JingleSession.h>
+#include <Swiften/Jingle/JingleContentID.h>
 #include <Swiften/FileTransfer/IncomingFileTransfer.h>
+#include <Swiften/FileTransfer/JingleTransport.h>
+#include <Swiften/FileTransfer/JingleIncomingIBBTransport.h>
+#include <Swiften/Elements/JingleContentPayload.h>
+#include <Swiften/Elements/JingleFileTransferDescription.h>
+#include <Swiften/Elements/JingleIBBTransportPayload.h>
 
 namespace Swift {
+	class IQRouter;
+	class RemoteJingleTransportCandidateSelectorFactory;
+	class LocalJingleTransportCandidateGeneratorFactory;
+	class RemoteJingleTransportCandidateSelector;
+	class LocalJingleTransportCandidateGenerator;
+
 	class IncomingJingleFileTransfer : public IncomingFileTransfer {
 		public:
 			typedef boost::shared_ptr<IncomingJingleFileTransfer> ref;
+			enum State {
+				Initial,
+				CreatingInitialTransports,
+				NegotiatingTransport,
+				Transferring,
+				WaitingForFallbackOrTerminate,
+				Terminated
+			};
 
-			IncomingJingleFileTransfer(IncomingJingleSession::ref session);
+			IncomingJingleFileTransfer(
+					JingleSession::ref,
+					JingleContentPayload::ref content,
+					RemoteJingleTransportCandidateSelectorFactory*,
+					LocalJingleTransportCandidateGeneratorFactory*,
+					IQRouter* router);
+			~IncomingJingleFileTransfer();
 
 			virtual void accept(WriteBytestream::ref);
 
 		private:
-			IncomingJingleSession::ref session;
+			void handleSessionTerminateReceived();
+			void handleTransportReplaceReceived(const JingleContentID&, JingleTransportPayload::ref);
+			void handleTransportInfoReceived(const JingleContentID&, JingleTransportPayload::ref);
+			void handleLocalTransportCandidatesGenerated(JingleTransportPayload::ref candidates);
+			void handleRemoteTransportCandidateSelectFinished(JingleTransportPayload::ref candidate);
+			void setActiveTransport(JingleTransport::ref transport);
+			void handleTransportDataReceived(const std::vector<unsigned char>& data);
+			void stopActiveTransport();
+			void checkCandidateSelected();
+			JingleIncomingIBBTransport::ref createIBBTransport(JingleIBBTransportPayload::ref ibbTransport);
+
+		private:
+			JingleSession::ref session;
+			IQRouter* router;
+			JingleContentPayload::ref initialContent;
+			JingleContentID contentID;
+			State state;
+			JingleFileTransferDescription::ref description;
 			WriteBytestream::ref stream;
+			RemoteJingleTransportCandidateSelector* candidateSelector;
+			LocalJingleTransportCandidateGenerator* candidateGenerator;
+			bool remoteTransportCandidateSelectFinished;
+			JingleTransportPayload::ref selectedRemoteTransportCandidate;
+			bool localTransportCandidateSelectFinished;
+			JingleTransportPayload::ref selectedLocalTransportCandidate;
+
+			JingleTransport::ref activeTransport;
 	};
 }
diff --git a/Swiften/FileTransfer/JingleIncomingIBBTransport.cpp b/Swiften/FileTransfer/JingleIncomingIBBTransport.cpp
new file mode 100644
index 0000000..0ca899f
--- /dev/null
+++ b/Swiften/FileTransfer/JingleIncomingIBBTransport.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/FileTransfer/JingleIncomingIBBTransport.h>
+
+namespace Swift {
+
+JingleIncomingIBBTransport::JingleIncomingIBBTransport(const JID& from, const std::string& id, size_t size, IQRouter* router) : ibbSession(from, id, size, router) {
+	ibbSession.onDataReceived.connect(boost::ref(onDataReceived));
+}
+
+void JingleIncomingIBBTransport::start() {
+	ibbSession.start();
+}
+
+void JingleIncomingIBBTransport::stop() {
+	ibbSession.stop();
+}
+
+}
diff --git a/Swiften/FileTransfer/JingleIncomingIBBTransport.h b/Swiften/FileTransfer/JingleIncomingIBBTransport.h
new file mode 100644
index 0000000..e2fa485
--- /dev/null
+++ b/Swiften/FileTransfer/JingleIncomingIBBTransport.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/FileTransfer/JingleTransport.h>
+#include <Swiften/FileTransfer/IBBReceiveSession.h>
+
+namespace Swift {
+	class JingleIncomingIBBTransport : public JingleTransport {
+		public:
+			typedef boost::shared_ptr<JingleIncomingIBBTransport> ref;
+
+			JingleIncomingIBBTransport(const JID& from, const std::string& id, size_t size, IQRouter* router);
+
+			virtual void start();
+			virtual void stop();
+
+		private:
+			IBBReceiveSession ibbSession;
+	};
+}
diff --git a/Swiften/FileTransfer/JingleTransport.cpp b/Swiften/FileTransfer/JingleTransport.cpp
new file mode 100644
index 0000000..c507922
--- /dev/null
+++ b/Swiften/FileTransfer/JingleTransport.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/FileTransfer/JingleTransport.h>
+
+namespace Swift {
+
+JingleTransport::~JingleTransport() {
+
+}
+
+}
diff --git a/Swiften/FileTransfer/JingleTransport.h b/Swiften/FileTransfer/JingleTransport.h
new file mode 100644
index 0000000..1d163d0
--- /dev/null
+++ b/Swiften/FileTransfer/JingleTransport.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/boost_bsignals.h>
+
+namespace Swift {
+	class JingleTransport {
+		public:
+			typedef boost::shared_ptr<JingleTransport> ref;
+
+			virtual ~JingleTransport();
+
+			virtual void start() = 0;
+			virtual void stop() = 0;
+
+			boost::signal<void (const std::vector<unsigned char>&)> onDataReceived;
+	};
+}
diff --git a/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.cpp b/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.cpp
new file mode 100644
index 0000000..852902b
--- /dev/null
+++ b/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.cpp
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h>
+
+namespace Swift {
+
+LocalJingleTransportCandidateGenerator::~LocalJingleTransportCandidateGenerator() {
+}
+
+}
diff --git a/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h b/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h
new file mode 100644
index 0000000..c111005
--- /dev/null
+++ b/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/boost_bsignals.h>
+
+#include <Swiften/Elements/JingleTransportPayload.h>
+#include <Swiften/FileTransfer/JingleTransport.h>
+
+namespace Swift {
+	class LocalJingleTransportCandidateGenerator {
+		public:
+			virtual ~LocalJingleTransportCandidateGenerator();
+
+			virtual void generateLocalTransportCandidates() = 0;
+
+			virtual bool isActualCandidate(JingleTransportPayload::ref) = 0;
+			virtual int getPriority(JingleTransportPayload::ref) = 0;
+			virtual JingleTransport::ref selectTransport(JingleTransportPayload::ref) = 0;
+
+			boost::signal<void (JingleTransportPayload::ref)> onLocalTransportCandidatesGenerated;
+	};
+}
diff --git a/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.cpp b/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.cpp
new file mode 100644
index 0000000..a1e3874
--- /dev/null
+++ b/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.cpp
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h>
+
+namespace Swift {
+
+LocalJingleTransportCandidateGeneratorFactory::~LocalJingleTransportCandidateGeneratorFactory() {
+}
+
+}
diff --git a/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h b/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h
new file mode 100644
index 0000000..c969fc7
--- /dev/null
+++ b/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+namespace Swift {
+	class LocalJingleTransportCandidateGenerator;
+
+	class LocalJingleTransportCandidateGeneratorFactory {
+		public:
+			virtual ~LocalJingleTransportCandidateGeneratorFactory();
+
+			virtual LocalJingleTransportCandidateGenerator* createCandidateGenerator() = 0;
+	};
+}
diff --git a/Swiften/FileTransfer/OutgoingFileTransfer.cpp b/Swiften/FileTransfer/OutgoingFileTransfer.cpp
index 32f7e17..94d4348 100644
--- a/Swiften/FileTransfer/OutgoingFileTransfer.cpp
+++ b/Swiften/FileTransfer/OutgoingFileTransfer.cpp
@@ -4,75 +4,11 @@
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
 
-#include "Swiften/FileTransfer/OutgoingFileTransfer.h"
-
-#include <boost/bind.hpp>
-
-#include "Swiften/FileTransfer/StreamInitiationRequest.h"
-#include "Swiften/FileTransfer/BytestreamsRequest.h"
-#include "Swiften/FileTransfer/SOCKS5BytestreamServer.h"
-#include "Swiften/FileTransfer/IBBSendSession.h"
+#include <Swiften/FileTransfer/OutgoingFileTransfer.h>
 
 namespace Swift {
 
-OutgoingFileTransfer::OutgoingFileTransfer(const std::string& id, const JID& from, const JID& to, const std::string& name, int size, const std::string& description, boost::shared_ptr<ReadBytestream> bytestream, IQRouter* iqRouter, SOCKS5BytestreamServer* socksServer) : id(id), from(from), to(to), name(name), size(size), description(description), bytestream(bytestream), iqRouter(iqRouter), socksServer(socksServer) {
-}
-
-void OutgoingFileTransfer::start() {
-	StreamInitiation::ref streamInitiation(new StreamInitiation());
-	streamInitiation->setID(id);
-	streamInitiation->setFileInfo(StreamInitiationFileInfo(name, description, size));
-	//streamInitiation->addProvidedMethod("http://jabber.org/protocol/bytestreams");
-	streamInitiation->addProvidedMethod("http://jabber.org/protocol/ibb");
-	StreamInitiationRequest::ref request = StreamInitiationRequest::create(to, streamInitiation, iqRouter);
-	request->onResponse.connect(boost::bind(&OutgoingFileTransfer::handleStreamInitiationRequestResponse, this, _1, _2));
-	request->send();
-}
-
-void OutgoingFileTransfer::stop() {
-}
-
-void OutgoingFileTransfer::handleStreamInitiationRequestResponse(StreamInitiation::ref response, ErrorPayload::ref error) {
-	if (error) {
-		finish(FileTransferError());
-	}
-	else {
-		if (response->getRequestedMethod() == "http://jabber.org/protocol/bytestreams") {
-			socksServer->addBytestream(id, from, to, bytestream); 
-			Bytestreams::ref bytestreams(new Bytestreams());
-			bytestreams->setStreamID(id);
-			HostAddressPort addressPort = socksServer->getAddressPort();
-			bytestreams->addStreamHost(Bytestreams::StreamHost(addressPort.getAddress().toString(), from, addressPort.getPort()));
-			BytestreamsRequest::ref request = BytestreamsRequest::create(to, bytestreams, iqRouter);
-			request->onResponse.connect(boost::bind(&OutgoingFileTransfer::handleBytestreamsRequestResponse, this, _1, _2));
-			request->send();
-		}
-		else if (response->getRequestedMethod() == "http://jabber.org/protocol/ibb") {
-			ibbSession = boost::shared_ptr<IBBSendSession>(new IBBSendSession(id, to, bytestream, iqRouter));
-			ibbSession->onFinished.connect(boost::bind(&OutgoingFileTransfer::handleIBBSessionFinished, this, _1));
-			ibbSession->start();
-		}
-	}
-}
-
-void OutgoingFileTransfer::handleBytestreamsRequestResponse(Bytestreams::ref, ErrorPayload::ref error) {
-	if (error) {
-		finish(FileTransferError());
-	}
-	//socksServer->onTransferFinished.connect();
-}
-
-void OutgoingFileTransfer::finish(boost::optional<FileTransferError> error) {
-	if (ibbSession) {
-		ibbSession->onFinished.disconnect(boost::bind(&OutgoingFileTransfer::handleIBBSessionFinished, this, _1));
-		ibbSession.reset();
-	}
-	socksServer->removeBytestream(id, from, to); 
-	onFinished(error);
-}
-
-void OutgoingFileTransfer::handleIBBSessionFinished(boost::optional<FileTransferError> error) {
-	finish(error);
+OutgoingFileTransfer::~OutgoingFileTransfer() {
 }
 
 }
diff --git a/Swiften/FileTransfer/OutgoingFileTransfer.h b/Swiften/FileTransfer/OutgoingFileTransfer.h
index a694c13..a8c1e81 100644
--- a/Swiften/FileTransfer/OutgoingFileTransfer.h
+++ b/Swiften/FileTransfer/OutgoingFileTransfer.h
@@ -6,47 +6,12 @@
 
 #pragma once
 
-#include <boost/shared_ptr.hpp>
-
-#include "Swiften/FileTransfer/ReadBytestream.h"
-#include "Swiften/Base/boost_bsignals.h"
-#include "Swiften/FileTransfer/FileTransferError.h"
-#include "Swiften/FileTransfer/SOCKS5BytestreamServer.h"
-#include "Swiften/JID/JID.h"
-#include "Swiften/Elements/StreamInitiation.h"
-#include "Swiften/Elements/Bytestreams.h"
-#include "Swiften/Elements/ErrorPayload.h"
-#include "Swiften/FileTransfer/IBBSendSession.h"
-
 namespace Swift {
-	class IQRouter;
-	class SOCKS5BytestreamServer;
-
 	class OutgoingFileTransfer {
 		public:
-			OutgoingFileTransfer(const std::string& id, const JID& from, const JID& to, const std::string& name, int size, const std::string& description, boost::shared_ptr<ReadBytestream> bytestream, IQRouter* iqRouter, SOCKS5BytestreamServer* socksServer);
-
-			void start();
-			void stop();
-
-			boost::signal<void (const boost::optional<FileTransferError>&)> onFinished;
-
-		private:
-			void handleStreamInitiationRequestResponse(StreamInitiation::ref, ErrorPayload::ref);
-			void handleBytestreamsRequestResponse(Bytestreams::ref, ErrorPayload::ref);
-			void finish(boost::optional<FileTransferError> error);
-			void handleIBBSessionFinished(boost::optional<FileTransferError> error);
+			virtual ~OutgoingFileTransfer();
 
-		private:
-			std::string id;
-			JID from;
-			JID to;
-			std::string name;
-			int size;
-			std::string description;
-			boost::shared_ptr<ReadBytestream> bytestream;
-			IQRouter* iqRouter;
-			SOCKS5BytestreamServer* socksServer;
-			boost::shared_ptr<IBBSendSession> ibbSession;
+			virtual void start() = 0;
+			virtual void stop() = 0;
 	};
 }
diff --git a/Swiften/FileTransfer/OutgoingSIFileTransfer.cpp b/Swiften/FileTransfer/OutgoingSIFileTransfer.cpp
new file mode 100644
index 0000000..2ed3a9d
--- /dev/null
+++ b/Swiften/FileTransfer/OutgoingSIFileTransfer.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include "Swiften/FileTransfer/OutgoingSIFileTransfer.h"
+
+#include <boost/bind.hpp>
+
+#include "Swiften/FileTransfer/StreamInitiationRequest.h"
+#include "Swiften/FileTransfer/BytestreamsRequest.h"
+#include "Swiften/FileTransfer/SOCKS5BytestreamServer.h"
+#include "Swiften/FileTransfer/IBBSendSession.h"
+
+namespace Swift {
+
+OutgoingSIFileTransfer::OutgoingSIFileTransfer(const std::string& id, const JID& from, const JID& to, const std::string& name, int size, const std::string& description, boost::shared_ptr<ReadBytestream> bytestream, IQRouter* iqRouter, SOCKS5BytestreamServer* socksServer) : id(id), from(from), to(to), name(name), size(size), description(description), bytestream(bytestream), iqRouter(iqRouter), socksServer(socksServer) {
+}
+
+void OutgoingSIFileTransfer::start() {
+	StreamInitiation::ref streamInitiation(new StreamInitiation());
+	streamInitiation->setID(id);
+	streamInitiation->setFileInfo(StreamInitiationFileInfo(name, description, size));
+	//streamInitiation->addProvidedMethod("http://jabber.org/protocol/bytestreams");
+	streamInitiation->addProvidedMethod("http://jabber.org/protocol/ibb");
+	StreamInitiationRequest::ref request = StreamInitiationRequest::create(to, streamInitiation, iqRouter);
+	request->onResponse.connect(boost::bind(&OutgoingSIFileTransfer::handleStreamInitiationRequestResponse, this, _1, _2));
+	request->send();
+}
+
+void OutgoingSIFileTransfer::stop() {
+}
+
+void OutgoingSIFileTransfer::handleStreamInitiationRequestResponse(StreamInitiation::ref response, ErrorPayload::ref error) {
+	if (error) {
+		finish(FileTransferError());
+	}
+	else {
+		if (response->getRequestedMethod() == "http://jabber.org/protocol/bytestreams") {
+			socksServer->addBytestream(id, from, to, bytestream); 
+			Bytestreams::ref bytestreams(new Bytestreams());
+			bytestreams->setStreamID(id);
+			HostAddressPort addressPort = socksServer->getAddressPort();
+			bytestreams->addStreamHost(Bytestreams::StreamHost(addressPort.getAddress().toString(), from, addressPort.getPort()));
+			BytestreamsRequest::ref request = BytestreamsRequest::create(to, bytestreams, iqRouter);
+			request->onResponse.connect(boost::bind(&OutgoingSIFileTransfer::handleBytestreamsRequestResponse, this, _1, _2));
+			request->send();
+		}
+		else if (response->getRequestedMethod() == "http://jabber.org/protocol/ibb") {
+			ibbSession = boost::shared_ptr<IBBSendSession>(new IBBSendSession(id, to, bytestream, iqRouter));
+			ibbSession->onFinished.connect(boost::bind(&OutgoingSIFileTransfer::handleIBBSessionFinished, this, _1));
+			ibbSession->start();
+		}
+	}
+}
+
+void OutgoingSIFileTransfer::handleBytestreamsRequestResponse(Bytestreams::ref, ErrorPayload::ref error) {
+	if (error) {
+		finish(FileTransferError());
+	}
+	//socksServer->onTransferFinished.connect();
+}
+
+void OutgoingSIFileTransfer::finish(boost::optional<FileTransferError> error) {
+	if (ibbSession) {
+		ibbSession->onFinished.disconnect(boost::bind(&OutgoingSIFileTransfer::handleIBBSessionFinished, this, _1));
+		ibbSession.reset();
+	}
+	socksServer->removeBytestream(id, from, to); 
+	onFinished(error);
+}
+
+void OutgoingSIFileTransfer::handleIBBSessionFinished(boost::optional<FileTransferError> error) {
+	finish(error);
+}
+
+}
diff --git a/Swiften/FileTransfer/OutgoingSIFileTransfer.h b/Swiften/FileTransfer/OutgoingSIFileTransfer.h
new file mode 100644
index 0000000..cdf988f
--- /dev/null
+++ b/Swiften/FileTransfer/OutgoingSIFileTransfer.h
@@ -0,0 +1,53 @@
+/*
+ * 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 <boost/shared_ptr.hpp>
+
+#include <Swiften/FileTransfer/OutgoingFileTransfer.h>
+#include "Swiften/FileTransfer/ReadBytestream.h"
+#include "Swiften/Base/boost_bsignals.h"
+#include "Swiften/FileTransfer/FileTransferError.h"
+#include "Swiften/FileTransfer/SOCKS5BytestreamServer.h"
+#include "Swiften/JID/JID.h"
+#include "Swiften/Elements/StreamInitiation.h"
+#include "Swiften/Elements/Bytestreams.h"
+#include "Swiften/Elements/ErrorPayload.h"
+#include "Swiften/FileTransfer/IBBSendSession.h"
+
+namespace Swift {
+	class IQRouter;
+	class SOCKS5BytestreamServer;
+
+	class OutgoingSIFileTransfer : public OutgoingFileTransfer {
+		public:
+			OutgoingSIFileTransfer(const std::string& id, const JID& from, const JID& to, const std::string& name, int size, const std::string& description, boost::shared_ptr<ReadBytestream> bytestream, IQRouter* iqRouter, SOCKS5BytestreamServer* socksServer);
+
+			virtual void start();
+			virtual void stop();
+
+			boost::signal<void (const boost::optional<FileTransferError>&)> onFinished;
+
+		private:
+			void handleStreamInitiationRequestResponse(StreamInitiation::ref, ErrorPayload::ref);
+			void handleBytestreamsRequestResponse(Bytestreams::ref, ErrorPayload::ref);
+			void finish(boost::optional<FileTransferError> error);
+			void handleIBBSessionFinished(boost::optional<FileTransferError> error);
+
+		private:
+			std::string id;
+			JID from;
+			JID to;
+			std::string name;
+			int size;
+			std::string description;
+			boost::shared_ptr<ReadBytestream> bytestream;
+			IQRouter* iqRouter;
+			SOCKS5BytestreamServer* socksServer;
+			boost::shared_ptr<IBBSendSession> ibbSession;
+	};
+}
diff --git a/Swiften/FileTransfer/ReadBytestream.h b/Swiften/FileTransfer/ReadBytestream.h
index 4da2bc2..529545e 100644
--- a/Swiften/FileTransfer/ReadBytestream.h
+++ b/Swiften/FileTransfer/ReadBytestream.h
@@ -6,13 +6,13 @@
 
 #pragma once
 
-#include "Swiften/Base/ByteArray.h"
+#include <vector>
 
 namespace Swift {
 	class ReadBytestream {
 		public:
 			virtual ~ReadBytestream();
-			virtual ByteArray read(size_t size) = 0;
+			virtual std::vector<unsigned char> read(size_t size) = 0;
 			virtual bool isFinished() const = 0;
 	};
 }
diff --git a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.cpp b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.cpp
new file mode 100644
index 0000000..338f221
--- /dev/null
+++ b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.cpp
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h>
+
+namespace Swift {
+
+RemoteJingleTransportCandidateSelector::~RemoteJingleTransportCandidateSelector() {
+}
+
+}
diff --git a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h
new file mode 100644
index 0000000..b12b06b
--- /dev/null
+++ b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/boost_bsignals.h>
+
+#include <Swiften/Elements/JingleTransportPayload.h>
+#include <Swiften/FileTransfer/JingleTransport.h>
+
+namespace Swift {
+	class RemoteJingleTransportCandidateSelector {
+		public:
+			virtual ~RemoteJingleTransportCandidateSelector();
+
+			virtual void addRemoteTransportCandidates(JingleTransportPayload::ref) = 0;
+			virtual void selectCandidate() = 0;
+			virtual void setMinimumPriority(int) = 0;
+
+			virtual bool isActualCandidate(JingleTransportPayload::ref) = 0;
+			virtual int getPriority(JingleTransportPayload::ref) = 0;
+			virtual JingleTransport::ref selectTransport(JingleTransportPayload::ref) = 0;
+
+			boost::signal<void (JingleTransportPayload::ref)> onRemoteTransportCandidateSelectFinished;
+	};
+}
diff --git a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.cpp b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.cpp
new file mode 100644
index 0000000..36b7cba
--- /dev/null
+++ b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.cpp
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h>
+
+namespace Swift {
+
+RemoteJingleTransportCandidateSelectorFactory::~RemoteJingleTransportCandidateSelectorFactory() {
+}
+
+}
diff --git a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h
new file mode 100644
index 0000000..caa3097
--- /dev/null
+++ b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+namespace Swift {
+	class RemoteJingleTransportCandidateSelector;
+
+	class RemoteJingleTransportCandidateSelectorFactory {
+		public:
+			virtual ~RemoteJingleTransportCandidateSelectorFactory();
+
+			virtual RemoteJingleTransportCandidateSelector* createCandidateSelector() = 0;
+	};
+}
diff --git a/Swiften/FileTransfer/SConscript b/Swiften/FileTransfer/SConscript
index ea9e7bb..24fc9e8 100644
--- a/Swiften/FileTransfer/SConscript
+++ b/Swiften/FileTransfer/SConscript
@@ -1,10 +1,17 @@
-Import("swiften_env")
+Import("swiften_env", "env")
 
 sources = [
 		"OutgoingFileTransfer.cpp",
+		"OutgoingSIFileTransfer.cpp",
 		"IncomingFileTransfer.cpp",
 		"IncomingJingleFileTransfer.cpp",
-		"IncomingFileTransferManager.cpp",	
+		"IncomingFileTransferManager.cpp",
+		"RemoteJingleTransportCandidateSelector.cpp",
+		"RemoteJingleTransportCandidateSelectorFactory.cpp",
+		"LocalJingleTransportCandidateGenerator.cpp",
+		"LocalJingleTransportCandidateGeneratorFactory.cpp",
+		"JingleTransport.cpp",
+		"JingleIncomingIBBTransport.cpp",
 		"ReadBytestream.cpp",
 		"WriteBytestream.cpp",
 		"FileReadBytestream.cpp",
@@ -17,3 +24,9 @@ sources = [
 	]
 
 swiften_env.Append(SWIFTEN_OBJECTS = swiften_env.SwiftenObject(sources))
+
+env.Append(UNITTEST_SOURCES = [
+			File("UnitTest/SOCKS5BytestreamServerSessionTest.cpp"),
+			File("UnitTest/IBBSendSessionTest.cpp"),
+			File("UnitTest/IBBReceiveSessionTest.cpp"),
+	])
diff --git a/Swiften/FileTransfer/UnitTest/IBBReceiveSessionTest.cpp b/Swiften/FileTransfer/UnitTest/IBBReceiveSessionTest.cpp
new file mode 100644
index 0000000..88d9cd4
--- /dev/null
+++ b/Swiften/FileTransfer/UnitTest/IBBReceiveSessionTest.cpp
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <vector>
+#include <boost/bind.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Base/ByteArray.h>
+#include "Swiften/FileTransfer/IBBReceiveSession.h"
+#include "Swiften/Queries/IQRouter.h"
+#include "Swiften/Client/DummyStanzaChannel.h"
+
+using namespace Swift;
+
+class IBBReceiveSessionTest : public CppUnit::TestFixture {
+		CPPUNIT_TEST_SUITE(IBBReceiveSessionTest);
+		CPPUNIT_TEST(testOpen);
+		CPPUNIT_TEST(testReceiveData);
+		CPPUNIT_TEST(testReceiveMultipleData);
+		CPPUNIT_TEST(testReceiveDataForOtherSession);
+		CPPUNIT_TEST(testReceiveDataOutOfOrder);
+		CPPUNIT_TEST(testReceiveLastData);
+		CPPUNIT_TEST(testReceiveClose);
+		CPPUNIT_TEST(testStopWhileActive);
+		CPPUNIT_TEST_SUITE_END();
+
+	public:
+		void setUp() {
+			stanzaChannel = new DummyStanzaChannel();
+			iqRouter = new IQRouter(stanzaChannel);
+		}
+
+		void tearDown() {
+			delete iqRouter;
+			delete stanzaChannel;
+		}
+
+		void testOpen() {
+			std::auto_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession"));
+			testling->start();
+			stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open"));
+
+			CPPUNIT_ASSERT(stanzaChannel->isResultAtIndex(0, "id-open"));
+			CPPUNIT_ASSERT(!finished);
+
+			testling->stop();
+		}
+
+		void testReceiveData() {
+			std::auto_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession"));
+			testling->start();
+			stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open"));
+
+			stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 0, ByteArray::create("abc")), "foo@bar.com/baz", "id-a"));
+
+			CPPUNIT_ASSERT(stanzaChannel->isResultAtIndex(1, "id-a"));
+			CPPUNIT_ASSERT(ByteArray::create("abc") == receivedData);
+			CPPUNIT_ASSERT(!finished);
+
+			testling->stop();
+		}
+
+		void testReceiveMultipleData() {
+			std::auto_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession"));
+			testling->start();
+			stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open"));
+
+			stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 0, ByteArray::create("abc")), "foo@bar.com/baz", "id-a"));
+			stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 1, ByteArray::create("def")), "foo@bar.com/baz", "id-b"));
+
+			CPPUNIT_ASSERT(stanzaChannel->isResultAtIndex(2, "id-b"));
+			CPPUNIT_ASSERT(ByteArray::create("abcdef") == receivedData);
+			CPPUNIT_ASSERT(!finished);
+
+			testling->stop();
+		}
+
+		void testReceiveDataForOtherSession() {
+			std::auto_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession"));
+			testling->start();
+			stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open"));
+
+			stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("othersession", 0, ByteArray::create("abc")), "foo@bar.com/baz", "id-a"));
+
+			CPPUNIT_ASSERT(stanzaChannel->isErrorAtIndex(1, "id-a"));
+
+			testling->stop();
+		}
+
+		void testReceiveDataOutOfOrder() {
+			std::auto_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession"));
+			testling->start();
+			stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open"));
+
+			stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 0, ByteArray::create("abc")), "foo@bar.com/baz", "id-a"));
+			stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 0, ByteArray::create("def")), "foo@bar.com/baz", "id-b"));
+
+			CPPUNIT_ASSERT(stanzaChannel->isErrorAtIndex(2, "id-b"));
+			CPPUNIT_ASSERT(finished);
+			CPPUNIT_ASSERT(error);
+
+			testling->stop();
+		}
+
+		void testReceiveLastData() {
+			std::auto_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession", 6));
+			testling->start();
+			stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open"));
+
+			stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 0, ByteArray::create("abc")), "foo@bar.com/baz", "id-a"));
+			stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 1, ByteArray::create("def")), "foo@bar.com/baz", "id-b"));
+
+			CPPUNIT_ASSERT(stanzaChannel->isResultAtIndex(2, "id-b"));
+			CPPUNIT_ASSERT(ByteArray::create("abcdef") == receivedData);
+			CPPUNIT_ASSERT(finished);
+			CPPUNIT_ASSERT(!error);
+
+			testling->stop();
+		}
+
+		void testReceiveClose() {
+			std::auto_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession"));
+			testling->start();
+			stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open"));
+
+			stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBClose("mysession"), "foo@bar.com/baz", "id-close"));
+
+			CPPUNIT_ASSERT(finished);
+			CPPUNIT_ASSERT(error);
+
+			testling->stop();
+		}
+
+		void testStopWhileActive() {
+			std::auto_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession"));
+			testling->start();
+			stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open"));
+
+			testling->stop();
+
+			CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<IBB>(1, JID("foo@bar.com/baz"), IQ::Set));
+			IBB::ref ibb = stanzaChannel->sentStanzas[1]->getPayload<IBB>();
+			CPPUNIT_ASSERT_EQUAL(IBB::Close, ibb->getAction());
+			CPPUNIT_ASSERT_EQUAL(std::string("mysession"), ibb->getStreamID());
+			CPPUNIT_ASSERT(finished);
+			CPPUNIT_ASSERT(!error);
+		}
+
+	private:
+		IQ::ref createIBBRequest(IBB::ref ibb, const JID& from, const std::string& id) {
+			IQ::ref request = IQ::createRequest(IQ::Set, JID("baz@fum.com/dum"), id, ibb);
+			request->setFrom(from);
+			return request;
+		}
+
+		IBBReceiveSession* createSession(const std::string& from, const std::string& id, size_t size = 0x1000) {
+			IBBReceiveSession* session = new IBBReceiveSession(id, JID(from), size, iqRouter);
+			session->onDataReceived.connect(boost::bind(&IBBReceiveSessionTest::handleDataReceived, this, _1));
+			session->onFinished.connect(boost::bind(&IBBReceiveSessionTest::handleFinished, this, _1));
+			return session;
+		}
+
+
+		void handleFinished(boost::optional<FileTransferError> error) {
+			finished = true;
+			this->error = error;
+		}
+
+		void handleDataReceived(const std::vector<unsigned char>& data) {
+			receivedData.insert(receivedData.end(), data.begin(), data.end());
+		}
+
+	private:
+		DummyStanzaChannel* stanzaChannel;
+		IQRouter* iqRouter;
+		bool finished;
+		boost::optional<FileTransferError> error;
+		std::vector<unsigned char> receivedData;
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(IBBReceiveSessionTest);
diff --git a/Swiften/FileTransfer/UnitTest/IBBSendSessionTest.cpp b/Swiften/FileTransfer/UnitTest/IBBSendSessionTest.cpp
index 0cd273a..32df34b 100644
--- a/Swiften/FileTransfer/UnitTest/IBBSendSessionTest.cpp
+++ b/Swiften/FileTransfer/UnitTest/IBBSendSessionTest.cpp
@@ -4,13 +4,12 @@
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
 
-#include "Swiften/Base/ByteArray.h"
-
 #include <cppunit/extensions/HelperMacros.h>
 #include <cppunit/extensions/TestFactoryRegistry.h>
 #include <vector>
 #include <boost/bind.hpp>
 
+#include "Swiften/Base/ByteArray.h"
 #include "Swiften/FileTransfer/IBBSendSession.h"
 #include "Swiften/FileTransfer/ByteArrayReadBytestream.h"
 #include "Swiften/Queries/IQRouter.h"
@@ -33,7 +32,7 @@ class IBBSendSessionTest : public CppUnit::TestFixture {
 		void setUp() {
 			stanzaChannel = new DummyStanzaChannel();
 			iqRouter = new IQRouter(stanzaChannel);
-			bytestream = boost::shared_ptr<ByteArrayReadBytestream>(new ByteArrayReadBytestream(ByteArray("abcdefg")));
+			bytestream = boost::shared_ptr<ByteArrayReadBytestream>(new ByteArrayReadBytestream(ByteArray::create("abcdefg")));
 		}
 
 		void tearDown() {
@@ -66,7 +65,7 @@ class IBBSendSessionTest : public CppUnit::TestFixture {
 			CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<IBB>(1, JID("foo@bar.com/baz"), IQ::Set));
 			IBB::ref ibb = stanzaChannel->sentStanzas[1]->getPayload<IBB>();
 			CPPUNIT_ASSERT_EQUAL(IBB::Data, ibb->getAction());
-			CPPUNIT_ASSERT_EQUAL(ByteArray("abc"), ibb->getData());
+			CPPUNIT_ASSERT(ByteArray::create("abc") == ibb->getData());
 			CPPUNIT_ASSERT_EQUAL(0, ibb->getSequenceNumber());
 			CPPUNIT_ASSERT_EQUAL(std::string("myid"), ibb->getStreamID());
 		}
@@ -82,7 +81,7 @@ class IBBSendSessionTest : public CppUnit::TestFixture {
 			CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<IBB>(2, JID("foo@bar.com/baz"), IQ::Set));
 			IBB::ref ibb = stanzaChannel->sentStanzas[2]->getPayload<IBB>();
 			CPPUNIT_ASSERT_EQUAL(IBB::Data, ibb->getAction());
-			CPPUNIT_ASSERT_EQUAL(ByteArray("def"), ibb->getData());
+			CPPUNIT_ASSERT(ByteArray::create("def") == ibb->getData());
 			CPPUNIT_ASSERT_EQUAL(1, ibb->getSequenceNumber());
 			CPPUNIT_ASSERT_EQUAL(std::string("myid"), ibb->getStreamID());
 		}
diff --git a/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp b/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp
index c6d246d..1c1a246 100644
--- a/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp
+++ b/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp
@@ -35,7 +35,7 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture {
 			eventLoop = new DummyEventLoop();
 			connection = boost::shared_ptr<DummyConnection>(new DummyConnection(eventLoop));
 			connection->onDataSent.connect(boost::bind(&SOCKS5BytestreamServerSessionTest::handleDataWritten, this, _1));
-			stream1 = boost::shared_ptr<ByteArrayReadBytestream>(new ByteArrayReadBytestream(ByteArray("abcdefg")));
+			stream1 = boost::shared_ptr<ByteArrayReadBytestream>(new ByteArrayReadBytestream(ByteArray::create("abcdefg")));
 		}
 
 		void tearDown() {
@@ -47,20 +47,20 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture {
 			std::auto_ptr<SOCKS5BytestreamServerSession> testling(createSession());
 			StartStopper<SOCKS5BytestreamServerSession> stopper(testling.get());
 
-			receive(ByteArray("\x05\x02\x01\x02"));
+			receive(ByteArray::create("\x05\x02\x01\x02"));
 
-			CPPUNIT_ASSERT_EQUAL(ByteArray("\x05\x00", 2), receivedData);
+			CPPUNIT_ASSERT(ByteArray::create("\x05\x00", 2) == receivedData);
 		}
 
 		void testAuthenticate_Chunked() {
 			std::auto_ptr<SOCKS5BytestreamServerSession> testling(createSession());
 			StartStopper<SOCKS5BytestreamServerSession> stopper(testling.get());
 
-			receive(ByteArray("\x05\x02\x01"));
+			receive(ByteArray::create("\x05\x02\x01"));
 
-			CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(receivedData.getSize()));
-			receive(ByteArray("\x01"));
-			CPPUNIT_ASSERT_EQUAL(ByteArray("\x05\x00", 2), receivedData);
+			CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(receivedData.size()));
+			receive(ByteArray::create("\x01"));
+			CPPUNIT_ASSERT(ByteArray::create("\x05\x00", 2) == receivedData);
 		}
 
 		void testRequest() {
@@ -70,8 +70,8 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture {
 			authenticate();
 
 			ByteArray hostname("abcdef");
-			receive(ByteArray("\x05\x01\x00\x03", 4) + hostname.getSize() + hostname + ByteArray("\x00\x00", 2));
-			CPPUNIT_ASSERT_EQUAL(ByteArray("\x05\x00\x00\x03\x06\x61\x62\x63\x64\x65\x66\x00\x00", 13), ByteArray(receivedData.getData(), 13));
+			receive(ByteArray(ByteArray::create("\x05\x01\x00\x03", 4)) + hostname.getSize() + hostname + ByteArray::create("\x00\x00", 2));
+			CPPUNIT_ASSERT(ByteArray::create("\x05\x00\x00\x03\x06\x61\x62\x63\x64\x65\x66\x00\x00", 13) == ByteArray::create(&receivedData[0], 13));
 		}
 
 		void testRequest_UnknownBytestream() {
@@ -80,8 +80,8 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture {
 			authenticate();
 
 			ByteArray hostname("abcdef");
-			receive(ByteArray("\x05\x01\x00\x03", 4) + hostname.getSize() + hostname + ByteArray("\x00\x00", 2));
-			CPPUNIT_ASSERT_EQUAL(ByteArray("\x05\x04\x00\x03\x06\x61\x62\x63\x64\x65\x66\x00\x00", 13), receivedData);
+			receive(ByteArray(ByteArray::create("\x05\x01\x00\x03", 4)) + hostname.getSize() + hostname + ByteArray::create("\x00\x00", 2));
+			CPPUNIT_ASSERT(ByteArray::create("\x05\x04\x00\x03\x06\x61\x62\x63\x64\x65\x66\x00\x00", 13) == receivedData);
 		}
 
 		void testReceiveData() {
@@ -93,7 +93,7 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture {
 			eventLoop->processEvents();
 			skipHeader("abcdef");
 
-			CPPUNIT_ASSERT_EQUAL(ByteArray("abcdefg"), receivedData);
+			CPPUNIT_ASSERT(ByteArray::create("abcdefg") == receivedData);
 			CPPUNIT_ASSERT_EQUAL(2, receivedDataChunks);
 		}
 
@@ -107,7 +107,7 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture {
 			eventLoop->processEvents();
 
 			skipHeader("abcdef");
-			CPPUNIT_ASSERT_EQUAL(ByteArray("abcdefg"), receivedData);
+			CPPUNIT_ASSERT(ByteArray::create("abcdefg") == receivedData);
 			CPPUNIT_ASSERT_EQUAL(4, receivedDataChunks);
 		}
 
@@ -118,23 +118,23 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture {
 		}
 
 		void authenticate() {
-			receive(ByteArray("\x05\x02\x01\x02"));
+			receive(ByteArray::create("\x05\x02\x01\x02"));
 			receivedData.clear();
 			receivedDataChunks = 0;
 		}
 
 		void request(const std::string& hostname) {
-			receive(ByteArray("\x05\x01\x00\x03", 4) + hostname.size() + hostname + ByteArray("\x00\x00", 2));
+			receive(ByteArray(ByteArray::create("\x05\x01\x00\x03", 4)) + hostname.size() + hostname + ByteArray::create("\x00\x00", 2));
 		}
 
 		void skipHeader(const std::string& hostname) {
 			int headerSize = 7 + hostname.size();
-			receivedData = ByteArray(receivedData.getData() + headerSize, receivedData.getSize() - headerSize);
+			receivedData = ByteArray::create(&receivedData[headerSize], receivedData.size() - headerSize);
 		}
 
 
 		void handleDataWritten(const ByteArray& data) {
-			receivedData += data;
+			receivedData.insert(receivedData.end(), data.begin(), data.end());
 			receivedDataChunks++;
 		}
 
@@ -148,7 +148,7 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture {
 		DummyEventLoop* eventLoop;
 		SOCKS5BytestreamRegistry bytestreams;
 		boost::shared_ptr<DummyConnection> connection;
-		ByteArray receivedData;
+		std::vector<unsigned char> receivedData;
 		int receivedDataChunks;
 		boost::shared_ptr<ByteArrayReadBytestream> stream1;
 };
diff --git a/Swiften/FileTransfer/WriteBytestream.h b/Swiften/FileTransfer/WriteBytestream.h
index 1dc791c..c27aeff 100644
--- a/Swiften/FileTransfer/WriteBytestream.h
+++ b/Swiften/FileTransfer/WriteBytestream.h
@@ -7,8 +7,7 @@
 #pragma once
 
 #include <boost/shared_ptr.hpp>
-
-#include "Swiften/Base/ByteArray.h"
+#include <vector>
 
 namespace Swift {
 	class WriteBytestream {
@@ -17,6 +16,6 @@ namespace Swift {
 
 			virtual ~WriteBytestream();
 
-			virtual void write(const ByteArray&) = 0;
+			virtual void write(const std::vector<unsigned char>&) = 0;
 	};
 }
diff --git a/Swiften/Jingle/IncomingJingleSession.cpp b/Swiften/Jingle/IncomingJingleSession.cpp
deleted file mode 100644
index b18d9d3..0000000
--- a/Swiften/Jingle/IncomingJingleSession.cpp
+++ /dev/null
@@ -1,15 +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 <Swiften/Jingle/IncomingJingleSession.h>
-
-namespace Swift {
-
-IncomingJingleSession::IncomingJingleSession(const std::string& id, const std::vector<JingleContent::ref>& contents) : JingleSession(id, contents) {
-
-}
-
-}
diff --git a/Swiften/Jingle/IncomingJingleSession.h b/Swiften/Jingle/IncomingJingleSession.h
deleted file mode 100644
index 64816f6..0000000
--- a/Swiften/Jingle/IncomingJingleSession.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (c) 2011 Remko Tronçon
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
- */
-
-#pragma once
-
-#include <boost/shared_ptr.hpp>
-
-#include <Swiften/Jingle/JingleSession.h>
-
-namespace Swift {
-	class IncomingJingleSession : public JingleSession {
-		public:
-			IncomingJingleSession(const std::string& id, const std::vector<JingleContent::ref>& contents);
-
-			typedef boost::shared_ptr<IncomingJingleSession> ref;
-	};
-}
diff --git a/Swiften/Jingle/IncomingJingleSessionHandler.h b/Swiften/Jingle/IncomingJingleSessionHandler.h
index 5bf9237..4d22a4e 100644
--- a/Swiften/Jingle/IncomingJingleSessionHandler.h
+++ b/Swiften/Jingle/IncomingJingleSessionHandler.h
@@ -6,13 +6,13 @@
 
 #pragma once
 
-#include <Swiften/Jingle/IncomingJingleSession.h>
+#include <Swiften/Jingle/JingleSession.h>
 
 namespace Swift {
 	class IncomingJingleSessionHandler {
 		public:
 			virtual ~IncomingJingleSessionHandler();
 
-			virtual bool handleIncomingJingleSession(IncomingJingleSession::ref) = 0;
+			virtual bool handleIncomingJingleSession(JingleSession::ref, const std::vector<JingleContentPayload::ref>& contents) = 0;
 	};
 }
diff --git a/Swiften/Jingle/Jingle.h b/Swiften/Jingle/Jingle.h
new file mode 100644
index 0000000..ba4dfe3
--- /dev/null
+++ b/Swiften/Jingle/Jingle.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <vector>
+
+#include <Swiften/Elements/JingleContentPayload.h>
+
+namespace Swift {
+	namespace Jingle {
+		template<typename T>
+		JingleContentPayload::ref getContentWithDescription(const std::vector<JingleContentPayload::ref>& contents) {
+			for (size_t i = 0; i < contents.size(); ++i) {
+				if (contents[i]->getDescription<T>()) {
+					return contents[i];
+				}
+			}
+			return JingleContentPayload::ref();
+		}
+	}
+}
diff --git a/Swiften/Jingle/JingleContentID.h b/Swiften/Jingle/JingleContentID.h
new file mode 100644
index 0000000..8d75581
--- /dev/null
+++ b/Swiften/Jingle/JingleContentID.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <Swiften/Elements/JingleContentPayload.h>
+
+namespace Swift {
+	class JingleContentID {
+		public:
+			JingleContentID(const std::string& name, JingleContentPayload::Creator creator) : name(name), creator(creator) {
+			}
+
+		private:
+			std::string name;
+			JingleContentPayload::Creator creator;
+	};
+}
diff --git a/Swiften/Jingle/JingleResponder.cpp b/Swiften/Jingle/JingleResponder.cpp
index 2397e63..198f9a2 100644
--- a/Swiften/Jingle/JingleResponder.cpp
+++ b/Swiften/Jingle/JingleResponder.cpp
@@ -9,7 +9,7 @@
 #include <boost/smart_ptr/make_shared.hpp>
 
 #include <Swiften/Jingle/JingleSessionManager.h>
-#include <Swiften/Jingle/IncomingJingleSession.h>
+#include <Swiften/Jingle/JingleSessionImpl.h>
 
 namespace Swift {
 
@@ -24,12 +24,12 @@ bool JingleResponder::handleSetRequest(const JID& from, const JID&, const std::s
 		}
 		else {
 			sendResponse(from, id, boost::shared_ptr<JinglePayload>());
-			IncomingJingleSession::ref session = boost::make_shared<IncomingJingleSession>(id, payload->getContents());
-			sessionManager->handleIncomingSession(from, session);
+			JingleSessionImpl::ref session = boost::make_shared<JingleSessionImpl>(payload->getInitiator(), payload->getSessionID());
+			sessionManager->handleIncomingSession(from, session, payload->getContents());
 		}
 	}
 	else {
-		JingleSession::ref session = sessionManager->getSession(from, payload->getSessionID());
+		JingleSessionImpl::ref session = sessionManager->getSession(from, payload->getSessionID());
 		if (session) {
 			session->handleIncomingAction(payload);
 			sendResponse(from, id, boost::shared_ptr<JinglePayload>());
diff --git a/Swiften/Jingle/JingleSession.cpp b/Swiften/Jingle/JingleSession.cpp
index d255abd..1366191 100644
--- a/Swiften/Jingle/JingleSession.cpp
+++ b/Swiften/Jingle/JingleSession.cpp
@@ -10,21 +10,11 @@
 
 namespace Swift {
 
-JingleSession::JingleSession(const std::string& id, const std::vector<JingleContent::ref>& contents) : id(id), contents(contents) {
+JingleSession::JingleSession(const JID& initiator, const std::string& id) : initiator(initiator), id(id) {
 
 }
 
 JingleSession::~JingleSession() {
 }
 
-void JingleSession::handleIncomingAction(JinglePayload::ref) {
-}
-
-void JingleSession::terminate(JinglePayload::Reason::Type reason) {
-	JinglePayload::ref payload = boost::make_shared<JinglePayload>(JinglePayload::SessionTerminate, id);
-	payload->setReason(JinglePayload::Reason(reason));
-	//onAction(payload)
-}
-
-
 }
diff --git a/Swiften/Jingle/JingleSession.h b/Swiften/Jingle/JingleSession.h
index b57701b..fa7da7e 100644
--- a/Swiften/Jingle/JingleSession.h
+++ b/Swiften/Jingle/JingleSession.h
@@ -7,46 +7,43 @@
 #pragma once
 
 #include <boost/shared_ptr.hpp>
+#include <string>
 
 #include <Swiften/Base/boost_bsignals.h>
-#include <string>
+#include <Swiften/JID/JID.h>
 #include <Swiften/Elements/JinglePayload.h>
-#include <Swiften/Elements/JingleContent.h>
 
 namespace Swift {
+	class JingleContentID;
+
 	class JingleSession {
-			friend class JingleResponder;
 		public:
 			typedef boost::shared_ptr<JingleSession> ref;
 
-			JingleSession(const std::string& id, const std::vector<JingleContent::ref>& contents);
+			JingleSession(const JID& initiator, const std::string& id);
 			virtual ~JingleSession();
 
-			std::string getID() const {
-				return id;
+			const JID& getInitiator() const {
+				return initiator;
 			}
 
-			template<typename T>
-			JingleContent::ref getContentWithDescription() const {
-				for (size_t i = 0; i < contents.size(); ++i) {
-					if (contents[i]->getDescription<T>()) {
-						return contents[i];
-					}
-				}
-				return JingleContent::ref();
-			}
-
-			const std::vector<JingleContent::ref> getContents() const {
-				return contents;
+			std::string getID() const {
+				return id;
 			}
 
-			void terminate(JinglePayload::Reason::Type reason);
+			virtual void terminate(JinglePayload::Reason::Type reason) = 0;
+			virtual void accept(JingleTransportPayload::ref = JingleTransportPayload::ref()) = 0;
+			virtual void sendTransportInfo(const JingleContentID&, JingleTransportPayload::ref) = 0;
+			virtual void acceptTransport(const JingleContentID&, JingleTransportPayload::ref) = 0;
+			virtual void rejectTransport(const JingleContentID&, JingleTransportPayload::ref) = 0;
 
-		private:
-			void handleIncomingAction(JinglePayload::ref);
+		public:
+			boost::signal<void ()> onSessionTerminateReceived;
+			boost::signal<void (const JingleContentID&, JingleTransportPayload::ref)> onTransportInfoReceived;
+			boost::signal<void (const JingleContentID&, JingleTransportPayload::ref)> onTransportReplaceReceived;
 
 		private:
+			JID initiator;
 			std::string id;
-			std::vector<JingleContent::ref> contents;
 	};
 }
diff --git a/Swiften/Jingle/JingleSessionImpl.cpp b/Swiften/Jingle/JingleSessionImpl.cpp
new file mode 100644
index 0000000..cbb2b42
--- /dev/null
+++ b/Swiften/Jingle/JingleSessionImpl.cpp
@@ -0,0 +1,42 @@
+/*
+ * 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>
+
+namespace Swift {
+
+JingleSessionImpl::JingleSessionImpl(const JID& initiator, const std::string& id) : JingleSession(initiator, id) {
+}
+
+void JingleSessionImpl::handleIncomingAction(JinglePayload::ref) {
+}
+
+void JingleSessionImpl::terminate(JinglePayload::Reason::Type reason) {
+	JinglePayload::ref payload = boost::make_shared<JinglePayload>(JinglePayload::SessionTerminate, getID());
+	payload->setReason(JinglePayload::Reason(reason));
+	//onAction(payload)
+}
+
+void JingleSessionImpl::acceptTransport(const JingleContentID&, JingleTransportPayload::ref) {
+
+}
+
+void JingleSessionImpl::rejectTransport(const JingleContentID&, JingleTransportPayload::ref) {
+
+}
+
+void JingleSessionImpl::accept(JingleTransportPayload::ref) {
+}
+
+void JingleSessionImpl::sendTransportInfo(const JingleContentID&, JingleTransportPayload::ref) {
+
+}
+
+
+
+}
diff --git a/Swiften/Jingle/JingleSessionImpl.h b/Swiften/Jingle/JingleSessionImpl.h
new file mode 100644
index 0000000..a254ead
--- /dev/null
+++ b/Swiften/Jingle/JingleSessionImpl.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Jingle/JingleSession.h>
+
+namespace Swift {
+	class JingleSessionImpl : public JingleSession {
+			friend class JingleResponder;
+		public:
+			typedef boost::shared_ptr<JingleSessionImpl> ref;
+
+			JingleSessionImpl(const JID& initiator, const std::string& id);
+
+			virtual void terminate(JinglePayload::Reason::Type reason);
+			virtual void accept(JingleTransportPayload::ref);
+			virtual void sendTransportInfo(const JingleContentID&, JingleTransportPayload::ref);
+			virtual void acceptTransport(const JingleContentID&, JingleTransportPayload::ref);
+			virtual void rejectTransport(const JingleContentID&, JingleTransportPayload::ref);
+
+		private:
+			void handleIncomingAction(JinglePayload::ref);
+	};
+}
diff --git a/Swiften/Jingle/JingleSessionManager.cpp b/Swiften/Jingle/JingleSessionManager.cpp
index af512e8..58e90c8 100644
--- a/Swiften/Jingle/JingleSessionManager.cpp
+++ b/Swiften/Jingle/JingleSessionManager.cpp
@@ -19,9 +19,9 @@ JingleSessionManager::~JingleSessionManager() {
 	delete responder;
 }
 
-JingleSession::ref JingleSessionManager::getSession(const JID& jid, const std::string& id) const {
+JingleSessionImpl::ref JingleSessionManager::getSession(const JID& jid, const std::string& id) const {
 	SessionMap::const_iterator i = incomingSessions.find(JIDSession(jid, id));
-	return i != incomingSessions.end() ? i->second : JingleSession::ref();
+	return i != incomingSessions.end() ? i->second : JingleSessionImpl::ref();
 }
 
 void JingleSessionManager::addIncomingSessionHandler(IncomingJingleSessionHandler* handler) {
@@ -32,10 +32,10 @@ void JingleSessionManager::removeIncomingSessionHandler(IncomingJingleSessionHan
 	incomingSessionHandlers.erase(std::remove(incomingSessionHandlers.begin(), incomingSessionHandlers.end(), handler), incomingSessionHandlers.end());
 }
 
-void JingleSessionManager::handleIncomingSession(const JID& from, IncomingJingleSession::ref session) {
+void JingleSessionManager::handleIncomingSession(const JID& from, JingleSessionImpl::ref session, const std::vector<JingleContentPayload::ref>& contents) {
 	incomingSessions.insert(std::make_pair(JIDSession(from, session->getID()), session));
 	foreach (IncomingJingleSessionHandler* handler, incomingSessionHandlers) {
-		if (handler->handleIncomingJingleSession(session)) {
+		if (handler->handleIncomingJingleSession(session, contents)) {
 			return;
 		}
 	}
diff --git a/Swiften/Jingle/JingleSessionManager.h b/Swiften/Jingle/JingleSessionManager.h
index 3e99656..3b23fb0 100644
--- a/Swiften/Jingle/JingleSessionManager.h
+++ b/Swiften/Jingle/JingleSessionManager.h
@@ -10,7 +10,7 @@
 #include <map>
 
 #include <Swiften/Base/boost_bsignals.h>
-#include <Swiften/Jingle/IncomingJingleSession.h>
+#include <Swiften/Jingle/JingleSessionImpl.h>
 
 namespace Swift {
 	class IQRouter;
@@ -23,13 +23,13 @@ namespace Swift {
 			JingleSessionManager(IQRouter* router);
 			~JingleSessionManager();
 
-			JingleSession::ref getSession(const JID& jid, const std::string& id) const;
+			JingleSessionImpl::ref getSession(const JID& jid, const std::string& id) const;
 
 			void addIncomingSessionHandler(IncomingJingleSessionHandler* handler);
 			void removeIncomingSessionHandler(IncomingJingleSessionHandler* handler);
 
 		protected:
-			void handleIncomingSession(const JID& from, IncomingJingleSession::ref);
+			void handleIncomingSession(const JID& from, JingleSessionImpl::ref, const std::vector<JingleContentPayload::ref>& contents);
 
 		private:
 			IQRouter* router;
@@ -43,7 +43,7 @@ namespace Swift {
 				JID jid;
 				std::string session;
 			};
-			typedef std::map<JIDSession, JingleSession::ref> SessionMap;
+			typedef std::map<JIDSession, JingleSessionImpl::ref> SessionMap;
 			SessionMap incomingSessions;
 	};
 }
diff --git a/Swiften/Jingle/SConscript b/Swiften/Jingle/SConscript
index a8890b7..6b3cfd3 100644
--- a/Swiften/Jingle/SConscript
+++ b/Swiften/Jingle/SConscript
@@ -1,11 +1,11 @@
 Import("swiften_env")
 
 sources = [
-		"IncomingJingleSession.cpp",
+		"JingleSession.cpp",
+		"JingleSessionImpl.cpp",	
 		"IncomingJingleSessionHandler.cpp",
 		"JingleSessionManager.cpp",	
 		"JingleResponder.cpp",
-		"JingleSession.cpp",
 	]
 
 swiften_env.Append(SWIFTEN_OBJECTS = swiften_env.SwiftenObject(sources))
diff --git a/Swiften/Parser/PayloadParsers/IBBParser.cpp b/Swiften/Parser/PayloadParsers/IBBParser.cpp
index 308f4ab..8196295 100644
--- a/Swiften/Parser/PayloadParsers/IBBParser.cpp
+++ b/Swiften/Parser/PayloadParsers/IBBParser.cpp
@@ -64,7 +64,7 @@ void IBBParser::handleEndElement(const std::string& element, const std::string&)
 					data.push_back(c);
 				}
 			}
-			getPayloadInternal()->setData(Base64::decode(std::string(&data[0], data.size())));
+			getPayloadInternal()->setData(Base64::decode(std::string(&data[0], data.size())).getDataVector());
 		}
 	}
 }
diff --git a/Swiften/Parser/PayloadParsers/UnitTest/IBBParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/IBBParserTest.cpp
index b4229f2..2fc3e79 100644
--- a/Swiften/Parser/PayloadParsers/UnitTest/IBBParserTest.cpp
+++ b/Swiften/Parser/PayloadParsers/UnitTest/IBBParserTest.cpp
@@ -32,7 +32,7 @@ class IBBParserTest : public CppUnit::TestFixture {
 
 			IBB::ref ibb = parser.getPayload<IBB>();
 			CPPUNIT_ASSERT(ibb->getAction() == IBB::Data);
-			CPPUNIT_ASSERT_EQUAL(ByteArray("abcdefgihjklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890\x0a"), ibb->getData());
+			CPPUNIT_ASSERT(ByteArray::create("abcdefgihjklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890\x0a") == ibb->getData());
 			CPPUNIT_ASSERT_EQUAL(4, ibb->getSequenceNumber());
 		}
 };
diff --git a/Swiften/QA/StorageTest/FileReadBytestreamTest.cpp b/Swiften/QA/StorageTest/FileReadBytestreamTest.cpp
index 925c775..73df0a0 100644
--- a/Swiften/QA/StorageTest/FileReadBytestreamTest.cpp
+++ b/Swiften/QA/StorageTest/FileReadBytestreamTest.cpp
@@ -7,6 +7,7 @@
 #include <cppunit/extensions/HelperMacros.h>
 #include <cppunit/extensions/TestFactoryRegistry.h>
 
+#include <Swiften/Base/ByteArray.h>
 #include "Swiften/FileTransfer/FileReadBytestream.h"
 #include "SwifTools/Application/PlatformApplicationPathProvider.h"
 
@@ -32,16 +33,16 @@ class FileReadBytestreamTest : public CppUnit::TestFixture {
 		void testRead() {
 			std::auto_ptr<FileReadBytestream> testling(createTestling());
 
-			ByteArray result = testling->read(10);
+			std::vector<unsigned char> result = testling->read(10);
 
-			CPPUNIT_ASSERT_EQUAL(std::string("/*\n * Copy"), result.toString());
+			CPPUNIT_ASSERT(ByteArray::create("/*\n * Copy") == result);
 		}
 
 		void testRead_Twice() {
 			std::auto_ptr<FileReadBytestream> testling(createTestling());
 
 			testling->read(10);
-			ByteArray result = testling->read(10);
+			ByteArray result(testling->read(10));
 
 			CPPUNIT_ASSERT_EQUAL(std::string("right (c) "), result.toString());
 		}
diff --git a/Swiften/SASL/SConscript b/Swiften/SASL/SConscript
index 5a0cdef..085e49d 100644
--- a/Swiften/SASL/SConscript
+++ b/Swiften/SASL/SConscript
@@ -12,6 +12,7 @@ objects = myenv.SwiftenObject([
 		"DIGESTMD5ClientAuthenticator.cpp",
 	])
 swiften_env.Append(SWIFTEN_OBJECTS = [objects])
+
 env.Append(UNITTEST_SOURCES = [
 			File("UnitTest/PLAINMessageTest.cpp"),
 			File("UnitTest/PLAINClientAuthenticatorTest.cpp"),
diff --git a/Swiften/SConscript b/Swiften/SConscript
index 8961d09..166e2ef 100644
--- a/Swiften/SConscript
+++ b/Swiften/SConscript
@@ -212,8 +212,6 @@ if env["SCONS_STAGE"] == "build" :
 			File("Elements/UnitTest/FormTest.cpp"),
 			File("EventLoop/UnitTest/EventLoopTest.cpp"),
 			File("EventLoop/UnitTest/SimpleEventLoopTest.cpp"),
-			File("FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp"),
-			File("FileTransfer/UnitTest/IBBSendSessionTest.cpp"),
 #			File("History/UnitTest/SQLiteHistoryManagerTest.cpp"),
 			File("JID/UnitTest/JIDTest.cpp"),
 			File("LinkLocal/UnitTest/LinkLocalConnectorTest.cpp"),
-- 
cgit v0.10.2-6-g49f6