From 1bb607f96e79845ce30dd5590b0d53cc394ac150 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Sun, 25 Aug 2013 18:39:06 +0200
Subject: PubSub implementation & Sluift refactoring.

Change-Id: I04ff7111b73565c00bff6db183451774a633344f

diff --git a/.gitignore b/.gitignore
index f3e0c2f..c89f9bf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -51,6 +51,8 @@ checker-report.xml
 /VERSION.*
 cppcheck.log
 /build
+/generator
+/tmp
 /.settings/
 /include/
 /nbproject/private/
diff --git a/.scons2ninja.conf b/.scons2ninja.conf
index 9a5e68c..9ea1c57 100644
--- a/.scons2ninja.conf
+++ b/.scons2ninja.conf
@@ -17,6 +17,6 @@ def ninja_post(ninja) :
 	
 	# Sluift
 	if sys.platform == 'win32' :
-		ninja.build(['Sluift', 'sluift'], 'phony', ['Sluift/sluift.exe', 'Sluift/sluift.dll'])
+		ninja.build(['Sluift', 'sluift'], 'phony', ['Sluift\\exe\\sluift.exe', 'Sluift\\dll\\sluift.dll'])
 	elif sys.platform in ['posix', 'darwin'] :
-		ninja.build(['Sluift', 'sluift'], 'phony', ['Sluift/sluift', 'Sluift/sluift.so'])
+		ninja.build(['Sluift', 'sluift'], 'phony', ['Sluift/exe/sluift', 'Sluift/dll/sluift.so'])
diff --git a/3rdParty/Boost/SConscript b/3rdParty/Boost/SConscript
index ba5aa47..adb6d4e 100644
--- a/3rdParty/Boost/SConscript
+++ b/3rdParty/Boost/SConscript
@@ -159,7 +159,7 @@ elif env.get("BOOST_BUNDLED", False) :
 		myenv.MergeFlags(myenv["BOOST_FLAGS"])
 		myenv.StaticLibrary("Swiften_Boost", sources)
 
-		if ARGUMENTS.get("BOOST_BUILD_BCP") or env.GetOption("clean") :
+		if ARGUMENTS.get("BOOST_BUILD_BCP") or env.get("BOOST_BUILD_BCP", False) or env.GetOption("clean") :
 			bcp_env = myenv.Clone()
 			bcp_env.MergeFlags(bcp_env["BOOST_FLAGS"])
 			bcp_env.Append(CPPPATH = ["src/tools/bcp"])
diff --git a/BuildTools/SCons/SConscript.boot b/BuildTools/SCons/SConscript.boot
index f1341d1..9c78bc0 100644
--- a/BuildTools/SCons/SConscript.boot
+++ b/BuildTools/SCons/SConscript.boot
@@ -247,9 +247,7 @@ if env["PLATFORM"] == "posix" and platform.machine() == "x86_64" :
 
 # Warnings
 if env["PLATFORM"] == "win32" :
-	# TODO: Find the ideal set of warnings
-	#env.Append(CCFLAGS = ["/Wall"])
-	pass
+	env.Append(CXXFLAGS = ["/wd4068"])
 else :
 	if "clang" in env["CXX"] :
 		env.Append(CXXFLAGS = [
diff --git a/BuildTools/SCons/SConstruct b/BuildTools/SCons/SConstruct
index 8f4d440..f3c4e5e 100644
--- a/BuildTools/SCons/SConstruct
+++ b/BuildTools/SCons/SConstruct
@@ -570,6 +570,7 @@ else :
 if ARGUMENTS.get("dump_trace", False) :
 	env.SetOption("no_exec", True)
 	env["TEST"] = True
+	env["BOOST_BUILD_BCP"] = True
 	env.Decider(lambda x, y, z : True)
 	SCons.Node.Python.Value.changed_since_last_build = (lambda x, y, z: True)
 
diff --git a/Sluift/.gitignore b/Sluift/.gitignore
index 35a18c0..e5fd1e5 100644
--- a/Sluift/.gitignore
+++ b/Sluift/.gitignore
@@ -2,3 +2,6 @@ lua.c
 sluift_dll.cpp
 sluift
 dll.c
+boot.c
+dll/
+exe/
diff --git a/Sluift/ElementConvertors/DOMElementConvertor.cpp b/Sluift/ElementConvertors/DOMElementConvertor.cpp
new file mode 100644
index 0000000..bb4256d
--- /dev/null
+++ b/Sluift/ElementConvertors/DOMElementConvertor.cpp
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/DOMElementConvertor.h>
+
+#include <iostream>
+#include <boost/smart_ptr/make_shared.hpp>
+#include <lua.hpp>
+
+#include <Swiften/Base/foreach.h>
+#include <Swiften/Elements/RawXMLPayload.h>
+#include <Swiften/Serializer/PayloadSerializer.h>
+#include <Sluift/Lua/Check.h>
+#include <Sluift/Lua/LuaUtils.h>
+#include <Swiften/Parser/XMLParserClient.h>
+#include <Swiften/Parser/XMLParser.h>
+#include <Swiften/Parser/AttributeMap.h>
+#include <Swiften/Parser/Attribute.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+#include <Swiften/Serializer/XML/XMLTextNode.h>
+#include <Swiften/Serializer/XML/XMLRawTextNode.h>
+#include <Sluift/Lua/Debug.h>
+
+using namespace Swift;
+
+namespace {
+	class ParserClient : public XMLParserClient {
+		public:
+			ParserClient(lua_State* L) : L(L), currentIndex(1) {
+			}
+
+			virtual void handleStartElement(
+					const std::string& element, const std::string& ns, 
+					const AttributeMap& attributes) SWIFTEN_OVERRIDE {
+				lua_pushnumber(L, currentIndex);
+				lua_newtable(L);
+				lua_pushstring(L, element.c_str());
+				lua_setfield(L, -2, "tag");
+				if (!ns.empty()) {
+					lua_pushstring(L, ns.c_str());
+					lua_setfield(L, -2, "ns");
+				}
+				if (!attributes.getEntries().empty()) {
+					lua_newtable(L);
+					int i = 1;
+					foreach(const AttributeMap::Entry& entry, attributes.getEntries()) {
+						lua_pushnumber(L, i);
+						lua_newtable(L);
+						lua_pushstring(L, entry.getAttribute().getName().c_str());
+						lua_setfield(L, -2, "name");
+						if (!entry.getAttribute().getNamespace().empty()) {
+							lua_pushstring(L, entry.getAttribute().getNamespace().c_str());
+							lua_setfield(L, -2, "ns");
+						}
+						lua_pushstring(L, entry.getValue().c_str());
+						lua_setfield(L, -2, "value");
+						lua_settable(L, -3);
+						++i;
+					}
+					lua_setfield(L, -2, "attributes");
+				}
+
+				indexStack.push_back(currentIndex);
+				currentIndex = 1;
+				lua_newtable(L);
+			}
+
+			virtual void handleEndElement(
+					const std::string&, const std::string&) SWIFTEN_OVERRIDE {
+				lua_setfield(L, -2, "children");
+				lua_settable(L, -3);
+				currentIndex = indexStack.back();
+				indexStack.pop_back();
+				currentIndex++;
+			}
+
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE {
+				lua_pushnumber(L, currentIndex);
+				lua_pushstring(L, data.c_str());
+				lua_settable(L, -3);
+				currentIndex++;
+			}
+
+		private:
+			lua_State* L;
+			std::vector<int> indexStack;
+			int currentIndex;
+	};
+
+	std::string serializeElement(lua_State* L) {
+		std::string tag;
+		lua_getfield(L, -1, "tag");
+		if (lua_isstring(L, -1)) {
+			tag = lua_tostring(L, -1);
+		}
+		lua_pop(L, 1);
+
+		std::string ns;
+		lua_getfield(L, -1, "ns");
+		if (lua_isstring(L, -1)) {
+			ns = lua_tostring(L, -1);
+		}
+		lua_pop(L, 1);
+
+		XMLElement element(tag, ns);
+
+		lua_getfield(L, -1, "attributes");
+		if (lua_istable(L, -1)) {
+			int index = Lua::absoluteOffset(L, -1);
+			for (lua_pushnil(L); lua_next(L, index) != 0; ) {
+				if (lua_istable(L, -1)) {
+					std::string attributeName;
+					lua_getfield(L, -1, "name");
+					if (lua_isstring(L, -1)) {
+						attributeName = lua_tostring(L, -1);
+					}
+					lua_pop(L, 1);
+
+					std::string attributeValue;
+					lua_getfield(L, -1, "value");
+					if (lua_isstring(L, -1)) {
+						attributeValue = lua_tostring(L, -1);
+					}
+					lua_pop(L, 1);
+
+					if (!attributeName.empty()) {
+						element.setAttribute(attributeName, attributeValue);
+					}
+				}
+				lua_pop(L, 1); // value
+			}
+		}
+		lua_pop(L, 1); // children
+
+		lua_getfield(L, -1, "children");
+		if (lua_istable(L, -1)) {
+			int index = Lua::absoluteOffset(L, -1);
+			for (lua_pushnil(L); lua_next(L, index) != 0; ) {
+				if (lua_isstring(L, -1)) {
+					element.addNode(boost::make_shared<XMLTextNode>(lua_tostring(L, -1)));
+				}
+				else if (lua_istable(L, -1)) {
+					element.addNode(boost::make_shared<XMLRawTextNode>(serializeElement(L)));
+				}
+				lua_pop(L, 1); // value
+			}
+		}
+		lua_pop(L, 1); // children
+
+		return element.serialize();
+	}
+}
+
+DOMElementConvertor::DOMElementConvertor() {
+}
+
+DOMElementConvertor::~DOMElementConvertor() {
+}
+
+boost::shared_ptr<Payload> DOMElementConvertor::convertFromLua(lua_State* L, int index, const std::string& type) {
+	if (!lua_istable(L, index) || type != "dom") {
+		return boost::shared_ptr<Payload>();
+	}
+	return boost::make_shared<RawXMLPayload>(serializeElement(L).c_str());
+}
+
+boost::optional<std::string> DOMElementConvertor::convertToLua(
+		lua_State* L, boost::shared_ptr<Payload> payload) {
+	// Serialize payload to XML
+	PayloadSerializer* serializer = serializers.getPayloadSerializer(payload);
+	assert(serializer);
+	std::string serializedPayload = serializer->serialize(payload);
+
+	lua_newtable(L);
+
+	// Parse the payload again
+	ParserClient parserClient(L);
+	boost::shared_ptr<XMLParser> parser(parsers.createXMLParser(&parserClient));
+	bool result = parser->parse(serializedPayload);
+	assert(result);
+
+	// There can only be one element, so stripping the list
+	lua_pushnil(L);
+	lua_next(L, -2);
+	Lua::registerTableToString(L, -1);
+
+	lua_replace(L, -3);
+	lua_settop(L, -2);
+
+	return std::string("dom");
+}
diff --git a/Sluift/ElementConvertors/DOMElementConvertor.h b/Sluift/ElementConvertors/DOMElementConvertor.h
new file mode 100644
index 0000000..94d0669
--- /dev/null
+++ b/Sluift/ElementConvertors/DOMElementConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/LuaElementConvertor.h>
+#include <Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h>
+#include <Swiften/Parser/PlatformXMLParserFactory.h>
+
+namespace Swift {
+	class DOMElementConvertor : public LuaElementConvertor {
+		public:
+			DOMElementConvertor();
+			virtual ~DOMElementConvertor();
+
+			virtual boost::shared_ptr<Payload> convertFromLua(lua_State*, int index, const std::string& type) SWIFTEN_OVERRIDE;
+			virtual boost::optional<std::string> convertToLua(lua_State*, boost::shared_ptr<Payload>) SWIFTEN_OVERRIDE;
+
+		private:
+			PlatformXMLParserFactory parsers;
+			FullPayloadSerializerCollection serializers;
+	};
+}
diff --git a/Sluift/ElementConvertors/DefaultElementConvertor.cpp b/Sluift/ElementConvertors/DefaultElementConvertor.cpp
new file mode 100644
index 0000000..62c799b
--- /dev/null
+++ b/Sluift/ElementConvertors/DefaultElementConvertor.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/DefaultElementConvertor.h>
+
+#include <iostream>
+#include <typeinfo>
+#include <string>
+
+using namespace Swift;
+
+DefaultElementConvertor::DefaultElementConvertor() {
+}
+
+DefaultElementConvertor::~DefaultElementConvertor() {
+}
+
+boost::shared_ptr<Payload> DefaultElementConvertor::convertFromLua(lua_State*, int, const std::string& type) {
+	std::cerr << "Warning: Unable to convert type '" << type << "'" << std::endl;
+	return boost::shared_ptr<Payload>();
+}
+
+boost::optional<std::string> DefaultElementConvertor::convertToLua(lua_State*, boost::shared_ptr<Payload>) {
+	// Should have been handled by the raw XML convertor
+	assert(false);
+	return NO_RESULT;
+}
diff --git a/Sluift/ElementConvertors/DefaultElementConvertor.h b/Sluift/ElementConvertors/DefaultElementConvertor.h
new file mode 100644
index 0000000..ad8fe75
--- /dev/null
+++ b/Sluift/ElementConvertors/DefaultElementConvertor.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/LuaElementConvertor.h>
+
+namespace Swift {
+	class DefaultElementConvertor : public LuaElementConvertor {
+		public:
+			DefaultElementConvertor();
+			virtual ~DefaultElementConvertor();
+
+			virtual boost::shared_ptr<Payload> convertFromLua(lua_State*, int index, const std::string& type) SWIFTEN_OVERRIDE;
+			virtual boost::optional<std::string> convertToLua(lua_State*, boost::shared_ptr<Payload>) SWIFTEN_OVERRIDE;
+	};
+}
diff --git a/Sluift/ElementConvertors/DiscoInfoConvertor.cpp b/Sluift/ElementConvertors/DiscoInfoConvertor.cpp
new file mode 100644
index 0000000..ac0cf2e
--- /dev/null
+++ b/Sluift/ElementConvertors/DiscoInfoConvertor.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/DiscoInfoConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+#include <Sluift/Lua/LuaUtils.h>
+
+using namespace Swift;
+
+DiscoInfoConvertor::DiscoInfoConvertor() : GenericLuaElementConvertor<DiscoInfo>("disco_info") {
+}
+
+DiscoInfoConvertor::~DiscoInfoConvertor() {
+}
+
+boost::shared_ptr<DiscoInfo> DiscoInfoConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<DiscoInfo> result = boost::make_shared<DiscoInfo>();
+	if (boost::optional<std::string> value = Lua::getStringField(L, -1, "node")) {
+		result->setNode(*value);
+	}
+
+	lua_getfield(L, -1, "identities");
+	if (lua_istable(L, -1)) {
+		for (lua_pushnil(L); lua_next(L, -2); ) {
+			result->addIdentity(DiscoInfo::Identity(
+					Lua::getStringField(L, -1, "name").get_value_or(""),
+					Lua::getStringField(L, -1, "category").get_value_or("client"),
+					Lua::getStringField(L, -1, "type").get_value_or("pc"),
+					Lua::getStringField(L, -1, "language").get_value_or("")));
+			lua_pop(L, 1);
+		}
+	}
+	lua_pop(L, 1);
+
+	lua_getfield(L, -1, "features");
+	if (lua_istable(L, -1)) {
+		for (lua_pushnil(L); lua_next(L, -2); ) {
+			if (lua_isstring(L, -1)) {
+				result->addFeature(lua_tostring(L, -1));
+			}
+			lua_pop(L, 1);
+		}
+	}
+	lua_pop(L, 1);
+
+	// TODO: Extension
+
+	return result;
+}
+
+void DiscoInfoConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<DiscoInfo> payload) {
+	lua_newtable(L);
+	if (!payload->getNode().empty()) {
+		lua_pushstring(L, payload->getNode().c_str());
+		lua_setfield(L, -2, "node");
+	}
+
+	const std::vector<DiscoInfo::Identity>& identities = payload->getIdentities();
+	if (!identities.empty()) {
+		lua_createtable(L, boost::numeric_cast<int>(identities.size()), 0);
+		for (size_t i = 0; i < identities.size(); ++i) {
+			lua_createtable(L, 0, 0);
+			if (!identities[i].getName().empty()) {
+				lua_pushstring(L, identities[i].getName().c_str());
+				lua_setfield(L, -2, "name");
+			}
+			if (!identities[i].getCategory().empty()) {
+				lua_pushstring(L, identities[i].getCategory().c_str());
+				lua_setfield(L, -2, "category");
+			}
+			if (!identities[i].getType().empty()) {
+				lua_pushstring(L, identities[i].getType().c_str());
+				lua_setfield(L, -2, "type");
+			}
+			if (!identities[i].getLanguage().empty()) {
+				lua_pushstring(L, identities[i].getLanguage().c_str());
+				lua_setfield(L, -2, "language");
+			}
+			lua_rawseti(L, -2, boost::numeric_cast<int>(i+1));
+		}
+		lua_setfield(L, -2, "identities");
+	}
+
+	const std::vector<std::string>& features = payload->getFeatures();
+	if (!features.empty()) {
+		lua_createtable(L, boost::numeric_cast<int>(features.size()), 0);
+		for (size_t i = 0; i < features.size(); ++i) {
+			lua_pushstring(L, features[i].c_str());
+			lua_rawseti(L, -2, boost::numeric_cast<int>(i+1));
+		}
+		lua_setfield(L, -2, "features");
+	}
+	
+	// TODO: Extension
+}
diff --git a/Sluift/ElementConvertors/DiscoInfoConvertor.h b/Sluift/ElementConvertors/DiscoInfoConvertor.h
new file mode 100644
index 0000000..7a2270e
--- /dev/null
+++ b/Sluift/ElementConvertors/DiscoInfoConvertor.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/DiscoInfo.h>
+
+namespace Swift {
+	class DiscoInfoConvertor : public GenericLuaElementConvertor<DiscoInfo> {
+		public:
+			DiscoInfoConvertor();
+			virtual ~DiscoInfoConvertor();
+
+			virtual boost::shared_ptr<DiscoInfo> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<DiscoInfo>) SWIFTEN_OVERRIDE;
+	};
+}
diff --git a/Sluift/ElementConvertors/DiscoItemsConvertor.cpp b/Sluift/ElementConvertors/DiscoItemsConvertor.cpp
new file mode 100644
index 0000000..6c39aea
--- /dev/null
+++ b/Sluift/ElementConvertors/DiscoItemsConvertor.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/DiscoItemsConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+#include <Sluift/Lua/LuaUtils.h>
+
+using namespace Swift;
+
+DiscoItemsConvertor::DiscoItemsConvertor() : GenericLuaElementConvertor<DiscoItems>("disco_items") {
+}
+
+DiscoItemsConvertor::~DiscoItemsConvertor() {
+}
+
+boost::shared_ptr<DiscoItems> DiscoItemsConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<DiscoItems> result = boost::make_shared<DiscoItems>();
+	if (boost::optional<std::string> value = Lua::getStringField(L, -1, "node")) {
+		result->setNode(*value);
+	}
+	lua_getfield(L, -1, "items");
+	if (lua_istable(L, -1)) {
+		for (lua_pushnil(L); lua_next(L, -2); ) {
+			result->addItem(DiscoItems::Item(
+					Lua::getStringField(L, -1, "name").get_value_or(""),
+					JID(Lua::getStringField(L, -1, "jid").get_value_or("")),
+					Lua::getStringField(L, -1, "node").get_value_or("")));
+			lua_pop(L, 1);
+		}
+	}
+	lua_pop(L, 1);
+	return result;
+}
+
+void DiscoItemsConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<DiscoItems> payload) {
+	lua_newtable(L);
+	if (!payload->getNode().empty()) {
+		lua_pushstring(L, payload->getNode().c_str());
+		lua_setfield(L, -2, "node");
+	}
+	const std::vector<DiscoItems::Item>& items = payload->getItems();
+	if (!items.empty()) {
+		lua_createtable(L, boost::numeric_cast<int>(items.size()), 0);
+		for (size_t i = 0; i < items.size(); ++i) {
+			lua_createtable(L, 0, 0);
+			lua_pushstring(L, items[i].getName().c_str());
+			lua_setfield(L, -2, "name");
+			lua_pushstring(L, items[i].getNode().c_str());
+			lua_setfield(L, -2, "node");
+			lua_pushstring(L, items[i].getJID().toString().c_str());
+			lua_setfield(L, -2, "jid");
+			lua_rawseti(L, -2, boost::numeric_cast<int>(i+1));
+		}
+		lua_setfield(L, -2, "items");
+	}
+}
diff --git a/Sluift/ElementConvertors/DiscoItemsConvertor.h b/Sluift/ElementConvertors/DiscoItemsConvertor.h
new file mode 100644
index 0000000..8972a84
--- /dev/null
+++ b/Sluift/ElementConvertors/DiscoItemsConvertor.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/DiscoItems.h>
+
+namespace Swift {
+	class DiscoItemsConvertor : public GenericLuaElementConvertor<DiscoItems> {
+		public:
+			DiscoItemsConvertor();
+			virtual ~DiscoItemsConvertor();
+
+			virtual boost::shared_ptr<DiscoItems> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<DiscoItems>) SWIFTEN_OVERRIDE;
+	};
+}
diff --git a/Sluift/ElementConvertors/ElementConvertors.ipp b/Sluift/ElementConvertors/ElementConvertors.ipp
new file mode 100644
index 0000000..b7b9166
--- /dev/null
+++ b/Sluift/ElementConvertors/ElementConvertors.ipp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubRetractConvertor.h>
+#include <Sluift/ElementConvertors/PubSubAffiliationsConvertor.h>
+#include <Sluift/ElementConvertors/PubSubPublishConvertor.h>
+#include <Sluift/ElementConvertors/PubSubItemsConvertor.h>
+#include <Sluift/ElementConvertors/PubSubOwnerRedirectConvertor.h>
+#include <Sluift/ElementConvertors/PubSubEventRedirectConvertor.h>
+#include <Sluift/ElementConvertors/PubSubConfigureConvertor.h>
+#include <Sluift/ElementConvertors/PubSubEventDisassociateConvertor.h>
+#include <Sluift/ElementConvertors/PubSubOwnerAffiliationsConvertor.h>
+#include <Sluift/ElementConvertors/PubSubOwnerConfigureConvertor.h>
+#include <Sluift/ElementConvertors/UserLocationConvertor.h>
+#include <Sluift/ElementConvertors/PubSubSubscribeOptionsConvertor.h>
+#include <Sluift/ElementConvertors/PubSubOwnerSubscriptionsConvertor.h>
+#include <Sluift/ElementConvertors/PubSubDefaultConvertor.h>
+#include <Sluift/ElementConvertors/PubSubEventCollectionConvertor.h>
+#include <Sluift/ElementConvertors/PubSubEventSubscriptionConvertor.h>
+#include <Sluift/ElementConvertors/PubSubEventRetractConvertor.h>
+#include <Sluift/ElementConvertors/PubSubItemConvertor.h>
+#include <Sluift/ElementConvertors/PubSubUnsubscribeConvertor.h>
+#include <Sluift/ElementConvertors/PubSubEventDeleteConvertor.h>
+#include <Sluift/ElementConvertors/PubSubCreateConvertor.h>
+#include <Sluift/ElementConvertors/PubSubOwnerPurgeConvertor.h>
+#include <Sluift/ElementConvertors/PubSubEventItemsConvertor.h>
+#include <Sluift/ElementConvertors/PubSubOptionsConvertor.h>
+#include <Sluift/ElementConvertors/PubSubEventItemConvertor.h>
+#include <Sluift/ElementConvertors/PubSubOwnerSubscriptionConvertor.h>
+#include <Sluift/ElementConvertors/PubSubOwnerAffiliationConvertor.h>
+#include <Sluift/ElementConvertors/PubSubEventPurgeConvertor.h>
+#include <Sluift/ElementConvertors/PubSubAffiliationConvertor.h>
+#include <Sluift/ElementConvertors/PubSubSubscribeConvertor.h>
+#include <Sluift/ElementConvertors/PubSubOwnerDeleteConvertor.h>
+#include <Sluift/ElementConvertors/PubSubOwnerDefaultConvertor.h>
+#include <Sluift/ElementConvertors/PubSubSubscriptionsConvertor.h>
+#include <Sluift/ElementConvertors/PubSubEventAssociateConvertor.h>
+#include <Sluift/ElementConvertors/PubSubSubscriptionConvertor.h>
+#include <Sluift/ElementConvertors/PubSubEventConfigurationConvertor.h>
+
+void LuaElementConvertors::registerConvertors() {
+	convertors.push_back(boost::make_shared<PubSubRetractConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubAffiliationsConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubPublishConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubItemsConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubOwnerRedirectConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubEventRedirectConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubConfigureConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubEventDisassociateConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubOwnerAffiliationsConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubOwnerConfigureConvertor>(this));
+	convertors.push_back(boost::make_shared<UserLocationConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubSubscribeOptionsConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubOwnerSubscriptionsConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubDefaultConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubEventCollectionConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubEventSubscriptionConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubEventRetractConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubItemConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubUnsubscribeConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubEventDeleteConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubCreateConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubOwnerPurgeConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubEventItemsConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubOptionsConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubEventItemConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubOwnerSubscriptionConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubOwnerAffiliationConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubEventPurgeConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubAffiliationConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubSubscribeConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubOwnerDeleteConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubOwnerDefaultConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubSubscriptionsConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubEventAssociateConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubSubscriptionConvertor>(this));
+	convertors.push_back(boost::make_shared<PubSubEventConfigurationConvertor>(this));
+}
diff --git a/Sluift/ElementConvertors/FormConvertor.cpp b/Sluift/ElementConvertors/FormConvertor.cpp
new file mode 100644
index 0000000..1720037
--- /dev/null
+++ b/Sluift/ElementConvertors/FormConvertor.cpp
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/FormConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+#include <Sluift/Lua/Check.h>
+#include <Sluift/Lua/Value.h>
+#include <Swiften/Base/foreach.h>
+#include <boost/assign/list_of.hpp>
+#include <sstream>
+
+using namespace Swift;
+
+namespace {
+	// TODO: add __newindex to set a field value
+	int formIndex(lua_State* L) {
+		lua_getfield(L, 1, "fields");
+		if (lua_type(L, -1) != LUA_TTABLE) {
+			return 0;
+		}
+		int index = Lua::absoluteOffset(L, -1);
+		lua_pushnil(L);
+		for (lua_pushnil(L); lua_next(L, index) != 0; ) {
+			lua_getfield(L, -1, "name");
+			if (lua_equal(L, -1, 2)) {
+				lua_pop(L, 1);
+				return 1;
+			}
+			lua_pop(L, 2);
+		}
+		return 0;
+	}
+
+	Lua::Table convertFieldToLua(boost::shared_ptr<FormField> field) {
+		Lua::Table luaField = boost::assign::map_list_of("name", Lua::valueRef(field->getName()));
+		std::string type;
+		switch (field->getType()) {
+			case FormField::UnknownType: type = ""; break;
+			case FormField::BooleanType: type = "boolean"; break;
+			case FormField::FixedType: type = "fixed"; break;
+			case FormField::HiddenType: type = "hidden"; break;
+			case FormField::ListSingleType: type = "list-single"; break;
+			case FormField::TextMultiType: type = "text-multi"; break;
+			case FormField::TextPrivateType: type = "text-private"; break;
+			case FormField::TextSingleType: type = "text-single"; break;
+			case FormField::JIDSingleType: type = "jid-single"; break;
+			case FormField::JIDMultiType: type = "jid-multi"; break;
+			case FormField::ListMultiType: type = "list-multi"; break;
+		}
+		if (!type.empty()) {
+			luaField["type"] = Lua::valueRef(type);
+		}
+		if (!field->getLabel().empty()) {
+			luaField["label"] = Lua::valueRef(field->getLabel());
+		}
+		if (field->getRequired()) {
+			luaField["required"] = Lua::boolRef(field->getRequired());
+		}
+		if (!field->getDescription().empty()) {
+			luaField["description"] = Lua::valueRef(field->getDescription());
+		}
+
+		if (field->getType() == FormField::ListMultiType || field->getType() == FormField::JIDMultiType || field->getType() == FormField::TextMultiType) {
+			luaField["values"] = Lua::valueRef(Lua::Array(field->getValues().begin(), field->getValues().end()));
+		}
+		else if (field->getType() == FormField::BooleanType) {
+			luaField["value"] = Lua::boolRef(field->getBoolValue());
+		}
+		else if (!field->getValues().empty()) {
+			luaField["value"] = Lua::valueRef(field->getValues()[0]);
+		}
+
+		if (!field->getOptions().empty()) {
+			Lua::Array options;
+			foreach(const FormField::Option& option, field->getOptions()) {
+				Lua::Table luaOption = boost::assign::map_list_of
+					("label", Lua::valueRef(option.label))
+					("value", Lua::valueRef(option.value));
+				options.push_back(luaOption);
+			}
+			luaField["options"] = valueRef(options);
+		}
+		return luaField;
+	}
+
+	Lua::Array convertFieldListToLua(const std::vector< boost::shared_ptr<FormField> >& fieldList) {
+		Lua::Array fields;
+		foreach(boost::shared_ptr<FormField> field, fieldList) {
+			fields.push_back(convertFieldToLua(field));
+		}
+		return fields;
+	}
+
+
+	boost::shared_ptr<FormField> convertFieldFromLua(lua_State* L) {
+		boost::shared_ptr<FormField> result = boost::make_shared<FormField>();
+		FormField::Type fieldType = FormField::UnknownType;
+		boost::optional<std::string> type = Lua::getStringField(L, -1, "type");
+		if (type) {
+			if (*type == "boolean") {
+				fieldType = FormField::BooleanType; 
+			}
+			if (*type == "fixed") {
+				fieldType = FormField::FixedType; 
+			}
+			if (*type == "hidden") {
+				fieldType = FormField::HiddenType; 
+			}
+			if (*type == "list-single") {
+				fieldType = FormField::ListSingleType; 
+			}
+			if (*type == "text-multi") {
+				fieldType = FormField::TextMultiType; 
+			}
+			if (*type == "text-private") {
+				fieldType = FormField::TextPrivateType; 
+			}
+			if (*type == "text-single") {
+				fieldType = FormField::TextSingleType; 
+			}
+			if (*type == "jid-single") {
+				fieldType = FormField::JIDSingleType; 
+			}
+			if (*type == "jid-multi") {
+				fieldType = FormField::JIDMultiType; 
+			}
+			if (*type == "list-multi") {
+				fieldType = FormField::ListMultiType; 
+			}
+		}
+		result->setType(fieldType);
+		if (boost::optional<std::string> name = Lua::getStringField(L, -1, "name")) {
+			result->setName(*name);
+		}
+		if (boost::optional<std::string> description = Lua::getStringField(L, -1, "description")) {
+			result->setDescription(*description);
+		}
+		if (boost::optional<std::string> label = Lua::getStringField(L, -1, "label")) {
+			result->setLabel(*label);
+		}
+		if (boost::optional<bool> required = Lua::getBooleanField(L, -1, "required")) {
+			result->setRequired(*required);
+		}
+		if (boost::optional<std::string> value = Lua::getStringField(L, -1, "value")) {
+			result->addValue(*value);
+		}
+		else if (boost::optional<bool> value = Lua::getBooleanField(L, -1, "value")) {
+			result->setBoolValue(*value);
+		}
+		else {
+			lua_getfield(L, -1, "values");
+			if (lua_istable(L, -1)) {
+				for (lua_pushnil(L); lua_next(L, -2); ) {
+					if (lua_isstring(L, -1)) {
+						result->addValue(lua_tostring(L, -1));
+					}
+					lua_pop(L, 1);
+				}
+			}
+			lua_pop(L, 1);
+		}
+		lua_getfield(L, -1, "options");
+		if (lua_istable(L, -1)) {
+			for (lua_pushnil(L); lua_next(L, -2); ) {
+				if (lua_istable(L, -1)) {
+					FormField::Option option("", "");
+					if (boost::optional<std::string> value = Lua::getStringField(L, -1, "value")) {
+						option.value = *value;
+					}
+					if (boost::optional<std::string> label = Lua::getStringField(L, -1, "label")) {
+						option.label = *label;
+					}
+					result->addOption(option);
+				}
+				lua_pop(L, 1);
+			}
+		}
+		lua_pop(L, 1);
+		return result;
+	}
+
+	std::vector< boost::shared_ptr<FormField> > convertFieldListFromLua(lua_State* L) {
+		std::vector< boost::shared_ptr<FormField> > result;
+		for (lua_pushnil(L); lua_next(L, -2);) {
+			result.push_back(convertFieldFromLua(L));
+			lua_pop(L, 1);
+		}
+		return result;
+	}
+
+	boost::shared_ptr<Form> convertFormFromLua(lua_State* L) {
+		boost::shared_ptr<Form> result = boost::make_shared<Form>();
+		if (boost::optional<std::string> title = Lua::getStringField(L, -1, "title")) {
+			result->setTitle(*title);
+		}
+		if (boost::optional<std::string> instructions = Lua::getStringField(L, -1, "instructions")) {
+			result->setInstructions(*instructions);
+		}
+		if (boost::optional<std::string> type = Lua::getStringField(L, -1, "type")) {
+			Form::Type formType = Form::FormType;
+			if (*type == "submit") {
+				formType = Form::SubmitType;
+			}
+			else if (*type == "cancel") {
+				formType = Form::CancelType;
+			}
+			else if (*type == "result") {
+				formType = Form::ResultType;
+			}
+			result->setType(formType);
+		}
+
+		lua_getfield(L, -1, "fields");
+		if (lua_istable(L, -1)) {
+			foreach (boost::shared_ptr<FormField> formField, convertFieldListFromLua(L)) {
+				result->addField(formField);
+			}
+		}
+		lua_pop(L, 1);
+
+		lua_getfield(L, -1, "reported_fields");
+		if (lua_istable(L, -1)) {
+			foreach (boost::shared_ptr<FormField> formField, convertFieldListFromLua(L)) {
+				result->addReportedField(formField);
+			}
+		}
+		lua_pop(L, 1);
+
+		lua_getfield(L, -1, "items");
+		if (lua_istable(L, -1)) {
+			for (lua_pushnil(L); lua_next(L, -2);) {
+				result->addItem(convertFieldListFromLua(L));
+				lua_pop(L, 1);
+			}
+		}
+		lua_pop(L, 1);
+
+		return result;
+	}
+
+	void convertFormToLua(lua_State* L, boost::shared_ptr<Form> payload) {
+		std::string type;
+		switch (payload->getType()) {
+			case Form::FormType: type = "form"; break;
+			case Form::SubmitType: type = "submit"; break;
+			case Form::CancelType: type = "cancel"; break;
+			case Form::ResultType: type = "result"; break;
+		}
+
+		Lua::Table result = boost::assign::map_list_of("type", Lua::valueRef(type));
+		if (!payload->getTitle().empty()) {
+			result["title"] = Lua::valueRef(payload->getTitle());
+		}
+		if (!payload->getInstructions().empty()) {
+			result["instructions"] = Lua::valueRef(payload->getInstructions());
+		}
+		if (!payload->getFields().empty()) {
+			result["fields"] = valueRef(convertFieldListToLua(payload->getFields()));
+		}
+		if (!payload->getReportedFields().empty()) {
+			result["reported_fields"] = valueRef(convertFieldListToLua(payload->getReportedFields()));
+		}
+
+		if (!payload->getItems().empty()) {
+			Lua::Array luaItems;
+			foreach(const Form::FormItem& item, payload->getItems()) {
+				if (!item.empty()) {
+					luaItems.push_back(convertFieldListToLua(item));
+				}
+			}
+			result["items"] = valueRef(luaItems);
+		}
+
+		Lua::pushValue(L, result);
+		lua_newtable(L);
+		lua_pushcfunction(L, formIndex);
+		lua_setfield(L, -2, "__index");
+		lua_setmetatable(L, -2);
+	}
+
+	int createSubmission(lua_State* L) {
+		boost::shared_ptr<Form> form = convertFormFromLua(L);
+
+		// Remove all redundant elements
+		form->setInstructions("");
+		form->setTitle("");
+		form->clearItems();
+		form->clearReportedFields();
+		std::vector< boost::shared_ptr<FormField> > fields(form->getFields());
+		form->clearFields();
+		foreach (boost::shared_ptr<FormField> field, fields) {
+			if (field->getType() == FormField::FixedType) {
+				continue;
+			}
+			field->clearOptions();
+			field->setLabel("");
+			field->setType(FormField::UnknownType);
+			field->setDescription("");
+			form->addField(field);
+		}
+
+		// Convert back
+		convertFormToLua(L, form);
+		Lua::registerTableToString(L, -1);
+		return 1;
+	}
+}
+
+FormConvertor::FormConvertor() : GenericLuaElementConvertor<Form>("form") {
+}
+
+FormConvertor::~FormConvertor() {
+}
+
+boost::shared_ptr<Form> FormConvertor::doConvertFromLua(lua_State* L) {
+	return convertFormFromLua(L);
+}
+
+void FormConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<Form> payload) {
+	convertFormToLua(L, payload);
+
+	lua_pushcfunction(L, createSubmission);
+	lua_setfield(L, -2, "create_submission");
+
+}
diff --git a/Sluift/ElementConvertors/FormConvertor.h b/Sluift/ElementConvertors/FormConvertor.h
new file mode 100644
index 0000000..eaccf74
--- /dev/null
+++ b/Sluift/ElementConvertors/FormConvertor.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/Form.h>
+
+namespace Swift {
+	class FormConvertor : public GenericLuaElementConvertor<Form> {
+		public:
+			FormConvertor();
+			virtual ~FormConvertor();
+
+			virtual boost::shared_ptr<Form> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<Form>) SWIFTEN_OVERRIDE;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubAffiliationConvertor.cpp b/Sluift/ElementConvertors/PubSubAffiliationConvertor.cpp
new file mode 100644
index 0000000..3d40be9
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubAffiliationConvertor.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubAffiliationConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+
+
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubAffiliationConvertor::PubSubAffiliationConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubAffiliation>("pubsub_affiliation"),
+		convertors(convertors) {
+}
+
+PubSubAffiliationConvertor::~PubSubAffiliationConvertor() {
+}
+
+boost::shared_ptr<PubSubAffiliation> PubSubAffiliationConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubAffiliation> result = boost::make_shared<PubSubAffiliation>();
+	lua_getfield(L, -1, "node");
+	if (lua_isstring(L, -1)) {
+		result->setNode(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "type");
+	lua_pop(L, 1);
+	return result;
+}
+
+void PubSubAffiliationConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubAffiliation> payload) {
+	lua_createtable(L, 0, 0);
+	lua_pushstring(L, payload->getNode().c_str());
+	lua_setfield(L, -2, "node");
+	switch (payload->getType()) {
+		case PubSubAffiliation::None:
+			lua_pushstring(L, "none");
+			break;
+		case PubSubAffiliation::Member:
+			lua_pushstring(L, "member");
+			break;
+		case PubSubAffiliation::Outcast:
+			lua_pushstring(L, "outcast");
+			break;
+		case PubSubAffiliation::Owner:
+			lua_pushstring(L, "owner");
+			break;
+		case PubSubAffiliation::Publisher:
+			lua_pushstring(L, "publisher");
+			break;
+		case PubSubAffiliation::PublishOnly:
+			lua_pushstring(L, "publish_only");
+			break;
+	}
+	lua_setfield(L, -2, "type");
+}
diff --git a/Sluift/ElementConvertors/PubSubAffiliationConvertor.h b/Sluift/ElementConvertors/PubSubAffiliationConvertor.h
new file mode 100644
index 0000000..632a8d7
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubAffiliationConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubAffiliation.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubAffiliationConvertor : public GenericLuaElementConvertor<PubSubAffiliation> {
+		public:
+			PubSubAffiliationConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubAffiliationConvertor();
+
+			virtual boost::shared_ptr<PubSubAffiliation> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubAffiliation>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubAffiliationsConvertor.cpp b/Sluift/ElementConvertors/PubSubAffiliationsConvertor.cpp
new file mode 100644
index 0000000..9f34235
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubAffiliationsConvertor.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubAffiliationsConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+
+#include <Sluift/LuaElementConvertors.h>
+#include <Swiften/Base/foreach.h>
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubAffiliationsConvertor::PubSubAffiliationsConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubAffiliations>("pubsub_affiliations"),
+		convertors(convertors) {
+}
+
+PubSubAffiliationsConvertor::~PubSubAffiliationsConvertor() {
+}
+
+boost::shared_ptr<PubSubAffiliations> PubSubAffiliationsConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubAffiliations> result = boost::make_shared<PubSubAffiliations>();
+	lua_getfield(L, -1, "node");
+	if (lua_isstring(L, -1)) {
+		result->setNode(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	if (lua_type(L, -1) == LUA_TTABLE) {
+		std::vector< boost::shared_ptr<PubSubAffiliation> > items;
+		for(size_t i = 0; i < lua_objlen(L, -1); ++i) {
+			lua_pushnumber(L, i + 1);
+			lua_gettable(L, -2);
+			if (!lua_isnil(L, -1)) {
+				if (boost::shared_ptr<PubSubAffiliation> payload = boost::dynamic_pointer_cast<PubSubAffiliation>(convertors->convertFromLuaUntyped(L, -1, "pubsub_affiliation"))) {
+					items.push_back(payload);
+				}
+			}
+			lua_pop(L, 1);
+		}
+
+		result->setAffiliations(items);
+	}
+	return result;
+}
+
+void PubSubAffiliationsConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubAffiliations> payload) {
+	lua_createtable(L, 0, 0);
+	if (payload->getNode()) {
+		lua_pushstring(L, (*payload->getNode()).c_str());
+		lua_setfield(L, -2, "node");
+	}
+	if (!payload->getAffiliations().empty()) {
+		{
+			int i = 0;
+			foreach(boost::shared_ptr<PubSubAffiliation> item, payload->getAffiliations()) {
+				if (convertors->convertToLuaUntyped(L, item) > 0) {
+					lua_rawseti(L, -2, boost::numeric_cast<int>(i+1));
+					++i;
+				}
+			}
+		}
+	}
+}
diff --git a/Sluift/ElementConvertors/PubSubAffiliationsConvertor.h b/Sluift/ElementConvertors/PubSubAffiliationsConvertor.h
new file mode 100644
index 0000000..fb0279a
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubAffiliationsConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubAffiliations.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubAffiliationsConvertor : public GenericLuaElementConvertor<PubSubAffiliations> {
+		public:
+			PubSubAffiliationsConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubAffiliationsConvertor();
+
+			virtual boost::shared_ptr<PubSubAffiliations> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubAffiliations>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubConfigureConvertor.cpp b/Sluift/ElementConvertors/PubSubConfigureConvertor.cpp
new file mode 100644
index 0000000..893bc27
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubConfigureConvertor.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubConfigureConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+
+#include <Sluift/LuaElementConvertors.h>
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubConfigureConvertor::PubSubConfigureConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubConfigure>("pubsub_configure"),
+		convertors(convertors) {
+}
+
+PubSubConfigureConvertor::~PubSubConfigureConvertor() {
+}
+
+boost::shared_ptr<PubSubConfigure> PubSubConfigureConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubConfigure> result = boost::make_shared<PubSubConfigure>();
+	lua_getfield(L, -1, "data");
+	if (!lua_isnil(L, -1)) {
+		if (boost::shared_ptr<Form> payload = boost::dynamic_pointer_cast<Form>(convertors->convertFromLuaUntyped(L, -1, "form"))) {
+			result->setData(payload);
+		}
+	}
+	lua_pop(L, 1);
+	return result;
+}
+
+void PubSubConfigureConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubConfigure> payload) {
+	lua_createtable(L, 0, 0);
+	if (convertors->convertToLuaUntyped(L, payload->getData()) > 0) {
+		lua_setfield(L, -2, "data");
+	}
+}
diff --git a/Sluift/ElementConvertors/PubSubConfigureConvertor.h b/Sluift/ElementConvertors/PubSubConfigureConvertor.h
new file mode 100644
index 0000000..0dd9094
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubConfigureConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubConfigure.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubConfigureConvertor : public GenericLuaElementConvertor<PubSubConfigure> {
+		public:
+			PubSubConfigureConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubConfigureConvertor();
+
+			virtual boost::shared_ptr<PubSubConfigure> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubConfigure>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubCreateConvertor.cpp b/Sluift/ElementConvertors/PubSubCreateConvertor.cpp
new file mode 100644
index 0000000..64e2ee3
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubCreateConvertor.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubCreateConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+
+#include <Sluift/LuaElementConvertors.h>
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubCreateConvertor::PubSubCreateConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubCreate>("pubsub_create"),
+		convertors(convertors) {
+}
+
+PubSubCreateConvertor::~PubSubCreateConvertor() {
+}
+
+boost::shared_ptr<PubSubCreate> PubSubCreateConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubCreate> result = boost::make_shared<PubSubCreate>();
+	lua_getfield(L, -1, "node");
+	if (lua_isstring(L, -1)) {
+		result->setNode(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "configure");
+	if (!lua_isnil(L, -1)) {
+		if (boost::shared_ptr<PubSubConfigure> payload = boost::dynamic_pointer_cast<PubSubConfigure>(convertors->convertFromLuaUntyped(L, -1, "pubsub_configure"))) {
+			result->setConfigure(payload);
+		}
+	}
+	lua_pop(L, 1);
+	return result;
+}
+
+void PubSubCreateConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubCreate> payload) {
+	lua_createtable(L, 0, 0);
+	lua_pushstring(L, payload->getNode().c_str());
+	lua_setfield(L, -2, "node");
+	if (convertors->convertToLuaUntyped(L, payload->getConfigure()) > 0) {
+		lua_setfield(L, -2, "configure");
+	}
+}
diff --git a/Sluift/ElementConvertors/PubSubCreateConvertor.h b/Sluift/ElementConvertors/PubSubCreateConvertor.h
new file mode 100644
index 0000000..2cb1ea6
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubCreateConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubCreate.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubCreateConvertor : public GenericLuaElementConvertor<PubSubCreate> {
+		public:
+			PubSubCreateConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubCreateConvertor();
+
+			virtual boost::shared_ptr<PubSubCreate> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubCreate>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubDefaultConvertor.cpp b/Sluift/ElementConvertors/PubSubDefaultConvertor.cpp
new file mode 100644
index 0000000..89609ed
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubDefaultConvertor.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubDefaultConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+
+
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubDefaultConvertor::PubSubDefaultConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubDefault>("pubsub_default"),
+		convertors(convertors) {
+}
+
+PubSubDefaultConvertor::~PubSubDefaultConvertor() {
+}
+
+boost::shared_ptr<PubSubDefault> PubSubDefaultConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubDefault> result = boost::make_shared<PubSubDefault>();
+	lua_getfield(L, -1, "node");
+	if (lua_isstring(L, -1)) {
+		result->setNode(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "type");
+	lua_pop(L, 1);
+	return result;
+}
+
+void PubSubDefaultConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubDefault> payload) {
+	lua_createtable(L, 0, 0);
+	if (payload->getNode()) {
+		lua_pushstring(L, (*payload->getNode()).c_str());
+		lua_setfield(L, -2, "node");
+	}
+	switch (payload->getType()) {
+		case PubSubDefault::None:
+			lua_pushstring(L, "none");
+			break;
+		case PubSubDefault::Collection:
+			lua_pushstring(L, "collection");
+			break;
+		case PubSubDefault::Leaf:
+			lua_pushstring(L, "leaf");
+			break;
+	}
+	lua_setfield(L, -2, "type");
+}
diff --git a/Sluift/ElementConvertors/PubSubDefaultConvertor.h b/Sluift/ElementConvertors/PubSubDefaultConvertor.h
new file mode 100644
index 0000000..89dd9be
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubDefaultConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubDefault.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubDefaultConvertor : public GenericLuaElementConvertor<PubSubDefault> {
+		public:
+			PubSubDefaultConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubDefaultConvertor();
+
+			virtual boost::shared_ptr<PubSubDefault> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubDefault>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubEventAssociateConvertor.cpp b/Sluift/ElementConvertors/PubSubEventAssociateConvertor.cpp
new file mode 100644
index 0000000..2b004c8
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubEventAssociateConvertor.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubEventAssociateConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+
+
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubEventAssociateConvertor::PubSubEventAssociateConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubEventAssociate>("pubsub_event_associate"),
+		convertors(convertors) {
+}
+
+PubSubEventAssociateConvertor::~PubSubEventAssociateConvertor() {
+}
+
+boost::shared_ptr<PubSubEventAssociate> PubSubEventAssociateConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubEventAssociate> result = boost::make_shared<PubSubEventAssociate>();
+	lua_getfield(L, -1, "node");
+	if (lua_isstring(L, -1)) {
+		result->setNode(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	return result;
+}
+
+void PubSubEventAssociateConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubEventAssociate> payload) {
+	lua_createtable(L, 0, 0);
+	lua_pushstring(L, payload->getNode().c_str());
+	lua_setfield(L, -2, "node");
+}
diff --git a/Sluift/ElementConvertors/PubSubEventAssociateConvertor.h b/Sluift/ElementConvertors/PubSubEventAssociateConvertor.h
new file mode 100644
index 0000000..60c9d28
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubEventAssociateConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubEventAssociate.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubEventAssociateConvertor : public GenericLuaElementConvertor<PubSubEventAssociate> {
+		public:
+			PubSubEventAssociateConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubEventAssociateConvertor();
+
+			virtual boost::shared_ptr<PubSubEventAssociate> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubEventAssociate>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubEventCollectionConvertor.cpp b/Sluift/ElementConvertors/PubSubEventCollectionConvertor.cpp
new file mode 100644
index 0000000..d05b479
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubEventCollectionConvertor.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubEventCollectionConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+
+#include <Sluift/LuaElementConvertors.h>
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubEventCollectionConvertor::PubSubEventCollectionConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubEventCollection>("pubsub_event_collection"),
+		convertors(convertors) {
+}
+
+PubSubEventCollectionConvertor::~PubSubEventCollectionConvertor() {
+}
+
+boost::shared_ptr<PubSubEventCollection> PubSubEventCollectionConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubEventCollection> result = boost::make_shared<PubSubEventCollection>();
+	lua_getfield(L, -1, "node");
+	if (lua_isstring(L, -1)) {
+		result->setNode(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "disassociate");
+	if (!lua_isnil(L, -1)) {
+		if (boost::shared_ptr<PubSubEventDisassociate> payload = boost::dynamic_pointer_cast<PubSubEventDisassociate>(convertors->convertFromLuaUntyped(L, -1, "pubsub_event_disassociate"))) {
+			result->setDisassociate(payload);
+		}
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "associate");
+	if (!lua_isnil(L, -1)) {
+		if (boost::shared_ptr<PubSubEventAssociate> payload = boost::dynamic_pointer_cast<PubSubEventAssociate>(convertors->convertFromLuaUntyped(L, -1, "pubsub_event_associate"))) {
+			result->setAssociate(payload);
+		}
+	}
+	lua_pop(L, 1);
+	return result;
+}
+
+void PubSubEventCollectionConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubEventCollection> payload) {
+	lua_createtable(L, 0, 0);
+	if (payload->getNode()) {
+		lua_pushstring(L, (*payload->getNode()).c_str());
+		lua_setfield(L, -2, "node");
+	}
+	if (convertors->convertToLuaUntyped(L, payload->getDisassociate()) > 0) {
+		lua_setfield(L, -2, "disassociate");
+	}
+	if (convertors->convertToLuaUntyped(L, payload->getAssociate()) > 0) {
+		lua_setfield(L, -2, "associate");
+	}
+}
diff --git a/Sluift/ElementConvertors/PubSubEventCollectionConvertor.h b/Sluift/ElementConvertors/PubSubEventCollectionConvertor.h
new file mode 100644
index 0000000..eed2541
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubEventCollectionConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubEventCollection.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubEventCollectionConvertor : public GenericLuaElementConvertor<PubSubEventCollection> {
+		public:
+			PubSubEventCollectionConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubEventCollectionConvertor();
+
+			virtual boost::shared_ptr<PubSubEventCollection> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubEventCollection>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubEventConfigurationConvertor.cpp b/Sluift/ElementConvertors/PubSubEventConfigurationConvertor.cpp
new file mode 100644
index 0000000..ecdf145
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubEventConfigurationConvertor.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubEventConfigurationConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+
+#include <Sluift/LuaElementConvertors.h>
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubEventConfigurationConvertor::PubSubEventConfigurationConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubEventConfiguration>("pubsub_event_configuration"),
+		convertors(convertors) {
+}
+
+PubSubEventConfigurationConvertor::~PubSubEventConfigurationConvertor() {
+}
+
+boost::shared_ptr<PubSubEventConfiguration> PubSubEventConfigurationConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubEventConfiguration> result = boost::make_shared<PubSubEventConfiguration>();
+	lua_getfield(L, -1, "node");
+	if (lua_isstring(L, -1)) {
+		result->setNode(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "data");
+	if (!lua_isnil(L, -1)) {
+		if (boost::shared_ptr<Form> payload = boost::dynamic_pointer_cast<Form>(convertors->convertFromLuaUntyped(L, -1, "form"))) {
+			result->setData(payload);
+		}
+	}
+	lua_pop(L, 1);
+	return result;
+}
+
+void PubSubEventConfigurationConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubEventConfiguration> payload) {
+	lua_createtable(L, 0, 0);
+	lua_pushstring(L, payload->getNode().c_str());
+	lua_setfield(L, -2, "node");
+	if (convertors->convertToLuaUntyped(L, payload->getData()) > 0) {
+		lua_setfield(L, -2, "data");
+	}
+}
diff --git a/Sluift/ElementConvertors/PubSubEventConfigurationConvertor.h b/Sluift/ElementConvertors/PubSubEventConfigurationConvertor.h
new file mode 100644
index 0000000..4347ebc
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubEventConfigurationConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubEventConfiguration.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubEventConfigurationConvertor : public GenericLuaElementConvertor<PubSubEventConfiguration> {
+		public:
+			PubSubEventConfigurationConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubEventConfigurationConvertor();
+
+			virtual boost::shared_ptr<PubSubEventConfiguration> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubEventConfiguration>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubEventConvertor.cpp b/Sluift/ElementConvertors/PubSubEventConvertor.cpp
new file mode 100644
index 0000000..46d870a
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubEventConvertor.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubEventConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+
+#include <Sluift/LuaElementConvertors.h>
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubEventConvertor::PubSubEventConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubEvent>("pubsub_event"),
+		convertors(convertors) {
+}
+
+PubSubEventConvertor::~PubSubEventConvertor() {
+}
+
+boost::shared_ptr<PubSubEvent> PubSubEventConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubEvent> result = boost::make_shared<PubSubEvent>();
+	if (boost::shared_ptr<PubSubEventPayload> payload = boost::dynamic_pointer_cast<PubSubEventPayload>(convertors->convertFromLua(L, -1))) {
+		result->setPayload(payload);
+	}
+	return result;
+}
+
+void PubSubEventConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubEvent> event) {
+	convertors->convertToLua(L,  event->getPayload());
+}
diff --git a/Sluift/ElementConvertors/PubSubEventConvertor.h b/Sluift/ElementConvertors/PubSubEventConvertor.h
new file mode 100644
index 0000000..8250fc4
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubEventConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubEvent.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubEventConvertor : public GenericLuaElementConvertor<PubSubEvent> {
+		public:
+			PubSubEventConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubEventConvertor();
+
+			virtual boost::shared_ptr<PubSubEvent> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubEvent>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubEventDeleteConvertor.cpp b/Sluift/ElementConvertors/PubSubEventDeleteConvertor.cpp
new file mode 100644
index 0000000..b03f22a
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubEventDeleteConvertor.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubEventDeleteConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+
+#include <Sluift/LuaElementConvertors.h>
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubEventDeleteConvertor::PubSubEventDeleteConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubEventDelete>("pubsub_event_delete"),
+		convertors(convertors) {
+}
+
+PubSubEventDeleteConvertor::~PubSubEventDeleteConvertor() {
+}
+
+boost::shared_ptr<PubSubEventDelete> PubSubEventDeleteConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubEventDelete> result = boost::make_shared<PubSubEventDelete>();
+	lua_getfield(L, -1, "node");
+	if (lua_isstring(L, -1)) {
+		result->setNode(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "redirects");
+	if (!lua_isnil(L, -1)) {
+		if (boost::shared_ptr<PubSubEventRedirect> payload = boost::dynamic_pointer_cast<PubSubEventRedirect>(convertors->convertFromLuaUntyped(L, -1, "pubsub_event_redirect"))) {
+			result->setRedirects(payload);
+		}
+	}
+	lua_pop(L, 1);
+	return result;
+}
+
+void PubSubEventDeleteConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubEventDelete> payload) {
+	lua_createtable(L, 0, 0);
+	lua_pushstring(L, payload->getNode().c_str());
+	lua_setfield(L, -2, "node");
+	if (convertors->convertToLuaUntyped(L, payload->getRedirects()) > 0) {
+		lua_setfield(L, -2, "redirects");
+	}
+}
diff --git a/Sluift/ElementConvertors/PubSubEventDeleteConvertor.h b/Sluift/ElementConvertors/PubSubEventDeleteConvertor.h
new file mode 100644
index 0000000..a0cfd3d
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubEventDeleteConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubEventDelete.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubEventDeleteConvertor : public GenericLuaElementConvertor<PubSubEventDelete> {
+		public:
+			PubSubEventDeleteConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubEventDeleteConvertor();
+
+			virtual boost::shared_ptr<PubSubEventDelete> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubEventDelete>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubEventDisassociateConvertor.cpp b/Sluift/ElementConvertors/PubSubEventDisassociateConvertor.cpp
new file mode 100644
index 0000000..ccd8c6e
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubEventDisassociateConvertor.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubEventDisassociateConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+
+
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubEventDisassociateConvertor::PubSubEventDisassociateConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubEventDisassociate>("pubsub_event_disassociate"),
+		convertors(convertors) {
+}
+
+PubSubEventDisassociateConvertor::~PubSubEventDisassociateConvertor() {
+}
+
+boost::shared_ptr<PubSubEventDisassociate> PubSubEventDisassociateConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubEventDisassociate> result = boost::make_shared<PubSubEventDisassociate>();
+	lua_getfield(L, -1, "node");
+	if (lua_isstring(L, -1)) {
+		result->setNode(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	return result;
+}
+
+void PubSubEventDisassociateConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubEventDisassociate> payload) {
+	lua_createtable(L, 0, 0);
+	lua_pushstring(L, payload->getNode().c_str());
+	lua_setfield(L, -2, "node");
+}
diff --git a/Sluift/ElementConvertors/PubSubEventDisassociateConvertor.h b/Sluift/ElementConvertors/PubSubEventDisassociateConvertor.h
new file mode 100644
index 0000000..90c8232
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubEventDisassociateConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubEventDisassociate.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubEventDisassociateConvertor : public GenericLuaElementConvertor<PubSubEventDisassociate> {
+		public:
+			PubSubEventDisassociateConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubEventDisassociateConvertor();
+
+			virtual boost::shared_ptr<PubSubEventDisassociate> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubEventDisassociate>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubEventItemConvertor.cpp b/Sluift/ElementConvertors/PubSubEventItemConvertor.cpp
new file mode 100644
index 0000000..fab4bff
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubEventItemConvertor.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubEventItemConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+
+#include <Sluift/LuaElementConvertors.h>
+#include <Swiften/Base/foreach.h>
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubEventItemConvertor::PubSubEventItemConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubEventItem>("pubsub_event_item"),
+		convertors(convertors) {
+}
+
+PubSubEventItemConvertor::~PubSubEventItemConvertor() {
+}
+
+boost::shared_ptr<PubSubEventItem> PubSubEventItemConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubEventItem> result = boost::make_shared<PubSubEventItem>();
+	lua_getfield(L, -1, "node");
+	if (lua_isstring(L, -1)) {
+		result->setNode(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "publisher");
+	if (lua_isstring(L, -1)) {
+		result->setPublisher(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "data");
+	if (lua_type(L, -1) == LUA_TTABLE) {
+		std::vector< boost::shared_ptr<Payload> > items;
+		for(size_t i = 0; i < lua_objlen(L, -1); ++i) {
+			lua_pushnumber(L, i + 1);
+			lua_gettable(L, -2);
+			if (!lua_isnil(L, -1)) {
+				if (boost::shared_ptr<Payload> payload = convertors->convertFromLua(L, -1)) {
+					items.push_back(payload);
+				}
+			}
+			lua_pop(L, 1);
+		}
+
+		result->setData(items);
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "id");
+	if (lua_isstring(L, -1)) {
+		result->setID(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	return result;
+}
+
+void PubSubEventItemConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubEventItem> payload) {
+	lua_createtable(L, 0, 0);
+	if (payload->getNode()) {
+		lua_pushstring(L, (*payload->getNode()).c_str());
+		lua_setfield(L, -2, "node");
+	}
+	if (payload->getPublisher()) {
+		lua_pushstring(L, (*payload->getPublisher()).c_str());
+		lua_setfield(L, -2, "publisher");
+	}
+	if (!payload->getData().empty()) {
+		lua_createtable(L, boost::numeric_cast<int>(payload->getData().size()), 0);
+		{
+			int i = 0;
+			foreach(boost::shared_ptr<Payload> item, payload->getData()) {
+				if (convertors->convertToLua(L, item) > 0) {
+					lua_rawseti(L, -2, boost::numeric_cast<int>(i+1));
+					++i;
+				}
+			}
+		}
+		lua_setfield(L, -2, "data");
+	}
+	if (payload->getID()) {
+		lua_pushstring(L, (*payload->getID()).c_str());
+		lua_setfield(L, -2, "id");
+	}
+}
diff --git a/Sluift/ElementConvertors/PubSubEventItemConvertor.h b/Sluift/ElementConvertors/PubSubEventItemConvertor.h
new file mode 100644
index 0000000..340602a
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubEventItemConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubEventItem.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubEventItemConvertor : public GenericLuaElementConvertor<PubSubEventItem> {
+		public:
+			PubSubEventItemConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubEventItemConvertor();
+
+			virtual boost::shared_ptr<PubSubEventItem> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubEventItem>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubEventItemsConvertor.cpp b/Sluift/ElementConvertors/PubSubEventItemsConvertor.cpp
new file mode 100644
index 0000000..9996cc6
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubEventItemsConvertor.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubEventItemsConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+
+#include <Sluift/LuaElementConvertors.h>
+#include <Swiften/Base/foreach.h>
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubEventItemsConvertor::PubSubEventItemsConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubEventItems>("pubsub_event_items"),
+		convertors(convertors) {
+}
+
+PubSubEventItemsConvertor::~PubSubEventItemsConvertor() {
+}
+
+boost::shared_ptr<PubSubEventItems> PubSubEventItemsConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubEventItems> result = boost::make_shared<PubSubEventItems>();
+	lua_getfield(L, -1, "node");
+	if (lua_isstring(L, -1)) {
+		result->setNode(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "items");
+	if (lua_type(L, -1) == LUA_TTABLE) {
+		std::vector< boost::shared_ptr<PubSubEventItem> > items;
+		for(size_t i = 0; i < lua_objlen(L, -1); ++i) {
+			lua_pushnumber(L, i + 1);
+			lua_gettable(L, -2);
+			if (!lua_isnil(L, -1)) {
+				if (boost::shared_ptr<PubSubEventItem> payload = boost::dynamic_pointer_cast<PubSubEventItem>(convertors->convertFromLuaUntyped(L, -1, "pubsub_event_item"))) {
+					items.push_back(payload);
+				}
+			}
+			lua_pop(L, 1);
+		}
+
+		result->setItems(items);
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "retracts");
+	if (lua_type(L, -1) == LUA_TTABLE) {
+		std::vector< boost::shared_ptr<PubSubEventRetract> > items;
+		for(size_t i = 0; i < lua_objlen(L, -1); ++i) {
+			lua_pushnumber(L, i + 1);
+			lua_gettable(L, -2);
+			if (!lua_isnil(L, -1)) {
+				if (boost::shared_ptr<PubSubEventRetract> payload = boost::dynamic_pointer_cast<PubSubEventRetract>(convertors->convertFromLuaUntyped(L, -1, "pubsub_event_retract"))) {
+					items.push_back(payload);
+				}
+			}
+			lua_pop(L, 1);
+		}
+
+		result->setRetracts(items);
+	}
+	lua_pop(L, 1);
+	return result;
+}
+
+void PubSubEventItemsConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubEventItems> payload) {
+	lua_createtable(L, 0, 0);
+	lua_pushstring(L, payload->getNode().c_str());
+	lua_setfield(L, -2, "node");
+	if (!payload->getItems().empty()) {
+		lua_createtable(L, boost::numeric_cast<int>(payload->getItems().size()), 0);
+		{
+			int i = 0;
+			foreach(boost::shared_ptr<PubSubEventItem> item, payload->getItems()) {
+				if (convertors->convertToLuaUntyped(L, item) > 0) {
+					lua_rawseti(L, -2, boost::numeric_cast<int>(i+1));
+					++i;
+				}
+			}
+		}
+		lua_setfield(L, -2, "items");
+	}
+	if (!payload->getRetracts().empty()) {
+		lua_createtable(L, boost::numeric_cast<int>(payload->getRetracts().size()), 0);
+		{
+			int i = 0;
+			foreach(boost::shared_ptr<PubSubEventRetract> item, payload->getRetracts()) {
+				if (convertors->convertToLuaUntyped(L, item) > 0) {
+					lua_rawseti(L, -2, boost::numeric_cast<int>(i+1));
+					++i;
+				}
+			}
+		}
+		lua_setfield(L, -2, "retracts");
+	}
+}
diff --git a/Sluift/ElementConvertors/PubSubEventItemsConvertor.h b/Sluift/ElementConvertors/PubSubEventItemsConvertor.h
new file mode 100644
index 0000000..9adbf15
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubEventItemsConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubEventItems.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubEventItemsConvertor : public GenericLuaElementConvertor<PubSubEventItems> {
+		public:
+			PubSubEventItemsConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubEventItemsConvertor();
+
+			virtual boost::shared_ptr<PubSubEventItems> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubEventItems>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubEventPurgeConvertor.cpp b/Sluift/ElementConvertors/PubSubEventPurgeConvertor.cpp
new file mode 100644
index 0000000..e389fcf
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubEventPurgeConvertor.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubEventPurgeConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+
+
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubEventPurgeConvertor::PubSubEventPurgeConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubEventPurge>("pubsub_event_purge"),
+		convertors(convertors) {
+}
+
+PubSubEventPurgeConvertor::~PubSubEventPurgeConvertor() {
+}
+
+boost::shared_ptr<PubSubEventPurge> PubSubEventPurgeConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubEventPurge> result = boost::make_shared<PubSubEventPurge>();
+	lua_getfield(L, -1, "node");
+	if (lua_isstring(L, -1)) {
+		result->setNode(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	return result;
+}
+
+void PubSubEventPurgeConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubEventPurge> payload) {
+	lua_createtable(L, 0, 0);
+	lua_pushstring(L, payload->getNode().c_str());
+	lua_setfield(L, -2, "node");
+}
diff --git a/Sluift/ElementConvertors/PubSubEventPurgeConvertor.h b/Sluift/ElementConvertors/PubSubEventPurgeConvertor.h
new file mode 100644
index 0000000..d94aa36
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubEventPurgeConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubEventPurge.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubEventPurgeConvertor : public GenericLuaElementConvertor<PubSubEventPurge> {
+		public:
+			PubSubEventPurgeConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubEventPurgeConvertor();
+
+			virtual boost::shared_ptr<PubSubEventPurge> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubEventPurge>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubEventRedirectConvertor.cpp b/Sluift/ElementConvertors/PubSubEventRedirectConvertor.cpp
new file mode 100644
index 0000000..6e128da
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubEventRedirectConvertor.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubEventRedirectConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+
+
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubEventRedirectConvertor::PubSubEventRedirectConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubEventRedirect>("pubsub_event_redirect"),
+		convertors(convertors) {
+}
+
+PubSubEventRedirectConvertor::~PubSubEventRedirectConvertor() {
+}
+
+boost::shared_ptr<PubSubEventRedirect> PubSubEventRedirectConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubEventRedirect> result = boost::make_shared<PubSubEventRedirect>();
+	lua_getfield(L, -1, "uri");
+	if (lua_isstring(L, -1)) {
+		result->setURI(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	return result;
+}
+
+void PubSubEventRedirectConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubEventRedirect> payload) {
+	lua_createtable(L, 0, 0);
+	lua_pushstring(L, payload->getURI().c_str());
+	lua_setfield(L, -2, "uri");
+}
diff --git a/Sluift/ElementConvertors/PubSubEventRedirectConvertor.h b/Sluift/ElementConvertors/PubSubEventRedirectConvertor.h
new file mode 100644
index 0000000..4904102
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubEventRedirectConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubEventRedirect.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubEventRedirectConvertor : public GenericLuaElementConvertor<PubSubEventRedirect> {
+		public:
+			PubSubEventRedirectConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubEventRedirectConvertor();
+
+			virtual boost::shared_ptr<PubSubEventRedirect> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubEventRedirect>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubEventRetractConvertor.cpp b/Sluift/ElementConvertors/PubSubEventRetractConvertor.cpp
new file mode 100644
index 0000000..aed29a0
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubEventRetractConvertor.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubEventRetractConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+
+
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubEventRetractConvertor::PubSubEventRetractConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubEventRetract>("pubsub_event_retract"),
+		convertors(convertors) {
+}
+
+PubSubEventRetractConvertor::~PubSubEventRetractConvertor() {
+}
+
+boost::shared_ptr<PubSubEventRetract> PubSubEventRetractConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubEventRetract> result = boost::make_shared<PubSubEventRetract>();
+	lua_getfield(L, -1, "id");
+	if (lua_isstring(L, -1)) {
+		result->setID(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	return result;
+}
+
+void PubSubEventRetractConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubEventRetract> payload) {
+	lua_createtable(L, 0, 0);
+	lua_pushstring(L, payload->getID().c_str());
+	lua_setfield(L, -2, "id");
+}
diff --git a/Sluift/ElementConvertors/PubSubEventRetractConvertor.h b/Sluift/ElementConvertors/PubSubEventRetractConvertor.h
new file mode 100644
index 0000000..7a7c0f9
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubEventRetractConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubEventRetract.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubEventRetractConvertor : public GenericLuaElementConvertor<PubSubEventRetract> {
+		public:
+			PubSubEventRetractConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubEventRetractConvertor();
+
+			virtual boost::shared_ptr<PubSubEventRetract> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubEventRetract>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubEventSubscriptionConvertor.cpp b/Sluift/ElementConvertors/PubSubEventSubscriptionConvertor.cpp
new file mode 100644
index 0000000..68cb34a
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubEventSubscriptionConvertor.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubEventSubscriptionConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+
+#include <Swiften/Base/DateTime.h>
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubEventSubscriptionConvertor::PubSubEventSubscriptionConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubEventSubscription>("pubsub_event_subscription"),
+		convertors(convertors) {
+}
+
+PubSubEventSubscriptionConvertor::~PubSubEventSubscriptionConvertor() {
+}
+
+boost::shared_ptr<PubSubEventSubscription> PubSubEventSubscriptionConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubEventSubscription> result = boost::make_shared<PubSubEventSubscription>();
+	lua_getfield(L, -1, "node");
+	if (lua_isstring(L, -1)) {
+		result->setNode(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "jid");
+	if (lua_isstring(L, -1)) {
+		result->setJID(JID(std::string(lua_tostring(L, -1))));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "subscription");
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "subscriptionid");
+	if (lua_isstring(L, -1)) {
+		result->setSubscriptionID(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "expiry");
+	if (lua_isstring(L, -1)) {
+		result->setExpiry(stringToDateTime(std::string(lua_tostring(L, -1))));
+	}
+	lua_pop(L, 1);
+	return result;
+}
+
+void PubSubEventSubscriptionConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubEventSubscription> payload) {
+	lua_createtable(L, 0, 0);
+	lua_pushstring(L, payload->getNode().c_str());
+	lua_setfield(L, -2, "node");
+	lua_pushstring(L, payload->getJID().toString().c_str());
+	lua_setfield(L, -2, "jid");
+	switch (payload->getSubscription()) {
+		case PubSubEventSubscription::None:
+			lua_pushstring(L, "none");
+			break;
+		case PubSubEventSubscription::Pending:
+			lua_pushstring(L, "pending");
+			break;
+		case PubSubEventSubscription::Subscribed:
+			lua_pushstring(L, "subscribed");
+			break;
+		case PubSubEventSubscription::Unconfigured:
+			lua_pushstring(L, "unconfigured");
+			break;
+	}
+	lua_setfield(L, -2, "subscription");
+	if (payload->getSubscriptionID()) {
+		lua_pushstring(L, (*payload->getSubscriptionID()).c_str());
+		lua_setfield(L, -2, "subscriptionid");
+	}
+	lua_pushstring(L, dateTimeToString(payload->getExpiry()).c_str());
+	lua_setfield(L, -2, "expiry");
+}
diff --git a/Sluift/ElementConvertors/PubSubEventSubscriptionConvertor.h b/Sluift/ElementConvertors/PubSubEventSubscriptionConvertor.h
new file mode 100644
index 0000000..fa04fb7
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubEventSubscriptionConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubEventSubscription.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubEventSubscriptionConvertor : public GenericLuaElementConvertor<PubSubEventSubscription> {
+		public:
+			PubSubEventSubscriptionConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubEventSubscriptionConvertor();
+
+			virtual boost::shared_ptr<PubSubEventSubscription> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubEventSubscription>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubItemConvertor.cpp b/Sluift/ElementConvertors/PubSubItemConvertor.cpp
new file mode 100644
index 0000000..e06065b
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubItemConvertor.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubItemConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+
+#include <Sluift/LuaElementConvertors.h>
+#include <Swiften/Base/foreach.h>
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubItemConvertor::PubSubItemConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubItem>("pubsub_item"),
+		convertors(convertors) {
+}
+
+PubSubItemConvertor::~PubSubItemConvertor() {
+}
+
+boost::shared_ptr<PubSubItem> PubSubItemConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubItem> result = boost::make_shared<PubSubItem>();
+	lua_getfield(L, -1, "data");
+	if (lua_type(L, -1) == LUA_TTABLE) {
+		std::vector< boost::shared_ptr<Payload> > items;
+		for(size_t i = 0; i < lua_objlen(L, -1); ++i) {
+			lua_pushnumber(L, i + 1);
+			lua_gettable(L, -2);
+			if (!lua_isnil(L, -1)) {
+				if (boost::shared_ptr<Payload> payload = convertors->convertFromLua(L, -1)) {
+					items.push_back(payload);
+				}
+			}
+			lua_pop(L, 1);
+		}
+
+		result->setData(items);
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "id");
+	if (lua_isstring(L, -1)) {
+		result->setID(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	return result;
+}
+
+void PubSubItemConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubItem> payload) {
+	lua_createtable(L, 0, 0);
+	if (!payload->getData().empty()) {
+		lua_createtable(L, boost::numeric_cast<int>(payload->getData().size()), 0);
+		{
+			int i = 0;
+			foreach(boost::shared_ptr<Payload> item, payload->getData()) {
+				if (convertors->convertToLua(L, item) > 0) {
+					lua_rawseti(L, -2, boost::numeric_cast<int>(i+1));
+					++i;
+				}
+			}
+		}
+		lua_setfield(L, -2, "data");
+	}
+	lua_pushstring(L, payload->getID().c_str());
+	lua_setfield(L, -2, "id");
+}
diff --git a/Sluift/ElementConvertors/PubSubItemConvertor.h b/Sluift/ElementConvertors/PubSubItemConvertor.h
new file mode 100644
index 0000000..176e1c4
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubItemConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubItem.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubItemConvertor : public GenericLuaElementConvertor<PubSubItem> {
+		public:
+			PubSubItemConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubItemConvertor();
+
+			virtual boost::shared_ptr<PubSubItem> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubItem>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubItemsConvertor.cpp b/Sluift/ElementConvertors/PubSubItemsConvertor.cpp
new file mode 100644
index 0000000..5ecb72e
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubItemsConvertor.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubItemsConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+
+#include <Sluift/LuaElementConvertors.h>
+#include <Swiften/Base/foreach.h>
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubItemsConvertor::PubSubItemsConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubItems>("pubsub_items"),
+		convertors(convertors) {
+}
+
+PubSubItemsConvertor::~PubSubItemsConvertor() {
+}
+
+boost::shared_ptr<PubSubItems> PubSubItemsConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubItems> result = boost::make_shared<PubSubItems>();
+	lua_getfield(L, -1, "node");
+	if (lua_isstring(L, -1)) {
+		result->setNode(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	if (lua_type(L, -1) == LUA_TTABLE) {
+		std::vector< boost::shared_ptr<PubSubItem> > items;
+		for(size_t i = 0; i < lua_objlen(L, -1); ++i) {
+			lua_pushnumber(L, i + 1);
+			lua_gettable(L, -2);
+			if (!lua_isnil(L, -1)) {
+				if (boost::shared_ptr<PubSubItem> payload = boost::dynamic_pointer_cast<PubSubItem>(convertors->convertFromLuaUntyped(L, -1, "pubsub_item"))) {
+					items.push_back(payload);
+				}
+			}
+			lua_pop(L, 1);
+		}
+
+		result->setItems(items);
+	}
+	lua_getfield(L, -1, "maximum_items");
+	if (lua_isnumber(L, -1)) {
+		result->setMaximumItems(boost::numeric_cast<unsigned int>(lua_tonumber(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "subscriptionid");
+	if (lua_isstring(L, -1)) {
+		result->setSubscriptionID(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	return result;
+}
+
+void PubSubItemsConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubItems> payload) {
+	lua_createtable(L, 0, 0);
+	lua_pushstring(L, payload->getNode().c_str());
+	lua_setfield(L, -2, "node");
+	if (!payload->getItems().empty()) {
+		{
+			int i = 0;
+			foreach(boost::shared_ptr<PubSubItem> item, payload->getItems()) {
+				if (convertors->convertToLuaUntyped(L, item) > 0) {
+					lua_rawseti(L, -2, boost::numeric_cast<int>(i+1));
+					++i;
+				}
+			}
+		}
+	}
+	if (payload->getMaximumItems()) {
+		lua_pushnumber(L, (*payload->getMaximumItems()));
+		lua_setfield(L, -2, "maximum_items");
+	}
+	if (payload->getSubscriptionID()) {
+		lua_pushstring(L, (*payload->getSubscriptionID()).c_str());
+		lua_setfield(L, -2, "subscriptionid");
+	}
+}
diff --git a/Sluift/ElementConvertors/PubSubItemsConvertor.h b/Sluift/ElementConvertors/PubSubItemsConvertor.h
new file mode 100644
index 0000000..9978806
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubItemsConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubItems.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubItemsConvertor : public GenericLuaElementConvertor<PubSubItems> {
+		public:
+			PubSubItemsConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubItemsConvertor();
+
+			virtual boost::shared_ptr<PubSubItems> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubItems>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubOptionsConvertor.cpp b/Sluift/ElementConvertors/PubSubOptionsConvertor.cpp
new file mode 100644
index 0000000..cc27973
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubOptionsConvertor.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubOptionsConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+
+#include <Sluift/LuaElementConvertors.h>
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubOptionsConvertor::PubSubOptionsConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubOptions>("pubsub_options"),
+		convertors(convertors) {
+}
+
+PubSubOptionsConvertor::~PubSubOptionsConvertor() {
+}
+
+boost::shared_ptr<PubSubOptions> PubSubOptionsConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubOptions> result = boost::make_shared<PubSubOptions>();
+	lua_getfield(L, -1, "node");
+	if (lua_isstring(L, -1)) {
+		result->setNode(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "jid");
+	if (lua_isstring(L, -1)) {
+		result->setJID(JID(std::string(lua_tostring(L, -1))));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "data");
+	if (!lua_isnil(L, -1)) {
+		if (boost::shared_ptr<Form> payload = boost::dynamic_pointer_cast<Form>(convertors->convertFromLuaUntyped(L, -1, "form"))) {
+			result->setData(payload);
+		}
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "subscriptionid");
+	if (lua_isstring(L, -1)) {
+		result->setSubscriptionID(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	return result;
+}
+
+void PubSubOptionsConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubOptions> payload) {
+	lua_createtable(L, 0, 0);
+	lua_pushstring(L, payload->getNode().c_str());
+	lua_setfield(L, -2, "node");
+	lua_pushstring(L, payload->getJID().toString().c_str());
+	lua_setfield(L, -2, "jid");
+	if (convertors->convertToLuaUntyped(L, payload->getData()) > 0) {
+		lua_setfield(L, -2, "data");
+	}
+	if (payload->getSubscriptionID()) {
+		lua_pushstring(L, (*payload->getSubscriptionID()).c_str());
+		lua_setfield(L, -2, "subscriptionid");
+	}
+}
diff --git a/Sluift/ElementConvertors/PubSubOptionsConvertor.h b/Sluift/ElementConvertors/PubSubOptionsConvertor.h
new file mode 100644
index 0000000..95a1dc8
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubOptionsConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubOptions.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubOptionsConvertor : public GenericLuaElementConvertor<PubSubOptions> {
+		public:
+			PubSubOptionsConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubOptionsConvertor();
+
+			virtual boost::shared_ptr<PubSubOptions> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubOptions>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubOwnerAffiliationConvertor.cpp b/Sluift/ElementConvertors/PubSubOwnerAffiliationConvertor.cpp
new file mode 100644
index 0000000..d7edaf4
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubOwnerAffiliationConvertor.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubOwnerAffiliationConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+
+
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubOwnerAffiliationConvertor::PubSubOwnerAffiliationConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubOwnerAffiliation>("pubsub_owner_affiliation"),
+		convertors(convertors) {
+}
+
+PubSubOwnerAffiliationConvertor::~PubSubOwnerAffiliationConvertor() {
+}
+
+boost::shared_ptr<PubSubOwnerAffiliation> PubSubOwnerAffiliationConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubOwnerAffiliation> result = boost::make_shared<PubSubOwnerAffiliation>();
+	lua_getfield(L, -1, "jid");
+	if (lua_isstring(L, -1)) {
+		result->setJID(JID(std::string(lua_tostring(L, -1))));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "type");
+	lua_pop(L, 1);
+	return result;
+}
+
+void PubSubOwnerAffiliationConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubOwnerAffiliation> payload) {
+	lua_createtable(L, 0, 0);
+	lua_pushstring(L, payload->getJID().toString().c_str());
+	lua_setfield(L, -2, "jid");
+	switch (payload->getType()) {
+		case PubSubOwnerAffiliation::None:
+			lua_pushstring(L, "none");
+			break;
+		case PubSubOwnerAffiliation::Member:
+			lua_pushstring(L, "member");
+			break;
+		case PubSubOwnerAffiliation::Outcast:
+			lua_pushstring(L, "outcast");
+			break;
+		case PubSubOwnerAffiliation::Owner:
+			lua_pushstring(L, "owner");
+			break;
+		case PubSubOwnerAffiliation::Publisher:
+			lua_pushstring(L, "publisher");
+			break;
+		case PubSubOwnerAffiliation::PublishOnly:
+			lua_pushstring(L, "publish_only");
+			break;
+	}
+	lua_setfield(L, -2, "type");
+}
diff --git a/Sluift/ElementConvertors/PubSubOwnerAffiliationConvertor.h b/Sluift/ElementConvertors/PubSubOwnerAffiliationConvertor.h
new file mode 100644
index 0000000..72bfaa1
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubOwnerAffiliationConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubOwnerAffiliation.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubOwnerAffiliationConvertor : public GenericLuaElementConvertor<PubSubOwnerAffiliation> {
+		public:
+			PubSubOwnerAffiliationConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubOwnerAffiliationConvertor();
+
+			virtual boost::shared_ptr<PubSubOwnerAffiliation> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubOwnerAffiliation>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubOwnerAffiliationsConvertor.cpp b/Sluift/ElementConvertors/PubSubOwnerAffiliationsConvertor.cpp
new file mode 100644
index 0000000..bee8539
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubOwnerAffiliationsConvertor.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubOwnerAffiliationsConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+
+#include <Sluift/LuaElementConvertors.h>
+#include <Swiften/Base/foreach.h>
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubOwnerAffiliationsConvertor::PubSubOwnerAffiliationsConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubOwnerAffiliations>("pubsub_owner_affiliations"),
+		convertors(convertors) {
+}
+
+PubSubOwnerAffiliationsConvertor::~PubSubOwnerAffiliationsConvertor() {
+}
+
+boost::shared_ptr<PubSubOwnerAffiliations> PubSubOwnerAffiliationsConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubOwnerAffiliations> result = boost::make_shared<PubSubOwnerAffiliations>();
+	lua_getfield(L, -1, "node");
+	if (lua_isstring(L, -1)) {
+		result->setNode(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	if (lua_type(L, -1) == LUA_TTABLE) {
+		std::vector< boost::shared_ptr<PubSubOwnerAffiliation> > items;
+		for(size_t i = 0; i < lua_objlen(L, -1); ++i) {
+			lua_pushnumber(L, i + 1);
+			lua_gettable(L, -2);
+			if (!lua_isnil(L, -1)) {
+				if (boost::shared_ptr<PubSubOwnerAffiliation> payload = boost::dynamic_pointer_cast<PubSubOwnerAffiliation>(convertors->convertFromLuaUntyped(L, -1, "pubsub_owner_affiliation"))) {
+					items.push_back(payload);
+				}
+			}
+			lua_pop(L, 1);
+		}
+
+		result->setAffiliations(items);
+	}
+	return result;
+}
+
+void PubSubOwnerAffiliationsConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubOwnerAffiliations> payload) {
+	lua_createtable(L, 0, 0);
+	lua_pushstring(L, payload->getNode().c_str());
+	lua_setfield(L, -2, "node");
+	if (!payload->getAffiliations().empty()) {
+		{
+			int i = 0;
+			foreach(boost::shared_ptr<PubSubOwnerAffiliation> item, payload->getAffiliations()) {
+				if (convertors->convertToLuaUntyped(L, item) > 0) {
+					lua_rawseti(L, -2, boost::numeric_cast<int>(i+1));
+					++i;
+				}
+			}
+		}
+	}
+}
diff --git a/Sluift/ElementConvertors/PubSubOwnerAffiliationsConvertor.h b/Sluift/ElementConvertors/PubSubOwnerAffiliationsConvertor.h
new file mode 100644
index 0000000..377e108
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubOwnerAffiliationsConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubOwnerAffiliations.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubOwnerAffiliationsConvertor : public GenericLuaElementConvertor<PubSubOwnerAffiliations> {
+		public:
+			PubSubOwnerAffiliationsConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubOwnerAffiliationsConvertor();
+
+			virtual boost::shared_ptr<PubSubOwnerAffiliations> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubOwnerAffiliations>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubOwnerConfigureConvertor.cpp b/Sluift/ElementConvertors/PubSubOwnerConfigureConvertor.cpp
new file mode 100644
index 0000000..87505e1
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubOwnerConfigureConvertor.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubOwnerConfigureConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+
+#include <Sluift/LuaElementConvertors.h>
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubOwnerConfigureConvertor::PubSubOwnerConfigureConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubOwnerConfigure>("pubsub_owner_configure"),
+		convertors(convertors) {
+}
+
+PubSubOwnerConfigureConvertor::~PubSubOwnerConfigureConvertor() {
+}
+
+boost::shared_ptr<PubSubOwnerConfigure> PubSubOwnerConfigureConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubOwnerConfigure> result = boost::make_shared<PubSubOwnerConfigure>();
+	lua_getfield(L, -1, "node");
+	if (lua_isstring(L, -1)) {
+		result->setNode(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "data");
+	if (!lua_isnil(L, -1)) {
+		if (boost::shared_ptr<Form> payload = boost::dynamic_pointer_cast<Form>(convertors->convertFromLuaUntyped(L, -1, "form"))) {
+			result->setData(payload);
+		}
+	}
+	lua_pop(L, 1);
+	return result;
+}
+
+void PubSubOwnerConfigureConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubOwnerConfigure> payload) {
+	lua_createtable(L, 0, 0);
+	if (payload->getNode()) {
+		lua_pushstring(L, (*payload->getNode()).c_str());
+		lua_setfield(L, -2, "node");
+	}
+	if (convertors->convertToLuaUntyped(L, payload->getData()) > 0) {
+		lua_setfield(L, -2, "data");
+	}
+}
diff --git a/Sluift/ElementConvertors/PubSubOwnerConfigureConvertor.h b/Sluift/ElementConvertors/PubSubOwnerConfigureConvertor.h
new file mode 100644
index 0000000..83b1153
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubOwnerConfigureConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubOwnerConfigure.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubOwnerConfigureConvertor : public GenericLuaElementConvertor<PubSubOwnerConfigure> {
+		public:
+			PubSubOwnerConfigureConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubOwnerConfigureConvertor();
+
+			virtual boost::shared_ptr<PubSubOwnerConfigure> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubOwnerConfigure>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubOwnerDefaultConvertor.cpp b/Sluift/ElementConvertors/PubSubOwnerDefaultConvertor.cpp
new file mode 100644
index 0000000..17612cc
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubOwnerDefaultConvertor.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubOwnerDefaultConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+
+#include <Sluift/LuaElementConvertors.h>
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubOwnerDefaultConvertor::PubSubOwnerDefaultConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubOwnerDefault>("pubsub_owner_default"),
+		convertors(convertors) {
+}
+
+PubSubOwnerDefaultConvertor::~PubSubOwnerDefaultConvertor() {
+}
+
+boost::shared_ptr<PubSubOwnerDefault> PubSubOwnerDefaultConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubOwnerDefault> result = boost::make_shared<PubSubOwnerDefault>();
+	lua_getfield(L, -1, "data");
+	if (!lua_isnil(L, -1)) {
+		if (boost::shared_ptr<Form> payload = boost::dynamic_pointer_cast<Form>(convertors->convertFromLuaUntyped(L, -1, "form"))) {
+			result->setData(payload);
+		}
+	}
+	lua_pop(L, 1);
+	return result;
+}
+
+void PubSubOwnerDefaultConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubOwnerDefault> payload) {
+	lua_createtable(L, 0, 0);
+	if (convertors->convertToLuaUntyped(L, payload->getData()) > 0) {
+		lua_setfield(L, -2, "data");
+	}
+}
diff --git a/Sluift/ElementConvertors/PubSubOwnerDefaultConvertor.h b/Sluift/ElementConvertors/PubSubOwnerDefaultConvertor.h
new file mode 100644
index 0000000..3a0f8ee
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubOwnerDefaultConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubOwnerDefault.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubOwnerDefaultConvertor : public GenericLuaElementConvertor<PubSubOwnerDefault> {
+		public:
+			PubSubOwnerDefaultConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubOwnerDefaultConvertor();
+
+			virtual boost::shared_ptr<PubSubOwnerDefault> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubOwnerDefault>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubOwnerDeleteConvertor.cpp b/Sluift/ElementConvertors/PubSubOwnerDeleteConvertor.cpp
new file mode 100644
index 0000000..f67ed1e
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubOwnerDeleteConvertor.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubOwnerDeleteConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+
+#include <Sluift/LuaElementConvertors.h>
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubOwnerDeleteConvertor::PubSubOwnerDeleteConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubOwnerDelete>("pubsub_owner_delete"),
+		convertors(convertors) {
+}
+
+PubSubOwnerDeleteConvertor::~PubSubOwnerDeleteConvertor() {
+}
+
+boost::shared_ptr<PubSubOwnerDelete> PubSubOwnerDeleteConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubOwnerDelete> result = boost::make_shared<PubSubOwnerDelete>();
+	lua_getfield(L, -1, "node");
+	if (lua_isstring(L, -1)) {
+		result->setNode(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "redirect");
+	if (!lua_isnil(L, -1)) {
+		if (boost::shared_ptr<PubSubOwnerRedirect> payload = boost::dynamic_pointer_cast<PubSubOwnerRedirect>(convertors->convertFromLuaUntyped(L, -1, "pubsub_owner_redirect"))) {
+			result->setRedirect(payload);
+		}
+	}
+	lua_pop(L, 1);
+	return result;
+}
+
+void PubSubOwnerDeleteConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubOwnerDelete> payload) {
+	lua_createtable(L, 0, 0);
+	lua_pushstring(L, payload->getNode().c_str());
+	lua_setfield(L, -2, "node");
+	if (convertors->convertToLuaUntyped(L, payload->getRedirect()) > 0) {
+		lua_setfield(L, -2, "redirect");
+	}
+}
diff --git a/Sluift/ElementConvertors/PubSubOwnerDeleteConvertor.h b/Sluift/ElementConvertors/PubSubOwnerDeleteConvertor.h
new file mode 100644
index 0000000..7475e9c
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubOwnerDeleteConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubOwnerDelete.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubOwnerDeleteConvertor : public GenericLuaElementConvertor<PubSubOwnerDelete> {
+		public:
+			PubSubOwnerDeleteConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubOwnerDeleteConvertor();
+
+			virtual boost::shared_ptr<PubSubOwnerDelete> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubOwnerDelete>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubOwnerPurgeConvertor.cpp b/Sluift/ElementConvertors/PubSubOwnerPurgeConvertor.cpp
new file mode 100644
index 0000000..a060db9
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubOwnerPurgeConvertor.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubOwnerPurgeConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+
+
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubOwnerPurgeConvertor::PubSubOwnerPurgeConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubOwnerPurge>("pubsub_owner_purge"),
+		convertors(convertors) {
+}
+
+PubSubOwnerPurgeConvertor::~PubSubOwnerPurgeConvertor() {
+}
+
+boost::shared_ptr<PubSubOwnerPurge> PubSubOwnerPurgeConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubOwnerPurge> result = boost::make_shared<PubSubOwnerPurge>();
+	lua_getfield(L, -1, "node");
+	if (lua_isstring(L, -1)) {
+		result->setNode(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	return result;
+}
+
+void PubSubOwnerPurgeConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubOwnerPurge> payload) {
+	lua_createtable(L, 0, 0);
+	lua_pushstring(L, payload->getNode().c_str());
+	lua_setfield(L, -2, "node");
+}
diff --git a/Sluift/ElementConvertors/PubSubOwnerPurgeConvertor.h b/Sluift/ElementConvertors/PubSubOwnerPurgeConvertor.h
new file mode 100644
index 0000000..34c979b
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubOwnerPurgeConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubOwnerPurge.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubOwnerPurgeConvertor : public GenericLuaElementConvertor<PubSubOwnerPurge> {
+		public:
+			PubSubOwnerPurgeConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubOwnerPurgeConvertor();
+
+			virtual boost::shared_ptr<PubSubOwnerPurge> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubOwnerPurge>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubOwnerRedirectConvertor.cpp b/Sluift/ElementConvertors/PubSubOwnerRedirectConvertor.cpp
new file mode 100644
index 0000000..d11df72
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubOwnerRedirectConvertor.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubOwnerRedirectConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+
+
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubOwnerRedirectConvertor::PubSubOwnerRedirectConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubOwnerRedirect>("pubsub_owner_redirect"),
+		convertors(convertors) {
+}
+
+PubSubOwnerRedirectConvertor::~PubSubOwnerRedirectConvertor() {
+}
+
+boost::shared_ptr<PubSubOwnerRedirect> PubSubOwnerRedirectConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubOwnerRedirect> result = boost::make_shared<PubSubOwnerRedirect>();
+	lua_getfield(L, -1, "uri");
+	if (lua_isstring(L, -1)) {
+		result->setURI(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	return result;
+}
+
+void PubSubOwnerRedirectConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubOwnerRedirect> payload) {
+	lua_createtable(L, 0, 0);
+	lua_pushstring(L, payload->getURI().c_str());
+	lua_setfield(L, -2, "uri");
+}
diff --git a/Sluift/ElementConvertors/PubSubOwnerRedirectConvertor.h b/Sluift/ElementConvertors/PubSubOwnerRedirectConvertor.h
new file mode 100644
index 0000000..fc1ddce
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubOwnerRedirectConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubOwnerRedirect.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubOwnerRedirectConvertor : public GenericLuaElementConvertor<PubSubOwnerRedirect> {
+		public:
+			PubSubOwnerRedirectConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubOwnerRedirectConvertor();
+
+			virtual boost::shared_ptr<PubSubOwnerRedirect> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubOwnerRedirect>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubOwnerSubscriptionConvertor.cpp b/Sluift/ElementConvertors/PubSubOwnerSubscriptionConvertor.cpp
new file mode 100644
index 0000000..0216874
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubOwnerSubscriptionConvertor.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubOwnerSubscriptionConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+
+
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubOwnerSubscriptionConvertor::PubSubOwnerSubscriptionConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubOwnerSubscription>("pubsub_owner_subscription"),
+		convertors(convertors) {
+}
+
+PubSubOwnerSubscriptionConvertor::~PubSubOwnerSubscriptionConvertor() {
+}
+
+boost::shared_ptr<PubSubOwnerSubscription> PubSubOwnerSubscriptionConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubOwnerSubscription> result = boost::make_shared<PubSubOwnerSubscription>();
+	lua_getfield(L, -1, "jid");
+	if (lua_isstring(L, -1)) {
+		result->setJID(JID(std::string(lua_tostring(L, -1))));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "subscription");
+	lua_pop(L, 1);
+	return result;
+}
+
+void PubSubOwnerSubscriptionConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubOwnerSubscription> payload) {
+	lua_createtable(L, 0, 0);
+	lua_pushstring(L, payload->getJID().toString().c_str());
+	lua_setfield(L, -2, "jid");
+	switch (payload->getSubscription()) {
+		case PubSubOwnerSubscription::None:
+			lua_pushstring(L, "none");
+			break;
+		case PubSubOwnerSubscription::Pending:
+			lua_pushstring(L, "pending");
+			break;
+		case PubSubOwnerSubscription::Subscribed:
+			lua_pushstring(L, "subscribed");
+			break;
+		case PubSubOwnerSubscription::Unconfigured:
+			lua_pushstring(L, "unconfigured");
+			break;
+	}
+	lua_setfield(L, -2, "subscription");
+}
diff --git a/Sluift/ElementConvertors/PubSubOwnerSubscriptionConvertor.h b/Sluift/ElementConvertors/PubSubOwnerSubscriptionConvertor.h
new file mode 100644
index 0000000..ca80c82
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubOwnerSubscriptionConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubOwnerSubscription.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubOwnerSubscriptionConvertor : public GenericLuaElementConvertor<PubSubOwnerSubscription> {
+		public:
+			PubSubOwnerSubscriptionConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubOwnerSubscriptionConvertor();
+
+			virtual boost::shared_ptr<PubSubOwnerSubscription> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubOwnerSubscription>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubOwnerSubscriptionsConvertor.cpp b/Sluift/ElementConvertors/PubSubOwnerSubscriptionsConvertor.cpp
new file mode 100644
index 0000000..045cf12
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubOwnerSubscriptionsConvertor.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubOwnerSubscriptionsConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+
+#include <Sluift/LuaElementConvertors.h>
+#include <Swiften/Base/foreach.h>
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubOwnerSubscriptionsConvertor::PubSubOwnerSubscriptionsConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubOwnerSubscriptions>("pubsub_owner_subscriptions"),
+		convertors(convertors) {
+}
+
+PubSubOwnerSubscriptionsConvertor::~PubSubOwnerSubscriptionsConvertor() {
+}
+
+boost::shared_ptr<PubSubOwnerSubscriptions> PubSubOwnerSubscriptionsConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubOwnerSubscriptions> result = boost::make_shared<PubSubOwnerSubscriptions>();
+	lua_getfield(L, -1, "node");
+	if (lua_isstring(L, -1)) {
+		result->setNode(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	if (lua_type(L, -1) == LUA_TTABLE) {
+		std::vector< boost::shared_ptr<PubSubOwnerSubscription> > items;
+		for(size_t i = 0; i < lua_objlen(L, -1); ++i) {
+			lua_pushnumber(L, i + 1);
+			lua_gettable(L, -2);
+			if (!lua_isnil(L, -1)) {
+				if (boost::shared_ptr<PubSubOwnerSubscription> payload = boost::dynamic_pointer_cast<PubSubOwnerSubscription>(convertors->convertFromLuaUntyped(L, -1, "pubsub_owner_subscription"))) {
+					items.push_back(payload);
+				}
+			}
+			lua_pop(L, 1);
+		}
+
+		result->setSubscriptions(items);
+	}
+	return result;
+}
+
+void PubSubOwnerSubscriptionsConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubOwnerSubscriptions> payload) {
+	lua_createtable(L, 0, 0);
+	lua_pushstring(L, payload->getNode().c_str());
+	lua_setfield(L, -2, "node");
+	if (!payload->getSubscriptions().empty()) {
+		{
+			int i = 0;
+			foreach(boost::shared_ptr<PubSubOwnerSubscription> item, payload->getSubscriptions()) {
+				if (convertors->convertToLuaUntyped(L, item) > 0) {
+					lua_rawseti(L, -2, boost::numeric_cast<int>(i+1));
+					++i;
+				}
+			}
+		}
+	}
+}
diff --git a/Sluift/ElementConvertors/PubSubOwnerSubscriptionsConvertor.h b/Sluift/ElementConvertors/PubSubOwnerSubscriptionsConvertor.h
new file mode 100644
index 0000000..2e12c93
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubOwnerSubscriptionsConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubOwnerSubscriptions.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubOwnerSubscriptionsConvertor : public GenericLuaElementConvertor<PubSubOwnerSubscriptions> {
+		public:
+			PubSubOwnerSubscriptionsConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubOwnerSubscriptionsConvertor();
+
+			virtual boost::shared_ptr<PubSubOwnerSubscriptions> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubOwnerSubscriptions>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubPublishConvertor.cpp b/Sluift/ElementConvertors/PubSubPublishConvertor.cpp
new file mode 100644
index 0000000..880d9fc
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubPublishConvertor.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubPublishConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+
+#include <Sluift/LuaElementConvertors.h>
+#include <Swiften/Base/foreach.h>
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubPublishConvertor::PubSubPublishConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubPublish>("pubsub_publish"),
+		convertors(convertors) {
+}
+
+PubSubPublishConvertor::~PubSubPublishConvertor() {
+}
+
+boost::shared_ptr<PubSubPublish> PubSubPublishConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubPublish> result = boost::make_shared<PubSubPublish>();
+	lua_getfield(L, -1, "node");
+	if (lua_isstring(L, -1)) {
+		result->setNode(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "items");
+	if (lua_type(L, -1) == LUA_TTABLE) {
+		std::vector< boost::shared_ptr<PubSubItem> > items;
+		for(size_t i = 0; i < lua_objlen(L, -1); ++i) {
+			lua_pushnumber(L, i + 1);
+			lua_gettable(L, -2);
+			if (!lua_isnil(L, -1)) {
+				if (boost::shared_ptr<PubSubItem> payload = boost::dynamic_pointer_cast<PubSubItem>(convertors->convertFromLuaUntyped(L, -1, "pubsub_item"))) {
+					items.push_back(payload);
+				}
+			}
+			lua_pop(L, 1);
+		}
+
+		result->setItems(items);
+	}
+	lua_pop(L, 1);
+	return result;
+}
+
+void PubSubPublishConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubPublish> payload) {
+	lua_createtable(L, 0, 0);
+	lua_pushstring(L, payload->getNode().c_str());
+	lua_setfield(L, -2, "node");
+	if (!payload->getItems().empty()) {
+		lua_createtable(L, boost::numeric_cast<int>(payload->getItems().size()), 0);
+		{
+			int i = 0;
+			foreach(boost::shared_ptr<PubSubItem> item, payload->getItems()) {
+				if (convertors->convertToLuaUntyped(L, item) > 0) {
+					lua_rawseti(L, -2, boost::numeric_cast<int>(i+1));
+					++i;
+				}
+			}
+		}
+		lua_setfield(L, -2, "items");
+	}
+}
diff --git a/Sluift/ElementConvertors/PubSubPublishConvertor.h b/Sluift/ElementConvertors/PubSubPublishConvertor.h
new file mode 100644
index 0000000..4415566
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubPublishConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubPublish.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubPublishConvertor : public GenericLuaElementConvertor<PubSubPublish> {
+		public:
+			PubSubPublishConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubPublishConvertor();
+
+			virtual boost::shared_ptr<PubSubPublish> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubPublish>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubRetractConvertor.cpp b/Sluift/ElementConvertors/PubSubRetractConvertor.cpp
new file mode 100644
index 0000000..61ca3df
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubRetractConvertor.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubRetractConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+
+#include <Sluift/LuaElementConvertors.h>
+#include <Swiften/Base/foreach.h>
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubRetractConvertor::PubSubRetractConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubRetract>("pubsub_retract"),
+		convertors(convertors) {
+}
+
+PubSubRetractConvertor::~PubSubRetractConvertor() {
+}
+
+boost::shared_ptr<PubSubRetract> PubSubRetractConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubRetract> result = boost::make_shared<PubSubRetract>();
+	lua_getfield(L, -1, "node");
+	if (lua_isstring(L, -1)) {
+		result->setNode(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "items");
+	if (lua_type(L, -1) == LUA_TTABLE) {
+		std::vector< boost::shared_ptr<PubSubItem> > items;
+		for(size_t i = 0; i < lua_objlen(L, -1); ++i) {
+			lua_pushnumber(L, i + 1);
+			lua_gettable(L, -2);
+			if (!lua_isnil(L, -1)) {
+				if (boost::shared_ptr<PubSubItem> payload = boost::dynamic_pointer_cast<PubSubItem>(convertors->convertFromLuaUntyped(L, -1, "pubsub_item"))) {
+					items.push_back(payload);
+				}
+			}
+			lua_pop(L, 1);
+		}
+
+		result->setItems(items);
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "notify");
+	if (lua_isboolean(L, -1)) {
+		result->setNotify(lua_toboolean(L, -1));
+	}
+	lua_pop(L, 1);
+	return result;
+}
+
+void PubSubRetractConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubRetract> payload) {
+	lua_createtable(L, 0, 0);
+	lua_pushstring(L, payload->getNode().c_str());
+	lua_setfield(L, -2, "node");
+	if (!payload->getItems().empty()) {
+		lua_createtable(L, boost::numeric_cast<int>(payload->getItems().size()), 0);
+		{
+			int i = 0;
+			foreach(boost::shared_ptr<PubSubItem> item, payload->getItems()) {
+				if (convertors->convertToLuaUntyped(L, item) > 0) {
+					lua_rawseti(L, -2, boost::numeric_cast<int>(i+1));
+					++i;
+				}
+			}
+		}
+		lua_setfield(L, -2, "items");
+	}
+	lua_pushboolean(L, payload->isNotify());
+	lua_setfield(L, -2, "notify");
+}
diff --git a/Sluift/ElementConvertors/PubSubRetractConvertor.h b/Sluift/ElementConvertors/PubSubRetractConvertor.h
new file mode 100644
index 0000000..80d888b
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubRetractConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubRetract.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubRetractConvertor : public GenericLuaElementConvertor<PubSubRetract> {
+		public:
+			PubSubRetractConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubRetractConvertor();
+
+			virtual boost::shared_ptr<PubSubRetract> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubRetract>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubSubscribeConvertor.cpp b/Sluift/ElementConvertors/PubSubSubscribeConvertor.cpp
new file mode 100644
index 0000000..06d6447
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubSubscribeConvertor.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubSubscribeConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+
+#include <Sluift/LuaElementConvertors.h>
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubSubscribeConvertor::PubSubSubscribeConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubSubscribe>("pubsub_subscribe"),
+		convertors(convertors) {
+}
+
+PubSubSubscribeConvertor::~PubSubSubscribeConvertor() {
+}
+
+boost::shared_ptr<PubSubSubscribe> PubSubSubscribeConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubSubscribe> result = boost::make_shared<PubSubSubscribe>();
+	lua_getfield(L, -1, "node");
+	if (lua_isstring(L, -1)) {
+		result->setNode(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "jid");
+	if (lua_isstring(L, -1)) {
+		result->setJID(JID(std::string(lua_tostring(L, -1))));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "options");
+	if (!lua_isnil(L, -1)) {
+		if (boost::shared_ptr<PubSubOptions> payload = boost::dynamic_pointer_cast<PubSubOptions>(convertors->convertFromLuaUntyped(L, -1, "pubsub_options"))) {
+			result->setOptions(payload);
+		}
+	}
+	lua_pop(L, 1);
+	return result;
+}
+
+void PubSubSubscribeConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubSubscribe> payload) {
+	lua_createtable(L, 0, 0);
+	if (payload->getNode()) {
+		lua_pushstring(L, (*payload->getNode()).c_str());
+		lua_setfield(L, -2, "node");
+	}
+	lua_pushstring(L, payload->getJID().toString().c_str());
+	lua_setfield(L, -2, "jid");
+	if (convertors->convertToLuaUntyped(L, payload->getOptions()) > 0) {
+		lua_setfield(L, -2, "options");
+	}
+}
diff --git a/Sluift/ElementConvertors/PubSubSubscribeConvertor.h b/Sluift/ElementConvertors/PubSubSubscribeConvertor.h
new file mode 100644
index 0000000..2073c09
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubSubscribeConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubSubscribe.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubSubscribeConvertor : public GenericLuaElementConvertor<PubSubSubscribe> {
+		public:
+			PubSubSubscribeConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubSubscribeConvertor();
+
+			virtual boost::shared_ptr<PubSubSubscribe> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubSubscribe>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubSubscribeOptionsConvertor.cpp b/Sluift/ElementConvertors/PubSubSubscribeOptionsConvertor.cpp
new file mode 100644
index 0000000..e8053fb
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubSubscribeOptionsConvertor.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubSubscribeOptionsConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+
+
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubSubscribeOptionsConvertor::PubSubSubscribeOptionsConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubSubscribeOptions>("pubsub_subscribe_options"),
+		convertors(convertors) {
+}
+
+PubSubSubscribeOptionsConvertor::~PubSubSubscribeOptionsConvertor() {
+}
+
+boost::shared_ptr<PubSubSubscribeOptions> PubSubSubscribeOptionsConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubSubscribeOptions> result = boost::make_shared<PubSubSubscribeOptions>();
+	lua_getfield(L, -1, "required");
+	if (lua_isboolean(L, -1)) {
+		result->setRequired(lua_toboolean(L, -1));
+	}
+	lua_pop(L, 1);
+	return result;
+}
+
+void PubSubSubscribeOptionsConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubSubscribeOptions> payload) {
+	lua_createtable(L, 0, 0);
+	lua_pushboolean(L, payload->isRequired());
+	lua_setfield(L, -2, "required");
+}
diff --git a/Sluift/ElementConvertors/PubSubSubscribeOptionsConvertor.h b/Sluift/ElementConvertors/PubSubSubscribeOptionsConvertor.h
new file mode 100644
index 0000000..71e1baf
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubSubscribeOptionsConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubSubscribeOptions.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubSubscribeOptionsConvertor : public GenericLuaElementConvertor<PubSubSubscribeOptions> {
+		public:
+			PubSubSubscribeOptionsConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubSubscribeOptionsConvertor();
+
+			virtual boost::shared_ptr<PubSubSubscribeOptions> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubSubscribeOptions>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubSubscriptionConvertor.cpp b/Sluift/ElementConvertors/PubSubSubscriptionConvertor.cpp
new file mode 100644
index 0000000..9ec9fec
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubSubscriptionConvertor.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubSubscriptionConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+
+#include <Sluift/LuaElementConvertors.h>
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubSubscriptionConvertor::PubSubSubscriptionConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubSubscription>("pubsub_subscription"),
+		convertors(convertors) {
+}
+
+PubSubSubscriptionConvertor::~PubSubSubscriptionConvertor() {
+}
+
+boost::shared_ptr<PubSubSubscription> PubSubSubscriptionConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubSubscription> result = boost::make_shared<PubSubSubscription>();
+	lua_getfield(L, -1, "node");
+	if (lua_isstring(L, -1)) {
+		result->setNode(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "subscriptionid");
+	if (lua_isstring(L, -1)) {
+		result->setSubscriptionID(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "jid");
+	if (lua_isstring(L, -1)) {
+		result->setJID(JID(std::string(lua_tostring(L, -1))));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "options");
+	if (!lua_isnil(L, -1)) {
+		if (boost::shared_ptr<PubSubSubscribeOptions> payload = boost::dynamic_pointer_cast<PubSubSubscribeOptions>(convertors->convertFromLuaUntyped(L, -1, "pubsub_subscribe_options"))) {
+			result->setOptions(payload);
+		}
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "subscription");
+	lua_pop(L, 1);
+	return result;
+}
+
+void PubSubSubscriptionConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubSubscription> payload) {
+	lua_createtable(L, 0, 0);
+	if (payload->getNode()) {
+		lua_pushstring(L, (*payload->getNode()).c_str());
+		lua_setfield(L, -2, "node");
+	}
+	if (payload->getSubscriptionID()) {
+		lua_pushstring(L, (*payload->getSubscriptionID()).c_str());
+		lua_setfield(L, -2, "subscriptionid");
+	}
+	lua_pushstring(L, payload->getJID().toString().c_str());
+	lua_setfield(L, -2, "jid");
+	if (convertors->convertToLuaUntyped(L, payload->getOptions()) > 0) {
+		lua_setfield(L, -2, "options");
+	}
+	switch (payload->getSubscription()) {
+		case PubSubSubscription::None:
+			lua_pushstring(L, "none");
+			break;
+		case PubSubSubscription::Pending:
+			lua_pushstring(L, "pending");
+			break;
+		case PubSubSubscription::Subscribed:
+			lua_pushstring(L, "subscribed");
+			break;
+		case PubSubSubscription::Unconfigured:
+			lua_pushstring(L, "unconfigured");
+			break;
+	}
+	lua_setfield(L, -2, "subscription");
+}
diff --git a/Sluift/ElementConvertors/PubSubSubscriptionConvertor.h b/Sluift/ElementConvertors/PubSubSubscriptionConvertor.h
new file mode 100644
index 0000000..2da4930
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubSubscriptionConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubSubscription.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubSubscriptionConvertor : public GenericLuaElementConvertor<PubSubSubscription> {
+		public:
+			PubSubSubscriptionConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubSubscriptionConvertor();
+
+			virtual boost::shared_ptr<PubSubSubscription> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubSubscription>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubSubscriptionsConvertor.cpp b/Sluift/ElementConvertors/PubSubSubscriptionsConvertor.cpp
new file mode 100644
index 0000000..04f8da8
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubSubscriptionsConvertor.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubSubscriptionsConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+
+#include <Sluift/LuaElementConvertors.h>
+#include <Swiften/Base/foreach.h>
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubSubscriptionsConvertor::PubSubSubscriptionsConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubSubscriptions>("pubsub_subscriptions"),
+		convertors(convertors) {
+}
+
+PubSubSubscriptionsConvertor::~PubSubSubscriptionsConvertor() {
+}
+
+boost::shared_ptr<PubSubSubscriptions> PubSubSubscriptionsConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubSubscriptions> result = boost::make_shared<PubSubSubscriptions>();
+	lua_getfield(L, -1, "node");
+	if (lua_isstring(L, -1)) {
+		result->setNode(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	if (lua_type(L, -1) == LUA_TTABLE) {
+		std::vector< boost::shared_ptr<PubSubSubscription> > items;
+		for(size_t i = 0; i < lua_objlen(L, -1); ++i) {
+			lua_pushnumber(L, i + 1);
+			lua_gettable(L, -2);
+			if (!lua_isnil(L, -1)) {
+				if (boost::shared_ptr<PubSubSubscription> payload = boost::dynamic_pointer_cast<PubSubSubscription>(convertors->convertFromLuaUntyped(L, -1, "pubsub_subscription"))) {
+					items.push_back(payload);
+				}
+			}
+			lua_pop(L, 1);
+		}
+
+		result->setSubscriptions(items);
+	}
+	return result;
+}
+
+void PubSubSubscriptionsConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubSubscriptions> payload) {
+	lua_createtable(L, 0, 0);
+	if (payload->getNode()) {
+		lua_pushstring(L, (*payload->getNode()).c_str());
+		lua_setfield(L, -2, "node");
+	}
+	if (!payload->getSubscriptions().empty()) {
+		{
+			int i = 0;
+			foreach(boost::shared_ptr<PubSubSubscription> item, payload->getSubscriptions()) {
+				if (convertors->convertToLuaUntyped(L, item) > 0) {
+					lua_rawseti(L, -2, boost::numeric_cast<int>(i+1));
+					++i;
+				}
+			}
+		}
+	}
+}
diff --git a/Sluift/ElementConvertors/PubSubSubscriptionsConvertor.h b/Sluift/ElementConvertors/PubSubSubscriptionsConvertor.h
new file mode 100644
index 0000000..7f18f64
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubSubscriptionsConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubSubscriptions.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubSubscriptionsConvertor : public GenericLuaElementConvertor<PubSubSubscriptions> {
+		public:
+			PubSubSubscriptionsConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubSubscriptionsConvertor();
+
+			virtual boost::shared_ptr<PubSubSubscriptions> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubSubscriptions>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/PubSubUnsubscribeConvertor.cpp b/Sluift/ElementConvertors/PubSubUnsubscribeConvertor.cpp
new file mode 100644
index 0000000..323cb29
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubUnsubscribeConvertor.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/PubSubUnsubscribeConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+
+
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+PubSubUnsubscribeConvertor::PubSubUnsubscribeConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<PubSubUnsubscribe>("pubsub_unsubscribe"),
+		convertors(convertors) {
+}
+
+PubSubUnsubscribeConvertor::~PubSubUnsubscribeConvertor() {
+}
+
+boost::shared_ptr<PubSubUnsubscribe> PubSubUnsubscribeConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<PubSubUnsubscribe> result = boost::make_shared<PubSubUnsubscribe>();
+	lua_getfield(L, -1, "node");
+	if (lua_isstring(L, -1)) {
+		result->setNode(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "jid");
+	if (lua_isstring(L, -1)) {
+		result->setJID(JID(std::string(lua_tostring(L, -1))));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "subscriptionid");
+	if (lua_isstring(L, -1)) {
+		result->setSubscriptionID(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	return result;
+}
+
+void PubSubUnsubscribeConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubUnsubscribe> payload) {
+	lua_createtable(L, 0, 0);
+	if (payload->getNode()) {
+		lua_pushstring(L, (*payload->getNode()).c_str());
+		lua_setfield(L, -2, "node");
+	}
+	lua_pushstring(L, payload->getJID().toString().c_str());
+	lua_setfield(L, -2, "jid");
+	if (payload->getSubscriptionID()) {
+		lua_pushstring(L, (*payload->getSubscriptionID()).c_str());
+		lua_setfield(L, -2, "subscriptionid");
+	}
+}
diff --git a/Sluift/ElementConvertors/PubSubUnsubscribeConvertor.h b/Sluift/ElementConvertors/PubSubUnsubscribeConvertor.h
new file mode 100644
index 0000000..16d279f
--- /dev/null
+++ b/Sluift/ElementConvertors/PubSubUnsubscribeConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/PubSubUnsubscribe.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class PubSubUnsubscribeConvertor : public GenericLuaElementConvertor<PubSubUnsubscribe> {
+		public:
+			PubSubUnsubscribeConvertor(LuaElementConvertors* convertors);
+			virtual ~PubSubUnsubscribeConvertor();
+
+			virtual boost::shared_ptr<PubSubUnsubscribe> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubUnsubscribe>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/RawXMLElementConvertor.cpp b/Sluift/ElementConvertors/RawXMLElementConvertor.cpp
new file mode 100644
index 0000000..35a53ca
--- /dev/null
+++ b/Sluift/ElementConvertors/RawXMLElementConvertor.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/RawXMLElementConvertor.h>
+
+#include <iostream>
+#include <boost/smart_ptr/make_shared.hpp>
+#include <lua.hpp>
+
+#include <Swiften/Elements/RawXMLPayload.h>
+#include <Swiften/Serializer/PayloadSerializer.h>
+#include <Sluift/Lua/Check.h>
+
+using namespace Swift;
+
+RawXMLElementConvertor::RawXMLElementConvertor() {
+}
+
+RawXMLElementConvertor::~RawXMLElementConvertor() {
+}
+
+boost::shared_ptr<Payload> RawXMLElementConvertor::convertFromLua(lua_State* L, int index, const std::string& type) {
+	if (type == "xml") {
+		return boost::make_shared<RawXMLPayload>(std::string(Lua::checkString(L, index)));
+	}
+	return boost::shared_ptr<Payload>();
+}
+
+boost::optional<std::string> RawXMLElementConvertor::convertToLua(lua_State* L, boost::shared_ptr<Payload> payload) {
+	PayloadSerializer* serializer = serializers.getPayloadSerializer(payload);
+	assert(serializer);
+	lua_pushstring(L, serializer->serialize(payload).c_str());
+	return std::string("xml");
+}
diff --git a/Sluift/ElementConvertors/RawXMLElementConvertor.h b/Sluift/ElementConvertors/RawXMLElementConvertor.h
new file mode 100644
index 0000000..6087ba0
--- /dev/null
+++ b/Sluift/ElementConvertors/RawXMLElementConvertor.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/LuaElementConvertor.h>
+#include <Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h>
+
+namespace Swift {
+	class RawXMLElementConvertor : public LuaElementConvertor {
+		public:
+			RawXMLElementConvertor();
+			virtual ~RawXMLElementConvertor();
+
+			virtual boost::shared_ptr<Payload> convertFromLua(lua_State*, int index, const std::string& type) SWIFTEN_OVERRIDE;
+			virtual boost::optional<std::string> convertToLua(lua_State*, boost::shared_ptr<Payload>) SWIFTEN_OVERRIDE;
+
+		private:
+			FullPayloadSerializerCollection serializers;
+	};
+}
diff --git a/Sluift/ElementConvertors/SConscript b/Sluift/ElementConvertors/SConscript
new file mode 100644
index 0000000..e98f7c4
--- /dev/null
+++ b/Sluift/ElementConvertors/SConscript
@@ -0,0 +1,42 @@
+
+Import('env')
+
+convertors = [
+	env.File("PubSubRetractConvertor.cpp"),
+	env.File("PubSubAffiliationsConvertor.cpp"),
+	env.File("PubSubPublishConvertor.cpp"),
+	env.File("PubSubItemsConvertor.cpp"),
+	env.File("PubSubOwnerRedirectConvertor.cpp"),
+	env.File("PubSubEventRedirectConvertor.cpp"),
+	env.File("PubSubConfigureConvertor.cpp"),
+	env.File("PubSubEventDisassociateConvertor.cpp"),
+	env.File("PubSubOwnerAffiliationsConvertor.cpp"),
+	env.File("PubSubOwnerConfigureConvertor.cpp"),
+	env.File("UserLocationConvertor.cpp"),
+	env.File("PubSubSubscribeOptionsConvertor.cpp"),
+	env.File("PubSubOwnerSubscriptionsConvertor.cpp"),
+	env.File("PubSubDefaultConvertor.cpp"),
+	env.File("PubSubEventCollectionConvertor.cpp"),
+	env.File("PubSubEventSubscriptionConvertor.cpp"),
+	env.File("PubSubEventRetractConvertor.cpp"),
+	env.File("PubSubItemConvertor.cpp"),
+	env.File("PubSubUnsubscribeConvertor.cpp"),
+	env.File("PubSubEventDeleteConvertor.cpp"),
+	env.File("PubSubCreateConvertor.cpp"),
+	env.File("PubSubOwnerPurgeConvertor.cpp"),
+	env.File("PubSubEventItemsConvertor.cpp"),
+	env.File("PubSubOptionsConvertor.cpp"),
+	env.File("PubSubEventItemConvertor.cpp"),
+	env.File("PubSubOwnerSubscriptionConvertor.cpp"),
+	env.File("PubSubOwnerAffiliationConvertor.cpp"),
+	env.File("PubSubEventPurgeConvertor.cpp"),
+	env.File("PubSubAffiliationConvertor.cpp"),
+	env.File("PubSubSubscribeConvertor.cpp"),
+	env.File("PubSubOwnerDeleteConvertor.cpp"),
+	env.File("PubSubOwnerDefaultConvertor.cpp"),
+	env.File("PubSubSubscriptionsConvertor.cpp"),
+	env.File("PubSubEventAssociateConvertor.cpp"),
+	env.File("PubSubSubscriptionConvertor.cpp"),
+	env.File("PubSubEventConfigurationConvertor.cpp")
+]
+Return('convertors')
diff --git a/Sluift/ElementConvertors/SoftwareVersionConvertor.cpp b/Sluift/ElementConvertors/SoftwareVersionConvertor.cpp
new file mode 100644
index 0000000..5799614
--- /dev/null
+++ b/Sluift/ElementConvertors/SoftwareVersionConvertor.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/SoftwareVersionConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+#include <Sluift/Lua/Check.h>
+
+using namespace Swift;
+
+SoftwareVersionConvertor::SoftwareVersionConvertor() : GenericLuaElementConvertor<SoftwareVersion>("software_version") {
+}
+
+SoftwareVersionConvertor::~SoftwareVersionConvertor() {
+}
+
+boost::shared_ptr<SoftwareVersion> SoftwareVersionConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<SoftwareVersion> result = boost::make_shared<SoftwareVersion>();
+	lua_getfield(L, -1, "name");
+	if (!lua_isnil(L, -1)) {
+		result->setName(std::string(Lua::checkString(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "version");
+	if (!lua_isnil(L, -1)) {
+		result->setVersion(std::string(Lua::checkString(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "os");
+	if (!lua_isnil(L, -1)) {
+		result->setOS(std::string(Lua::checkString(L, -1)));
+	}
+	lua_pop(L, 1);
+	return result;
+}
+
+void SoftwareVersionConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<SoftwareVersion> payload) {
+	lua_createtable(L, 0, 0);
+	lua_pushstring(L, payload->getName().c_str());
+	lua_setfield(L, -2, "name");
+	lua_pushstring(L, payload->getVersion().c_str());
+	lua_setfield(L, -2, "version");
+	lua_pushstring(L, payload->getOS().c_str());
+	lua_setfield(L, -2, "os");
+}
diff --git a/Sluift/ElementConvertors/SoftwareVersionConvertor.h b/Sluift/ElementConvertors/SoftwareVersionConvertor.h
new file mode 100644
index 0000000..5fa3cc3
--- /dev/null
+++ b/Sluift/ElementConvertors/SoftwareVersionConvertor.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/SoftwareVersion.h>
+
+namespace Swift {
+	class SoftwareVersionConvertor : public GenericLuaElementConvertor<SoftwareVersion> {
+		public:
+			SoftwareVersionConvertor();
+			virtual ~SoftwareVersionConvertor();
+
+			virtual boost::shared_ptr<SoftwareVersion> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<SoftwareVersion>) SWIFTEN_OVERRIDE;
+	};
+}
diff --git a/Sluift/ElementConvertors/UserLocationConvertor.cpp b/Sluift/ElementConvertors/UserLocationConvertor.cpp
new file mode 100644
index 0000000..97cb288
--- /dev/null
+++ b/Sluift/ElementConvertors/UserLocationConvertor.cpp
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/UserLocationConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+
+#include <Swiften/Base/DateTime.h>
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+UserLocationConvertor::UserLocationConvertor(LuaElementConvertors* convertors) : 
+		GenericLuaElementConvertor<UserLocation>("user_location"),
+		convertors(convertors) {
+}
+
+UserLocationConvertor::~UserLocationConvertor() {
+}
+
+boost::shared_ptr<UserLocation> UserLocationConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<UserLocation> result = boost::make_shared<UserLocation>();
+	lua_getfield(L, -1, "area");
+	if (lua_isstring(L, -1)) {
+		result->setArea(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "altitude");
+	if (lua_isnumber(L, -1)) {
+		result->setAltitude(boost::numeric_cast<float>(lua_tonumber(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "locality");
+	if (lua_isstring(L, -1)) {
+		result->setLocality(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "latitude");
+	if (lua_isnumber(L, -1)) {
+		result->setLatitude(boost::numeric_cast<float>(lua_tonumber(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "accuracy");
+	if (lua_isnumber(L, -1)) {
+		result->setAccuracy(boost::numeric_cast<float>(lua_tonumber(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "description");
+	if (lua_isstring(L, -1)) {
+		result->setDescription(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "country_code");
+	if (lua_isstring(L, -1)) {
+		result->setCountryCode(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "timestamp");
+	if (lua_isstring(L, -1)) {
+		result->setTimestamp(stringToDateTime(std::string(lua_tostring(L, -1))));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "floor");
+	if (lua_isstring(L, -1)) {
+		result->setFloor(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "building");
+	if (lua_isstring(L, -1)) {
+		result->setBuilding(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "room");
+	if (lua_isstring(L, -1)) {
+		result->setRoom(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "country");
+	if (lua_isstring(L, -1)) {
+		result->setCountry(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "region");
+	if (lua_isstring(L, -1)) {
+		result->setRegion(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "uri");
+	if (lua_isstring(L, -1)) {
+		result->setURI(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "longitude");
+	if (lua_isnumber(L, -1)) {
+		result->setLongitude(boost::numeric_cast<float>(lua_tonumber(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "error");
+	if (lua_isnumber(L, -1)) {
+		result->setError(boost::numeric_cast<float>(lua_tonumber(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "postal_code");
+	if (lua_isstring(L, -1)) {
+		result->setPostalCode(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "bearing");
+	if (lua_isnumber(L, -1)) {
+		result->setBearing(boost::numeric_cast<float>(lua_tonumber(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "text");
+	if (lua_isstring(L, -1)) {
+		result->setText(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "datum");
+	if (lua_isstring(L, -1)) {
+		result->setDatum(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "street");
+	if (lua_isstring(L, -1)) {
+		result->setStreet(std::string(lua_tostring(L, -1)));
+	}
+	lua_pop(L, 1);
+	lua_getfield(L, -1, "speed");
+	if (lua_isnumber(L, -1)) {
+		result->setSpeed(boost::numeric_cast<float>(lua_tonumber(L, -1)));
+	}
+	lua_pop(L, 1);
+	return result;
+}
+
+void UserLocationConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<UserLocation> payload) {
+	lua_createtable(L, 0, 0);
+	if (payload->getArea()) {
+		lua_pushstring(L, (*payload->getArea()).c_str());
+		lua_setfield(L, -2, "area");
+	}
+	if (payload->getAltitude()) {
+		lua_pushnumber(L, (*payload->getAltitude()));
+		lua_setfield(L, -2, "altitude");
+	}
+	if (payload->getLocality()) {
+		lua_pushstring(L, (*payload->getLocality()).c_str());
+		lua_setfield(L, -2, "locality");
+	}
+	if (payload->getLatitude()) {
+		lua_pushnumber(L, (*payload->getLatitude()));
+		lua_setfield(L, -2, "latitude");
+	}
+	if (payload->getAccuracy()) {
+		lua_pushnumber(L, (*payload->getAccuracy()));
+		lua_setfield(L, -2, "accuracy");
+	}
+	if (payload->getDescription()) {
+		lua_pushstring(L, (*payload->getDescription()).c_str());
+		lua_setfield(L, -2, "description");
+	}
+	if (payload->getCountryCode()) {
+		lua_pushstring(L, (*payload->getCountryCode()).c_str());
+		lua_setfield(L, -2, "country_code");
+	}
+	if (payload->getTimestamp()) {
+	lua_pushstring(L, dateTimeToString((*payload->getTimestamp())).c_str());
+		lua_setfield(L, -2, "timestamp");
+	}
+	if (payload->getFloor()) {
+		lua_pushstring(L, (*payload->getFloor()).c_str());
+		lua_setfield(L, -2, "floor");
+	}
+	if (payload->getBuilding()) {
+		lua_pushstring(L, (*payload->getBuilding()).c_str());
+		lua_setfield(L, -2, "building");
+	}
+	if (payload->getRoom()) {
+		lua_pushstring(L, (*payload->getRoom()).c_str());
+		lua_setfield(L, -2, "room");
+	}
+	if (payload->getCountry()) {
+		lua_pushstring(L, (*payload->getCountry()).c_str());
+		lua_setfield(L, -2, "country");
+	}
+	if (payload->getRegion()) {
+		lua_pushstring(L, (*payload->getRegion()).c_str());
+		lua_setfield(L, -2, "region");
+	}
+	if (payload->getURI()) {
+		lua_pushstring(L, (*payload->getURI()).c_str());
+		lua_setfield(L, -2, "uri");
+	}
+	if (payload->getLongitude()) {
+		lua_pushnumber(L, (*payload->getLongitude()));
+		lua_setfield(L, -2, "longitude");
+	}
+	if (payload->getError()) {
+		lua_pushnumber(L, (*payload->getError()));
+		lua_setfield(L, -2, "error");
+	}
+	if (payload->getPostalCode()) {
+		lua_pushstring(L, (*payload->getPostalCode()).c_str());
+		lua_setfield(L, -2, "postal_code");
+	}
+	if (payload->getBearing()) {
+		lua_pushnumber(L, (*payload->getBearing()));
+		lua_setfield(L, -2, "bearing");
+	}
+	if (payload->getText()) {
+		lua_pushstring(L, (*payload->getText()).c_str());
+		lua_setfield(L, -2, "text");
+	}
+	if (payload->getDatum()) {
+		lua_pushstring(L, (*payload->getDatum()).c_str());
+		lua_setfield(L, -2, "datum");
+	}
+	if (payload->getStreet()) {
+		lua_pushstring(L, (*payload->getStreet()).c_str());
+		lua_setfield(L, -2, "street");
+	}
+	if (payload->getSpeed()) {
+		lua_pushnumber(L, (*payload->getSpeed()));
+		lua_setfield(L, -2, "speed");
+	}
+}
diff --git a/Sluift/ElementConvertors/UserLocationConvertor.h b/Sluift/ElementConvertors/UserLocationConvertor.h
new file mode 100644
index 0000000..a5eb153
--- /dev/null
+++ b/Sluift/ElementConvertors/UserLocationConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/UserLocation.h>
+
+namespace Swift {
+	class LuaElementConvertors;
+
+	class UserLocationConvertor : public GenericLuaElementConvertor<UserLocation> {
+		public:
+			UserLocationConvertor(LuaElementConvertors* convertors);
+			virtual ~UserLocationConvertor();
+
+			virtual boost::shared_ptr<UserLocation> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<UserLocation>) SWIFTEN_OVERRIDE;
+
+		private:
+			LuaElementConvertors* convertors;
+	};
+}
diff --git a/Sluift/ElementConvertors/VCardConvertor.cpp b/Sluift/ElementConvertors/VCardConvertor.cpp
new file mode 100644
index 0000000..a1c57be
--- /dev/null
+++ b/Sluift/ElementConvertors/VCardConvertor.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/VCardConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+#include <Sluift/Lua/LuaUtils.h>
+#include <Swiften/Base/ByteArray.h>
+
+using namespace Swift;
+
+VCardConvertor::VCardConvertor() : GenericLuaElementConvertor<VCard>("vcard") {
+}
+
+VCardConvertor::~VCardConvertor() {
+}
+
+boost::shared_ptr<VCard> VCardConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<VCard> result = boost::make_shared<VCard>();
+	lua_getfield(L, -1, "photo");
+	if (lua_isstring(L, -1)) {
+		size_t len;
+		const char* data = lua_tolstring(L, -1, &len);
+		result->setPhoto(createByteArray(data, len));
+	}
+	lua_pop(L, 1);
+
+	// TODO
+
+	return result;
+}
+
+void VCardConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<VCard> payload) {
+	lua_newtable(L);
+	if (!payload->getPhoto().empty()) {
+		lua_pushlstring(L, 
+				reinterpret_cast<const char*>(vecptr(payload->getPhoto())), 
+				payload->getPhoto().size());
+		lua_setfield(L, -2, "photo");
+	}
+}
diff --git a/Sluift/ElementConvertors/VCardConvertor.h b/Sluift/ElementConvertors/VCardConvertor.h
new file mode 100644
index 0000000..1cf4e9f
--- /dev/null
+++ b/Sluift/ElementConvertors/VCardConvertor.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/VCard.h>
+
+namespace Swift {
+	class VCardConvertor : public GenericLuaElementConvertor<VCard> {
+		public:
+			VCardConvertor();
+			virtual ~VCardConvertor();
+
+			virtual boost::shared_ptr<VCard> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<VCard>) SWIFTEN_OVERRIDE;
+	};
+}
diff --git a/Sluift/ElementConvertors/VCardUpdateConvertor.cpp b/Sluift/ElementConvertors/VCardUpdateConvertor.cpp
new file mode 100644
index 0000000..0010ca5
--- /dev/null
+++ b/Sluift/ElementConvertors/VCardUpdateConvertor.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/VCardUpdateConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+#include <Sluift/Lua/LuaUtils.h>
+
+using namespace Swift;
+
+VCardUpdateConvertor::VCardUpdateConvertor() : GenericLuaElementConvertor<VCardUpdate>("vcard_update") {
+}
+
+VCardUpdateConvertor::~VCardUpdateConvertor() {
+}
+
+boost::shared_ptr<VCardUpdate> VCardUpdateConvertor::doConvertFromLua(lua_State* L) {
+	boost::shared_ptr<VCardUpdate> result = boost::make_shared<VCardUpdate>();
+	if (boost::optional<std::string> value = Lua::getStringField(L, -1, "photo_hash")) {
+		result->setPhotoHash(*value);
+	}
+	return result;
+}
+
+void VCardUpdateConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<VCardUpdate> payload) {
+	lua_newtable(L);
+	if (!payload->getPhotoHash().empty()) {
+		lua_pushstring(L, payload->getPhotoHash().c_str());
+		lua_setfield(L, -2, "photo_hash");
+	}
+}
diff --git a/Sluift/ElementConvertors/VCardUpdateConvertor.h b/Sluift/ElementConvertors/VCardUpdateConvertor.h
new file mode 100644
index 0000000..e9bcd0f
--- /dev/null
+++ b/Sluift/ElementConvertors/VCardUpdateConvertor.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/VCardUpdate.h>
+
+namespace Swift {
+	class VCardUpdateConvertor : public GenericLuaElementConvertor<VCardUpdate> {
+		public:
+			VCardUpdateConvertor();
+			virtual ~VCardUpdateConvertor();
+
+			virtual boost::shared_ptr<VCardUpdate> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<VCardUpdate>) SWIFTEN_OVERRIDE;
+	};
+}
diff --git a/Sluift/Examples/CollectVersions.lua b/Sluift/Examples/CollectVersions.lua
index c93c8c8..38bf6ac 100644
--- a/Sluift/Examples/CollectVersions.lua
+++ b/Sluift/Examples/CollectVersions.lua
@@ -1,22 +1,22 @@
---
--- Copyright (c) 2010 Remko Tronçon
--- Licensed under the GNU General Public License v3.
--- See Documentation/Licenses/GPLv3.txt for more information.
---
+--[[
+	
+	Copyright (c) 2010-2013 Remko Tronçon
+	Licensed under the GNU General Public License v3.
+	See Documentation/Licenses/GPLv3.txt for more information.
 
--- This script logs into an XMPP server, and collects statistics about
--- the server software of all contacts in your roster
+	This script logs into an XMPP server, and collects statistics about
+	the server software of all contacts in your roster
 
-require "sluift"
+--]]
 
-c = sluift.new_client(os.getenv("SLUIFT_JID"), os.getenv("SLUIFT_PASS"))
-c:connect()
+require 'sluift'
 
-versions = {}
-for jid, _ in pairs(c:get_contacts()) do
-	v = c:get_version(sluift.jid_domain(jid))
-	if v then versions[v["name"]] = (versions[v["name"]] or 0) + 1 end
-end
-for name, count in pairs(versions) do print(name .. ": " .. count) end
-
-c:disconnect()
+c = sluift.new_client(os.getenv('SLUIFT_JID'), os.getenv('SLUIFT_PASS'))
+c:connect(function () 
+	versions = {}
+	for jid in pairs(c:get_contacts()) do
+		local v = c:get_software_version {to = sluift.jid.domain(jid), timeout = 3000} or {name = 'Unknown'}
+		versions[v['name']] = (versions[v['name']] or 0) + 1
+	end
+	for name, count in pairs(versions) do print(name .. ': ' .. count) end
+end)
diff --git a/Sluift/Examples/ContactsMap.lua b/Sluift/Examples/ContactsMap.lua
new file mode 100644
index 0000000..d248dc7
--- /dev/null
+++ b/Sluift/Examples/ContactsMap.lua
@@ -0,0 +1,120 @@
+--[[
+	Copyright (c) 2013 Remko Tronçon
+	Licensed under the GNU General Public License v3.
+	See Documentation/Licenses/GPLv3.txt for more information.
+--]]
+
+--[[
+
+	Contacts map
+
+	Creates an HTML file of a map with all your contacts on it.
+
+	The following environment variables are used:
+	- SLUIFT_JID, SWIFT_PASS: JID and password to log in with
+
+--]]
+
+require "sluift"
+
+output_dir = arg[1]
+if not output_dir then
+	error("Please specify the directory to write the map to")
+end
+
+-- Collect all data
+geolocs = {}
+avatars = {}
+c = sluift.new_client(os.getenv("SLUIFT_JID"), os.getenv("SLUIFT_PASS"))
+c:connect(function () 
+	-- Indicate we're interested in getting user location information, and send initial presence
+	c:set_caps_node("http://swift.im/ContactsMap")
+	c:set_disco_info({identities = {{name = 'ContactsMap'}}, features = {
+		sluift.disco.features.DISCO_INFO,
+		sluift.disco.features.USER_LOCATION .. '+notify',
+	}})
+	c:send_presence()
+
+	-- Collect geoloc info
+	for event in c:pubsub_events {timeout = 10000} do
+		local from = sluift.jid.to_bare(event.from)
+		if event._type == 'pubsub_event_items' and event.item then
+			if event.node == sluift.disco.features.USER_LOCATION then
+				local lat, lon = event.item.latitude, event.item.longitude
+				if lat and lon then geolocs[from] = {lat = lat, lon = lon} end
+			end
+		end
+	end
+
+	-- Download the necessary avatars
+	for contact in pairs(geolocs) do
+		local vcard = c:get_vcard {to = contact}
+		if vcard and vcard.photo then
+			local avatar_hash = sluift.hexify(sluift.sha1(vcard.photo))
+			local file = io.open(output_dir.."/" .. avatar_hash .. ".png", "wb")
+			file:write(vcard.photo)
+			file:close()
+			avatars[contact] = avatar_hash
+		end
+	end
+end)
+
+-- Generate html
+min_lat, max_lat = 90, -90
+min_lon, max_lon = 180, -180
+contacts_html = {}
+for contact, geoloc in pairs(geolocs) do
+	if geoloc.lat < min_lat then min_lat = geoloc.lat end
+	if geoloc.lon < min_lon then min_lon = geoloc.lon end
+	if geoloc.lat > max_lat then max_lat = geoloc.lat end
+	if geoloc.lon > max_lon then max_lon = geoloc.lon end
+	local image = 'null'
+	if avatars[contact] then
+		image = "'" .. avatars[contact] .. ".png'"
+	end
+	contacts_html[#contacts_html+1] = "['" .. contact .. "'," .. geoloc.lat .. "," .. geoloc.lon .. "," .. image .. "]"
+end
+center_html = ((min_lat + max_lat) / 2) .. ',' .. ((min_lon + max_lon) / 2)
+
+map_html = [[
+<html>
+	<head>
+		<title>Contacts Map</title>
+		<script src="http://maps.google.com/maps/api/js?sensor=false" type="text/javascript"></script>
+	</head>
+	<body>
+		<div id="map" style="height: 100%; width: 100%;"/>
+		<script>
+			var map = new google.maps.Map(document.getElementById('map'), {
+				zoom: 2,
+				center: new google.maps.LatLng(%(CENTER)),
+				mapTypeId: google.maps.MapTypeId.ROADMAP
+			});
+			var infowindow = new google.maps.InfoWindow();
+			var contacts = [%(CONTACTS)];
+			for (var i = 0; i < contacts.length; i++) { 
+				var icon = null;
+				if (contacts[i][3]) {
+					icon = { url: contacts[i][3], scaledSize: { width: 30, height: 30} };
+				}
+				var marker = new google.maps.Marker({
+					position: new google.maps.LatLng(contacts[i][1], contacts[i][2]),
+					map: map,
+					icon: icon,
+				});
+				google.maps.event.addListener(marker, 'click', (function(marker, i) {
+					return function() {
+						infowindow.setContent(contacts[i][0]);
+						infowindow.open(map, marker);
+					}
+				})(marker, i));
+			}
+		</script>
+	</body>
+</html>
+]]
+local file = io.open(output_dir .. "/index.html", "w")
+file:write(map_html:
+	gsub('%%%(CONTACTS%)', table.concat(contacts_html, ",")):
+	gsub('%%%(CENTER%)', center_html))
+file:close()
diff --git a/Sluift/Examples/EchoBot.lua b/Sluift/Examples/EchoBot.lua
index 09da63b..fc495c4 100644
--- a/Sluift/Examples/EchoBot.lua
+++ b/Sluift/Examples/EchoBot.lua
@@ -1,27 +1,31 @@
---
--- Copyright (c) 2010 Remko Tronçon
--- Licensed under the GNU General Public License v3.
--- See Documentation/Licenses/GPLv3.txt for more information.
---
+--[[
+	Copyright (c) 2010-2013 Remko Tronçon
+	Licensed under the GNU General Public License v3.
+	See Documentation/Licenses/GPLv3.txt for more information.
+--]]
 
---
--- An XMPP Echoing Bot
---
--- This script logs into an XMPP server, sends initial presence,
--- and then waits for incoming messages, and echoes them back.
--- 
--- The following environment variables are used:
--- * SLUIFT_JID, SWIFT_PASS: JID and password to log in with
--- * SLUIFT_DEBUG: Sets whether debugging should be turned on
--- 
+--[[
+	
+	An XMPP Echoing Bot
+
+	This script logs into an XMPP server, sends initial presence,
+	and then waits for incoming messages, and echoes them back.
+	
+	The following environment variables are used:
+	* SLUIFT_JID, SWIFT_PASS: JID and password to log in with
+	* SLUIFT_DEBUG: Sets whether debugging should be turned on
+
+--]]
 
 require "sluift"
 
 sluift.debug = os.getenv("SLUIFT_DEBUG") or false
 
 c = sluift.new_client(os.getenv("SLUIFT_JID"), os.getenv("SLUIFT_PASS"))
-c:connect()
-c:send_presence("Send me a message")
-c:for_event(function(e) 
-		if e["type"] == "message" then c:send_message(e["from"], e["body"]) end 
-	end)
+c:connect(function () 
+	c:set_version{name = "EchoBot", version = "0.1"}
+	c:send_presence("Send me a message")
+	for message in c:messages() do
+		c:send_message{to = message["from"], body = message["body"]}
+	end
+end)
diff --git a/Sluift/Examples/Login.lua b/Sluift/Examples/Login.lua
index 1733bb9..c43b72a 100644
--- a/Sluift/Examples/Login.lua
+++ b/Sluift/Examples/Login.lua
@@ -1,16 +1,20 @@
---
--- Copyright (c) 2010 Remko Tronçon
--- Licensed under the GNU General Public License v3.
--- See Documentation/Licenses/GPLv3.txt for more information.
---
+--[[
+	Copyright (c) 2010-2013 Remko Tronçon
+	Licensed under the GNU General Public License v3.
+	See Documentation/Licenses/GPLv3.txt for more information.
+--]]
 
--- This script logs into an XMPP server, and sends initial presence
--- Useful as initialization script for an interactive session ('-i'),
--- or as a starting point for scripts.
--- 
--- The following environment variables are used:
--- * SLUIFT_JID, SWIFT_PASS: JID and password to log in with
--- * SLUIFT_DEBUG: Sets whether debugging should be turned on
+--[[
+
+	This script logs into an XMPP server, and sends initial presence
+	Useful as initialization script for an interactive session ('-i'),
+	or as a starting point for scripts.
+
+	The following environment variables are used:
+	* SLUIFT_JID, SWIFT_PASS: JID and password to log in with
+	* SLUIFT_DEBUG: Sets whether debugging should be turned on
+
+--]]
 
 require "sluift"
 sluift.debug = os.getenv("SLUIFT_DEBUG") or false
@@ -18,6 +22,8 @@ sluift.debug = os.getenv("SLUIFT_DEBUG") or false
 print("Connecting " .. os.getenv("SLUIFT_JID") .. " ...")
 c = sluift.new_client(os.getenv("SLUIFT_JID"), os.getenv("SLUIFT_PASS"))
 c:set_options({compress = false, tls = false})
-c:connect():send_presence("")
+c:connect()
+c:send_presence("")
 
 print("Connected ...")
+print("Use the 'c' variable to communicate.")
diff --git a/Sluift/Examples/PEPListener.lua b/Sluift/Examples/PEPListener.lua
new file mode 100644
index 0000000..f196f84
--- /dev/null
+++ b/Sluift/Examples/PEPListener.lua
@@ -0,0 +1,46 @@
+--[[
+	Copyright (c) 2010-2013 Remko Tronçon
+	Licensed under the GNU General Public License v3.
+	See Documentation/Licenses/GPLv3.txt for more information.
+--]]
+
+--[[
+
+	PEP Listener
+
+	Listens to a series of PEP events of all contacts.
+
+	The following environment variables are used:
+	- SLUIFT_JID, SWIFT_PASS: JID and password to log in with
+	- SLUIFT_DEBUG: Sets whether debugging should be turned on
+
+--]]
+
+require "sluift"
+
+sluift.debug = os.getenv("SLUIFT_DEBUG") or false
+
+pep_protocols = {
+	[sluift.disco.features.USER_LOCATION] = true,
+	[sluift.disco.features.USER_TUNE] = true,
+	[sluift.disco.features.USER_ACTIVITY] = true,
+	[sluift.disco.features.USER_AVATAR_METADATA] = true,
+	[sluift.disco.features.USER_PROFILE] = true,
+}
+
+client = sluift.new_client(os.getenv("SLUIFT_JID"), os.getenv("SLUIFT_PASS"))
+client:connect(function (c) 
+	features = {sluift.disco.features.DISCO_INFO}
+	for protocol in pairs(pep_protocols) do
+		features[#features+1] = protocol .. '+notify'
+	end
+
+	c:set_caps_node("http://swift.im/PEPListener")
+	c:set_disco_info({identities = {{name = 'PEPListener'}}, features = features})
+	c:send_presence()
+	for event in c:pubsub_events() do
+		if event._type == 'pubsub_event_items' and pep_protocols[event.node] then
+			print("<" .. event.from .. "> " .. tostring(event.item))
+		end
+	end
+end)
diff --git a/Sluift/Examples/RemoveUnreachableContacts.lua b/Sluift/Examples/RemoveUnreachableContacts.lua
index 90122df..a202e62 100644
--- a/Sluift/Examples/RemoveUnreachableContacts.lua
+++ b/Sluift/Examples/RemoveUnreachableContacts.lua
@@ -1,37 +1,38 @@
---
--- Copyright (c) 2010 Remko Tronçon
--- Licensed under the GNU General Public License v3.
--- See Documentation/Licenses/GPLv3.txt for more information.
---
+--[[
+	Copyright (c) 2010-2013 Remko Tronçon
+	Licensed under the GNU General Public License v3.
+	See Documentation/Licenses/GPLv3.txt for more information.
+--]]
 
--- This script logs into an XMPP server, iterates over all roster items,
--- and checks if their server is still alive. If not, the script asks you
--- whether it should remove the contact from your contact list.
--- 
--- The following environment variables are used:
--- * SLUIFT_JID, SWIFT_PASS: JID and password to log in with
--- * SLUIFT_DEBUG: Sets whether debugging should be turned on
+--[[
+	This script logs into an XMPP server, iterates over all roster items,
+	and checks if their server is still alive. If not, the script asks you
+	whether it should remove the contact from your contact list.
 
-require "sluift"
-sluift.debug = os.getenv("SLUIFT_DEBUG")
+	The following environment variables are used:
+	* SLUIFT_JID, SWIFT_PASS: JID and password to log in with
+	* SLUIFT_DEBUG: Sets whether debugging should be turned on
+--]]
 
-print "Connecting ..."
-c = sluift.new_client(os.getenv("SLUIFT_JID"), os.getenv("SLUIFT_PASS"))
-c:connect()
+require 'sluift'
+sluift.debug = os.getenv('SLUIFT_DEBUG')
 
-print "Checking for unreachable contacts ..."
-for jid, _ in pairs(c:get_contacts()) do
-	_, err = c:get_version(sluift.jid_domain(jid), 10000)
-	if err == "Remote server not found" or err == "Timeout" then
-		print("Delete " .. jid .. " (" .. err .. ") ? [y/n/q]")
-		answer = io.read()
-		if answer == "y" then
-			c:remove_contact(jid)
-		elseif answer == "q" then
-			break
+print 'Connecting ...'
+c = sluift.new_client(os.getenv('SLUIFT_JID'), os.getenv('SLUIFT_PASS'))
+c:connect(function (c)
+	print 'Checking for unreachable contacts ...'
+	for jid in pairs(c:get_contacts()) do
+		_, err = c:get_software_version {to = sluift.jid.domain(jid), timeout = 10000}
+		print(err)
+		if err == 'Remote server not found' or err == 'Remote server timeout' then
+			print('Delete ' .. jid .. ' (' .. err .. ') ? [y/n/q]')
+			answer = io.read()
+			if answer == 'y' then
+				c:remove_contact(jid)
+			elseif answer == 'q' then
+				break
+			end
 		end
 	end
-end
-
-print "Done. Exiting ..."
-c:disconnect()
+	print 'Done. Exiting ...'
+end)
diff --git a/Sluift/Examples/Wonderland.lua b/Sluift/Examples/Wonderland.lua
index 58c00ca..235d8d0 100755
--- a/Sluift/Examples/Wonderland.lua
+++ b/Sluift/Examples/Wonderland.lua
@@ -44,9 +44,9 @@ end
 print("Done. Waiting ...")
 while true do
 	for _, client in ipairs(clients) do
-		client:for_event(function(e) 
-				if e["type"] == "message" then client:send_message(e["from"], "Off with their heads!") end 
-			end, 1000)
+		for message in client:messages {timeout = 1000} do
+			client:send_message{to = e["from"], body = "Off with their heads!"}
+		end
 	end
 	sluift.sleep(1000)
 end
diff --git a/Sluift/GenericLuaElementConvertor.h b/Sluift/GenericLuaElementConvertor.h
new file mode 100644
index 0000000..afad481
--- /dev/null
+++ b/Sluift/GenericLuaElementConvertor.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <lua.hpp>
+#include <string>
+
+#include <Swiften/Base/Override.h>
+#include <Sluift/LuaElementConvertor.h>
+#include <Sluift/Lua/Check.h>
+#include <Sluift/Lua/LuaUtils.h>
+
+namespace Swift {
+	template<typename T>
+	class GenericLuaElementConvertor : public LuaElementConvertor {
+		public:
+			GenericLuaElementConvertor(const std::string& type) : type(type) {
+			}
+
+			virtual ~GenericLuaElementConvertor() {}
+
+			virtual boost::shared_ptr<Payload> convertFromLua(lua_State* L, int index, const std::string& payloadType) SWIFTEN_OVERRIDE {
+				if (payloadType == type) {
+					Lua::checkType(L, index, LUA_TTABLE);
+					lua_pushvalue(L, index);
+					boost::shared_ptr<Payload> result = doConvertFromLua(L);
+					lua_pop(L, 1);
+					return result;
+				}
+				return boost::shared_ptr<Payload>();
+			}
+
+			virtual boost::optional<std::string> convertToLua(
+					lua_State* L, boost::shared_ptr<Payload> payload) SWIFTEN_OVERRIDE {
+				if (boost::shared_ptr<T> actualPayload = boost::dynamic_pointer_cast<T>(payload)) {
+					doConvertToLua(L, actualPayload);
+					assert(lua_type(L, -1) == LUA_TTABLE);
+					return type;
+				}
+				return NO_RESULT;
+			}
+
+		protected:
+			virtual boost::shared_ptr<T> doConvertFromLua(lua_State*) = 0;
+			virtual void doConvertToLua(lua_State*, boost::shared_ptr<T>) = 0;
+
+		private:
+			std::string type;
+	};
+}
diff --git a/Sluift/Lua/Check.cpp b/Sluift/Lua/Check.cpp
new file mode 100644
index 0000000..cfb726a
--- /dev/null
+++ b/Sluift/Lua/Check.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/Lua/Check.h>
+
+#include <boost/numeric/conversion/cast.hpp>
+#include <iostream>
+#include <sstream>
+#include <lua.hpp>
+
+#include <Sluift/Lua/Exception.h>
+
+using namespace Swift;
+
+
+static std::string getArgTypeError(lua_State* L, int arg, int tag) {
+	std::ostringstream s;
+	s << "Arg " << arg << ": expected " << lua_typename(L, tag) << ", got " << luaL_typename(L, arg);
+	return s.str();
+}
+
+void Lua::checkType(lua_State* L, int arg, int type) {
+	if (lua_type(L, arg) !=  type) {
+		throw Lua::Exception(getArgTypeError(L, arg, type));
+	}
+}
+
+int Lua::checkIntNumber(lua_State* L, int arg) {
+	if (!lua_isnumber(L, arg)) {
+		throw Lua::Exception(getArgTypeError(L, arg, LUA_TNUMBER));
+	}
+	return boost::numeric_cast<int>(lua_tonumber(L, arg));
+}
+
+std::string Lua::checkString(lua_State* L, int arg) {
+	const char *s = lua_tolstring(L, arg, NULL);
+	if (!s) {
+		throw Lua::Exception(getArgTypeError(L, arg, LUA_TSTRING));
+	}
+	return std::string(s);
+}
+
+void* Lua::checkUserDataRaw(lua_State* L, int arg, const char* tableName) {
+	void* userData = lua_touserdata(L, arg);
+	if (!userData) {
+		throw Lua::Exception(getArgTypeError(L, arg, LUA_TUSERDATA));
+	}
+	if (!lua_getmetatable(L, arg)) {
+		throw Lua::Exception(getArgTypeError(L, arg, LUA_TUSERDATA));
+	}
+	lua_getfield(L, LUA_REGISTRYINDEX, tableName);
+	if (!lua_rawequal(L, -1, -2)) {
+		throw Lua::Exception(getArgTypeError(L, arg, LUA_TUSERDATA));
+	}
+	lua_pop(L, 2);
+	return userData;
+}
diff --git a/Sluift/Lua/Check.h b/Sluift/Lua/Check.h
new file mode 100644
index 0000000..a569826
--- /dev/null
+++ b/Sluift/Lua/Check.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <string>
+
+struct lua_State;
+
+namespace Swift {
+	namespace Lua {
+		void checkType(lua_State* L, int arg, int type);
+		int checkIntNumber(lua_State* L, int arg);
+		std::string checkString(lua_State* L, int arg);
+
+		void* checkUserDataRaw(lua_State* L, int arg, const char* tableName);
+
+		template<typename T>
+		T** checkUserData(lua_State* L, int arg, const char* tableName) {
+			return reinterpret_cast<T**>(checkUserDataRaw(L, arg, tableName));
+		}
+	}
+}
diff --git a/Sluift/Lua/Debug.h b/Sluift/Lua/Debug.h
new file mode 100644
index 0000000..8e86b89
--- /dev/null
+++ b/Sluift/Lua/Debug.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <lua.hpp>
+#include <iostream>
+
+namespace Swift {
+	namespace Lua {
+		inline void dumpStack(lua_State *L) {
+			for (int i = 1; i <= lua_gettop(L); i++) {
+				int type = lua_type(L, i);
+				std::cout << i << ": [" << lua_typename(L, type) << "] ";
+				switch (type) {
+					case LUA_TSTRING: std::cout << lua_tostring(L, i); break;
+					case LUA_TNUMBER: std::cout << lua_tonumber(L, i); break;
+					case LUA_TBOOLEAN: std::cout << lua_toboolean(L, i); break;
+					default: break;
+				}
+				std::cout << std::endl;
+			}
+		}
+	}
+}
diff --git a/Sluift/Lua/Exception.cpp b/Sluift/Lua/Exception.cpp
new file mode 100644
index 0000000..d80b9fb
--- /dev/null
+++ b/Sluift/Lua/Exception.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/Lua/Exception.h>
+
+using namespace Swift::Lua;
+
+Exception::Exception(const std::string& what) : std::runtime_error(what) {
+}
+
+Exception::~Exception() throw() {
+}
diff --git a/Sluift/Lua/Exception.h b/Sluift/Lua/Exception.h
new file mode 100644
index 0000000..6d00d01
--- /dev/null
+++ b/Sluift/Lua/Exception.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <stdexcept>
+
+namespace Swift {
+	namespace Lua {
+		class Exception : public std::runtime_error {
+			public:
+				Exception(const std::string& what);
+				virtual ~Exception() throw();
+		};
+	}
+}
+
diff --git a/Sluift/Lua/FunctionRegistration.cpp b/Sluift/Lua/FunctionRegistration.cpp
new file mode 100644
index 0000000..b773952
--- /dev/null
+++ b/Sluift/Lua/FunctionRegistration.cpp
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/Lua/FunctionRegistration.h>
+
+using namespace Swift::Lua;
+
+FunctionRegistration::FunctionRegistration(const std::string& name, lua_CFunction function, const std::string& type) {
+	FunctionRegistry::getInstance().addFunction(name, function, type);
+}
+
+FunctionRegistration::~FunctionRegistration() {
+}
diff --git a/Sluift/Lua/FunctionRegistration.h b/Sluift/Lua/FunctionRegistration.h
new file mode 100644
index 0000000..0df1da1
--- /dev/null
+++ b/Sluift/Lua/FunctionRegistration.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Sluift/Lua/FunctionRegistry.h>
+#include <lua.hpp>
+#include <string>
+
+namespace Swift {
+	namespace Lua {
+		class FunctionRegistration {
+			public:
+				FunctionRegistration(const std::string& name, lua_CFunction function, const std::string& type);
+				~FunctionRegistration();
+		};
+	}
+}
+#define SLUIFT_LUA_FUNCTION(TYPE, NAME) \
+	static int TYPE##_##NAME(lua_State* L); \
+	static int TYPE##_##NAME##_wrapper(lua_State* L); \
+	static ::Swift::Lua::FunctionRegistration TYPE##_##NAME##_registration( #NAME , TYPE##_##NAME##_wrapper, #TYPE); \
+	static int TYPE##_##NAME##_wrapper(lua_State* L) { \
+		try { \
+			return TYPE ## _ ## NAME (L); \
+		} \
+		catch (const std::exception& e) { \
+			return luaL_error(L, e.what()); \
+		} \
+	} \
+	static int TYPE ## _ ## NAME (lua_State* L)
diff --git a/Sluift/Lua/FunctionRegistry.cpp b/Sluift/Lua/FunctionRegistry.cpp
new file mode 100644
index 0000000..99ea096
--- /dev/null
+++ b/Sluift/Lua/FunctionRegistry.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/Lua/FunctionRegistry.h>
+
+#include <Swiften/Base/foreach.h>
+
+using namespace Swift::Lua;
+
+FunctionRegistry::FunctionRegistry() {
+}
+
+FunctionRegistry::~FunctionRegistry() {
+}
+
+FunctionRegistry& FunctionRegistry::getInstance() {
+	static FunctionRegistry instance;
+	return instance;
+}
+
+void FunctionRegistry::addFunction(const std::string& name, lua_CFunction function, const std::string& type) {
+	Registration registration;
+	registration.name = name;
+	registration.function = function;
+	registration.type = type;
+	registrations.push_back(registration);
+}
+
+std::string FunctionRegistry::getMetaTableNameForType(const std::string& type) {
+	return "Sluift_" + type;
+}
+
+void FunctionRegistry::registerTypeMetaTable(lua_State* L, const std::string& type) {
+	luaL_newmetatable(L, getMetaTableNameForType(type).c_str());
+	lua_pushvalue(L, -1);
+	lua_setfield(L, -2, "__index");
+	addFunctionsToTable(L, type);
+}
+
+void FunctionRegistry::createFunctionTable(lua_State* L, const std::string& type) {
+	lua_newtable(L);
+	addFunctionsToTable(L, type);
+}
+
+void FunctionRegistry::addFunctionsToTable(lua_State* L, const std::string& type) {
+	foreach(const Registration& registration, registrations) {
+		if (registration.type == type) {
+			lua_pushcclosure(L, registration.function, 0);
+			lua_setfield(L, -2, registration.name.c_str());
+		}
+	}
+}
diff --git a/Sluift/Lua/FunctionRegistry.h b/Sluift/Lua/FunctionRegistry.h
new file mode 100644
index 0000000..e3ad620
--- /dev/null
+++ b/Sluift/Lua/FunctionRegistry.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <lua.hpp>
+#include <string>
+#include <vector>
+
+namespace Swift {
+	namespace Lua {
+		class FunctionRegistry {
+			public:
+				~FunctionRegistry();
+				static FunctionRegistry& getInstance();
+
+				void addFunction(const std::string& name, lua_CFunction function, const std::string& type);
+
+				static std::string getMetaTableNameForType(const std::string& type);
+				void registerTypeMetaTable(lua_State* L, const std::string& type);
+
+				void createFunctionTable(lua_State* L, const std::string& type);
+
+				/**
+				 * Adds the functions to the table on the top of the stack.
+				 */
+				void addFunctionsToTable(lua_State* L, const std::string& type);
+
+			private:
+				FunctionRegistry();
+
+
+			private:
+				struct Registration {
+					std::string name;
+					lua_CFunction function;
+					std::string type;
+				};
+				std::vector<Registration> registrations;
+		};
+	}
+}
diff --git a/Sluift/Lua/LuaUtils.cpp b/Sluift/Lua/LuaUtils.cpp
new file mode 100644
index 0000000..7052abe
--- /dev/null
+++ b/Sluift/Lua/LuaUtils.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/Lua/LuaUtils.h>
+
+#include <lua.hpp>
+
+#include <boost/scope_exit.hpp>
+#include <Sluift/Lua/Exception.h>
+#include <iostream>
+#include <cassert>
+#include <sstream>
+#include <boost/numeric/conversion/cast.hpp>
+#include <Sluift/globals.h>
+
+using namespace Swift::Lua;
+
+static const std::string INDENT = "  ";
+
+void Swift::Lua::registerTableToString(lua_State* L, int index) {
+	index = Lua::absoluteOffset(L, index);
+	lua_rawgeti(L, LUA_REGISTRYINDEX, Sluift::globals.bootIndex);
+	lua_getfield(L, -1, "register_table_tostring");
+	lua_pushvalue(L, index);
+	if (lua_pcall(L, 1, 0, 0) != 0) {
+		throw Lua::Exception(lua_tostring(L, -1));
+	}
+	lua_pop(L, 1);
+}
+
+void Swift::Lua::registerGetByTypeIndex(lua_State* L, int index) {
+	index = Lua::absoluteOffset(L, index);
+	lua_rawgeti(L, LUA_REGISTRYINDEX, Sluift::globals.bootIndex);
+	lua_getfield(L, -1, "register_get_by_type_index");
+	lua_pushvalue(L, index);
+	if (lua_pcall(L, 1, 0, 0) != 0) {
+		throw Lua::Exception(lua_tostring(L, -1));
+	}
+	lua_pop(L, 1);
+}
+
+boost::optional<std::string> Swift::Lua::getStringField(lua_State* L, int index, const std::string& field) {
+	lua_getfield(L, index, field.c_str());
+	// Seems to generate warnings with some versions of CLang that i can't turn off.
+	// Leaving the more elegant code here, hoping we can re-enable it later (newer boost? c++11?).
+	// The same applies to the other get*Field functions.
+	//BOOST_SCOPE_EXIT(&L) { lua_pop(L,1); } BOOST_SCOPE_EXIT_END
+	//return lua_isstring(L, -1) ? std::string(lua_tostring(L, -1)) : boost::optional<std::string>();
+	
+	boost::optional<std::string> result;
+	if (lua_isstring(L, -1)) {
+		result = std::string(lua_tostring(L, -1));
+	}
+	lua_pop(L, 1);
+	return result;
+}
+
+boost::optional<bool> Swift::Lua::getBooleanField(lua_State* L, int index, const std::string& field) {
+	lua_getfield(L, index, field.c_str());
+	boost::optional<bool> result;
+	if (lua_isboolean(L, -1)) {
+		result = lua_toboolean(L, -1);
+	}
+	lua_pop(L, 1);
+	return result;
+}
+
+boost::optional<int> Swift::Lua::getIntField(lua_State* L, int index, const std::string& field) {
+	lua_getfield(L, index, field.c_str());
+	boost::optional<int> result;
+	if (lua_isnumber(L, -1)) {
+		result = boost::numeric_cast<int>(lua_tonumber(L, -1));
+	}
+	lua_pop(L, 1);
+	return result;
+}
diff --git a/Sluift/Lua/LuaUtils.h b/Sluift/Lua/LuaUtils.h
new file mode 100644
index 0000000..bad307c
--- /dev/null
+++ b/Sluift/Lua/LuaUtils.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <lua.hpp>
+#include <boost/optional.hpp>
+
+struct lua_State;
+
+namespace Swift {
+	namespace Lua {
+		/**
+		 * Can be used as __tostring metamethod on a table.
+		 */
+		int convertTableToString(lua_State* L);
+
+		void registerTableToString(lua_State* L, int index);
+		void registerGetByTypeIndex(lua_State* L, int index);
+
+		inline int absoluteOffset(lua_State* L, int index) {
+			return index > 0 ? index : lua_gettop(L) + index + 1;
+		}
+
+		boost::optional<std::string> getStringField(lua_State* L, int index, const std::string&);
+		boost::optional<bool> getBooleanField(lua_State* L, int index, const std::string&);
+		boost::optional<int> getIntField(lua_State* L, int index, const std::string&);
+	}
+}
diff --git a/Sluift/Lua/Value.h b/Sluift/Lua/Value.h
index 7b10cd2..55aa347 100644
--- a/Sluift/Lua/Value.h
+++ b/Sluift/Lua/Value.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011 Remko Tronçon
+ * Copyright (c) 2010-2013 Remko Tronçon
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -11,6 +11,7 @@
 #include <vector>
 #include <boost/variant.hpp>
 #include <boost/shared_ptr.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
 
 struct lua_State;
 
@@ -28,7 +29,32 @@ namespace Swift {
 			>::type Value;
 
 		typedef std::map<std::string, boost::shared_ptr<Value> > Table;
+		typedef std::vector<Value> Array;
 		
+		inline boost::shared_ptr<Value> nilRef() {
+			return boost::make_shared<Value>(Nil());
+		}
+
+		inline boost::shared_ptr<Value> valueRef(const std::string& value) {
+			return boost::make_shared<Value>(value);
+		}
+
+		inline boost::shared_ptr<Value> intRef(int value) {
+			return boost::make_shared<Value>(value);
+		}
+
+		inline boost::shared_ptr<Value> boolRef(bool value) {
+			return boost::make_shared<Value>(value);
+		}
+
+		inline boost::shared_ptr<Value> valueRef(const Table& table) {
+			return boost::make_shared<Value>(table);
+		}
+
+		inline boost::shared_ptr<Value> valueRef(const Array& array) {
+		 	return boost::make_shared<Value>(array);
+		}
+
 		void pushValue(lua_State* state, const Value& value);
 	}
 }
diff --git a/Sluift/LuaElementConvertor.cpp b/Sluift/LuaElementConvertor.cpp
new file mode 100644
index 0000000..c1d0720
--- /dev/null
+++ b/Sluift/LuaElementConvertor.cpp
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/LuaElementConvertor.h>
+
+using namespace Swift;
+
+LuaElementConvertor::~LuaElementConvertor() {
+}
+
+boost::optional<std::string> LuaElementConvertor::NO_RESULT;
diff --git a/Sluift/LuaElementConvertor.h b/Sluift/LuaElementConvertor.h
new file mode 100644
index 0000000..187ccf1
--- /dev/null
+++ b/Sluift/LuaElementConvertor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/optional.hpp>
+
+struct lua_State;
+
+namespace Swift {
+	class Payload;
+
+	class LuaElementConvertor {
+		public:
+			static boost::optional<std::string> NO_RESULT;
+
+			virtual ~LuaElementConvertor();
+
+			virtual boost::shared_ptr<Payload> convertFromLua(lua_State*, int index, const std::string& type) = 0;
+			virtual boost::optional<std::string> convertToLua(lua_State*, boost::shared_ptr<Payload>) = 0;
+	};
+}
diff --git a/Sluift/LuaElementConvertors.cpp b/Sluift/LuaElementConvertors.cpp
new file mode 100644
index 0000000..5913858
--- /dev/null
+++ b/Sluift/LuaElementConvertors.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/LuaElementConvertors.h>
+
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Base/foreach.h>
+#include <Sluift/LuaElementConvertor.h>
+#include <Sluift/ElementConvertors/RawXMLElementConvertor.h>
+#include <Sluift/ElementConvertors/PubSubEventConvertor.h>
+#include <Sluift/ElementConvertors/DOMElementConvertor.h>
+#include <Sluift/ElementConvertors/DefaultElementConvertor.h>
+#include <Sluift/ElementConvertors/DiscoItemsConvertor.h>
+#include <Sluift/ElementConvertors/DiscoInfoConvertor.h>
+#include <Sluift/ElementConvertors/FormConvertor.h>
+#include <Sluift/ElementConvertors/SoftwareVersionConvertor.h>
+#include <Sluift/ElementConvertors/VCardUpdateConvertor.h>
+#include <Sluift/ElementConvertors/VCardConvertor.h>
+#include <Sluift/Lua/LuaUtils.h>
+#include <Sluift/Lua/Exception.h>
+
+using namespace Swift;
+
+LuaElementConvertors::LuaElementConvertors() {
+	registerConvertors();
+	convertors.push_back(boost::make_shared<PubSubEventConvertor>(this));
+	convertors.push_back(boost::make_shared<VCardConvertor>());
+	convertors.push_back(boost::make_shared<VCardUpdateConvertor>());
+	convertors.push_back(boost::make_shared<FormConvertor>());
+	convertors.push_back(boost::make_shared<SoftwareVersionConvertor>());
+	convertors.push_back(boost::make_shared<DiscoInfoConvertor>());
+	convertors.push_back(boost::make_shared<DiscoItemsConvertor>());
+	convertors.push_back(boost::make_shared<DOMElementConvertor>());
+	convertors.push_back(boost::make_shared<RawXMLElementConvertor>());
+	convertors.push_back(boost::make_shared<DefaultElementConvertor>());
+}
+
+LuaElementConvertors::~LuaElementConvertors() {
+}
+
+#include <Sluift/ElementConvertors/ElementConvertors.ipp>
+
+boost::shared_ptr<Payload> LuaElementConvertors::convertFromLua(lua_State* L, int index) {
+	if (lua_isstring(L, index)) {
+		return convertFromLuaUntyped(L, index, "xml");
+	}
+	else if (lua_istable(L, index)) {
+		lua_getfield(L, index, "_type");
+		if (lua_isstring(L, -1)) {
+			std::string type = lua_tostring(L, -1);
+			lua_pop(L, 1);
+			return convertFromLuaUntyped(L, index, type);
+		}
+		lua_pop(L, 1);
+	}
+	throw Lua::Exception("Unable to determine type");
+}
+
+boost::shared_ptr<Payload> LuaElementConvertors::convertFromLuaUntyped(lua_State* L, int index, const std::string& type) {
+	index = Lua::absoluteOffset(L, index);
+	foreach (boost::shared_ptr<LuaElementConvertor> convertor, convertors) {
+		if (boost::shared_ptr<Payload> result = convertor->convertFromLua(L, index, type)) {
+			return result;
+		}
+	}
+	return boost::shared_ptr<Payload>();
+}
+
+
+int LuaElementConvertors::convertToLua(lua_State* L, boost::shared_ptr<Payload> payload) {
+	if (boost::optional<std::string> type = doConvertToLuaUntyped(L, payload)) {
+		if (lua_istable(L, -1)) {
+			lua_pushstring(L, type->c_str());
+			lua_setfield(L, -2, "_type");
+			Lua::registerTableToString(L, -1);
+		}
+		else {
+			assert(*type == "xml");
+		}
+		return 1;
+	}
+	return 0;
+}
+
+int LuaElementConvertors::convertToLuaUntyped(lua_State* L, boost::shared_ptr<Payload> payload) {
+	if (doConvertToLuaUntyped(L, payload)) {
+		return 1;
+	}
+	return 0;
+}
+
+boost::optional<std::string> LuaElementConvertors::doConvertToLuaUntyped(
+		lua_State* L, boost::shared_ptr<Payload> payload) {
+	if (!payload) {
+		return LuaElementConvertor::NO_RESULT;
+	}
+	foreach (boost::shared_ptr<LuaElementConvertor> convertor, convertors) {
+		if (boost::optional<std::string> type = convertor->convertToLua(L, payload)) {
+			return *type;
+		}
+	}
+	return LuaElementConvertor::NO_RESULT;
+}
+
diff --git a/Sluift/LuaElementConvertors.h b/Sluift/LuaElementConvertors.h
new file mode 100644
index 0000000..36da15a
--- /dev/null
+++ b/Sluift/LuaElementConvertors.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <vector>
+#include <boost/shared_ptr.hpp>
+#include <boost/optional.hpp>
+
+struct lua_State;
+
+namespace Swift {
+	class LuaElementConvertor;
+	class Payload;
+
+	class LuaElementConvertors {
+		public:
+			LuaElementConvertors();
+			virtual ~LuaElementConvertors();
+
+			boost::shared_ptr<Payload> convertFromLua(lua_State*, int index);
+			int convertToLua(lua_State*, boost::shared_ptr<Payload>);
+
+			/**
+			 * Adds a toplevel type+data table with the given type.
+			 */
+			boost::shared_ptr<Payload> convertFromLuaUntyped(lua_State*, int index, const std::string& type);
+			
+			/**
+			 * Strips the toplevel type+data table, and only return the
+			 * data.
+			 */
+			int convertToLuaUntyped(lua_State*, boost::shared_ptr<Payload>);
+
+		private:
+			boost::optional<std::string> doConvertToLuaUntyped(lua_State*, boost::shared_ptr<Payload>);
+			void registerConvertors();
+
+		private:
+			std::vector< boost::shared_ptr<LuaElementConvertor> > convertors;
+	};
+}
diff --git a/Sluift/Response.cpp b/Sluift/Response.cpp
new file mode 100644
index 0000000..519379c
--- /dev/null
+++ b/Sluift/Response.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/Response.h>
+
+#include <lua.hpp>
+
+#include <Sluift/globals.h>
+#include <Swiften/Elements/ErrorPayload.h>
+#include <Sluift/Lua/LuaUtils.h>
+
+using namespace Swift;
+using namespace Swift::Sluift;
+
+static std::string getErrorString(boost::shared_ptr<ErrorPayload> error) {
+	// Copied from ChatControllerBase.
+	// TODO: Share this code;
+	std::string defaultMessage = "Error sending message";
+	if (!error->getText().empty()) {
+		return error->getText();
+	}
+	else {
+		switch (error->getCondition()) {
+			case ErrorPayload::BadRequest: return "Bad request";
+			case ErrorPayload::Conflict: return "Conflict";
+			case ErrorPayload::FeatureNotImplemented: return "This feature is not implemented";
+			case ErrorPayload::Forbidden: return "Forbidden";
+			case ErrorPayload::Gone: return "Recipient can no longer be contacted";
+			case ErrorPayload::InternalServerError: return "Internal server error";
+			case ErrorPayload::ItemNotFound: return "Item not found";
+			case ErrorPayload::JIDMalformed: return "JID Malformed";
+			case ErrorPayload::NotAcceptable: return "Message was rejected";
+			case ErrorPayload::NotAllowed: return "Not allowed";
+			case ErrorPayload::NotAuthorized: return "Not authorized";
+			case ErrorPayload::PaymentRequired: return "Payment is required";
+			case ErrorPayload::RecipientUnavailable: return "Recipient is unavailable";
+			case ErrorPayload::Redirect: return "Redirect";
+			case ErrorPayload::RegistrationRequired: return "Registration required";
+			case ErrorPayload::RemoteServerNotFound: return "Recipient's server not found";
+			case ErrorPayload::RemoteServerTimeout: return "Remote server timeout";
+			case ErrorPayload::ResourceConstraint: return "The server is low on resources";
+			case ErrorPayload::ServiceUnavailable: return "The service is unavailable";
+			case ErrorPayload::SubscriptionRequired: return "A subscription is required";
+			case ErrorPayload::UndefinedCondition: return "Undefined condition";
+			case ErrorPayload::UnexpectedRequest: return "Unexpected request";
+		}
+	}
+	assert(false);
+	return defaultMessage;
+}
+
+Response::~Response() {
+}
+
+int Response::convertToLuaResult(lua_State* L) {
+	if (error) {
+		lua_pushnil(L);
+		lua_pushstring(L, getErrorString(error).c_str());
+		Sluift::globals.elementConvertor.convertToLuaUntyped(L, error);
+		Lua::registerTableToString(L, -1);
+		return 3;
+	}
+	else {
+		if (result) {
+			Sluift::globals.elementConvertor.convertToLuaUntyped(L, result);
+			Lua::registerTableToString(L, -1);
+		}
+		else {
+			lua_pushboolean(L, 1);
+		}
+		return 1;
+	}
+
+}
+
diff --git a/Sluift/Response.h b/Sluift/Response.h
new file mode 100644
index 0000000..1cd059a
--- /dev/null
+++ b/Sluift/Response.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Elements/Payload.h>
+#include <Swiften/Elements/ErrorPayload.h>
+
+struct lua_State;
+
+namespace Swift {
+	namespace Sluift {
+		struct Response {
+			Response(boost::shared_ptr<Payload> result, boost::shared_ptr<ErrorPayload> error) : result(result), error(error) {}
+			~Response();
+
+			static Response withResult(boost::shared_ptr<Payload> response) {
+				return Response(response, boost::shared_ptr<ErrorPayload>());
+			}
+
+			static Response withError(boost::shared_ptr<ErrorPayload> error) {
+				return Response(boost::shared_ptr<Payload>(), error);
+			}
+
+			int convertToLuaResult(lua_State* L);
+
+			boost::shared_ptr<Payload> result;
+			boost::shared_ptr<ErrorPayload> error;
+		};
+	}
+}
diff --git a/Sluift/ResponseSink.h b/Sluift/ResponseSink.h
deleted file mode 100644
index 700363a..0000000
--- a/Sluift/ResponseSink.h
+++ /dev/null
@@ -1,48 +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/ErrorPayload.h>
-
-namespace Swift {
-	template<typename T>
-	class ResponseSink {
-		public:
-			ResponseSink() : responseReceived(false) {
-			}
-
-			bool hasResponse() const {
-				return responseReceived;
-			}
-
-			boost::shared_ptr<T> getResponsePayload() const {
-				return payload;
-			}
-
-			ErrorPayload::ref getResponseError() const {
-				return error;
-			}
-
-			void operator()(boost::shared_ptr<T> payload, ErrorPayload::ref error) {
-				this->payload = payload;
-				this->error = error;
-				this->responseReceived = true;
-			}
-
-			void operator()(ErrorPayload::ref error) {
-				this->error = error;
-				this->responseReceived = true;
-			}
-
-		private:
-			bool responseReceived;
-			boost::shared_ptr<T> payload;
-			ErrorPayload::ref error;
-	};
-}
diff --git a/Sluift/SConscript b/Sluift/SConscript
index af3cf8c..fcc39fc 100644
--- a/Sluift/SConscript
+++ b/Sluift/SConscript
@@ -10,21 +10,44 @@ if env["SCONS_STAGE"] == "build" and not GetOption("help") and not env.get("HAVE
 elif env["SCONS_STAGE"] == "build" :
 	sluift_sources = [
 		"Lua/Value.cpp",
+		"Lua/Exception.cpp",
+		"Lua/Check.cpp",
+		"Lua/FunctionRegistration.cpp",
+		"Lua/FunctionRegistry.cpp",
+		"Lua/LuaUtils.cpp",
+		"LuaElementConvertors.cpp",
+		"LuaElementConvertor.cpp",
+		"Response.cpp",
+		"ElementConvertors/VCardUpdateConvertor.cpp",
+		"ElementConvertors/PubSubEventConvertor.cpp",
+		"ElementConvertors/RawXMLElementConvertor.cpp",
+		"ElementConvertors/DOMElementConvertor.cpp",
+		"ElementConvertors/DefaultElementConvertor.cpp",
+		"ElementConvertors/DiscoInfoConvertor.cpp",
+		"ElementConvertors/DiscoItemsConvertor.cpp",
+		"ElementConvertors/FormConvertor.cpp",
+		"ElementConvertors/SoftwareVersionConvertor.cpp",
+		"ElementConvertors/VCardConvertor.cpp",
 		"ClientHelpers.cpp",
+		"SluiftClient.cpp",
+		"boot.c",
+		"client.cpp",
 		"sluift.cpp"
 	]
+	sluift_sources += env.SConscript("ElementConvertors/SConscript")
 
-	myenv = env.Clone()
-	myenv.UseFlags(env.get("LUA_FLAGS", {}))
-	myenv.UseFlags(env["SWIFTEN_FLAGS"])
-	myenv.UseFlags(env["SWIFTEN_DEP_FLAGS"])
-	myenv["SHLIBPREFIX"] = ""
-	if myenv["PLATFORM"] == "win32" :
-		myenv.Append(CPPDEFINES = ["SLUIFT_BUILD_DLL"])
-	elif myenv["PLATFORM"] == "darwin" :
-		myenv["SHLIBSUFFIX"] = ".so"
-
-	myenv["SLUIFT_VERSION"] = Version.getBuildVersion(env.Dir("#").abspath, "sluift")
+	sluift_env = env.Clone()
+	sluift_env.UseFlags(env.get("LUA_FLAGS", {}))
+	sluift_env.UseFlags(env["SWIFTEN_FLAGS"])
+	sluift_env.UseFlags(env["SWIFTEN_DEP_FLAGS"])
+	sluift_env["SHLIBPREFIX"] = ""
+	if sluift_env["PLATFORM"] == "win32" :
+		sluift_env.Append(CPPDEFINES = ["SLUIFT_BUILD_DLL"])
+	elif sluift_env["PLATFORM"] == "darwin" :
+		sluift_env["SHLIBSUFFIX"] = ".so"
+
+	# Generate a customized lua.c
+	sluift_env["SLUIFT_VERSION"] = Version.getBuildVersion(env.Dir("#").abspath, "sluift")
 	def patchLua(env, target, source) :
 		f = open(source[0].abspath, "r")
 		contents = f.read()
@@ -38,24 +61,27 @@ elif env["SCONS_STAGE"] == "build" :
 		f = open(target[0].abspath, "w")
 		f.write(contents)
 		f.close()
+	sluift_env.Command("lua.c", ["#/3rdParty/Lua/src/lua.c", sluift_env.Value(sluift_env["SLUIFT_VERSION"])], env.Action(patchLua, cmdstr = "$GENCOMSTR"))
+
+	# Generate boot.cpp
+	def generate_embedded_lua(env, target, source) :
+		f = open(source[0].abspath, "r")
+		data = f.read()
+		f.close()
+		f = open(target[0].abspath, "w")
+		f.write('const char ' + source[0].name.replace(".", "_") + "[] = \"" + data.replace("\\", "\\\\").replace("\n", "\\n").replace('"', '\\"') + "\";")
+		f.close()
+	sluift_env.Command("boot.c", ["boot.lua"], env.Action(generate_embedded_lua, cmdstr="$GENCOMSTR"))
+
+	if sluift_env.get("HAVE_READLINE", False) :
+		sluift_env.Append(CPPDEFINES = ["LUA_USE_READLINE"])
+		sluift_env.MergeFlags(sluift_env["READLINE_FLAGS"])
+
+	sluift_env.WriteVal("dll.c", sluift_env.Value(""))
+
+	sluift_sources = [env.File(x) for x in sluift_sources]
+	for sluift_variant in ['dll', 'exe'] :
+		SConscript(["SConscript.variant"], variant_dir = sluift_variant,
+				duplicate = 0,
+				exports = ['sluift_sources', 'sluift_variant', 'sluift_env'])
 
-	myenv.Command("lua.c", ["#/3rdParty/Lua/src/lua.c", myenv.Value(myenv["SLUIFT_VERSION"])], env.Action(patchLua, cmdstr = "$GENCOMSTR"))
-	if myenv.get("HAVE_READLINE", False) :
-		myenv.Append(CPPDEFINES = ["LUA_USE_READLINE"])
-		myenv.MergeFlags(myenv["READLINE_FLAGS"])
-	env["SLUIFT"] = myenv.Program("sluift", sluift_sources + [
-			"lua.c",
-			"linit.c",
-		])
-
-	myenv.WriteVal("dll.c", myenv.Value(""))
-	myenv.SharedLibrary("sluift", sluift_sources + ["dll.c"])
-
-	if env["PLATFORM"] == "win32" :
-		ssl_libs = []
-		if myenv.get("OPENSSL_DIR", False) :
-			ssl_libs = [
-			os.path.join(env["OPENSSL_DIR"], "bin", "ssleay32.dll"),  
-			os.path.join(env["OPENSSL_DIR"], "bin", "libeay32.dll")
-		]
-		myenv.WindowsBundle("Sluift", resources = {"": ssl_libs})
diff --git a/Sluift/SConscript.variant b/Sluift/SConscript.variant
new file mode 100644
index 0000000..bf5d85e
--- /dev/null
+++ b/Sluift/SConscript.variant
@@ -0,0 +1,14 @@
+Import('env')
+Import('sluift_env')
+Import('sluift_variant')
+Import('sluift_sources')
+
+if sluift_variant == 'exe' :
+	env["SLUIFT"] = sluift_env.Program("sluift", sluift_sources + [
+		"#/Sluift/lua.c",
+		"#/Sluift/linit.c",
+	])
+else :
+	sluift_env.SharedLibrary("sluift", sluift_sources + [
+		"#/Sluift/dll.c"
+	])
diff --git a/Sluift/SluiftClient.cpp b/Sluift/SluiftClient.cpp
new file mode 100644
index 0000000..726a683
--- /dev/null
+++ b/Sluift/SluiftClient.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/SluiftClient.h>
+
+#include <Swiften/Client/ClientXMLTracer.h>
+#include <Swiften/Client/Client.h>
+#include <Swiften/Roster/XMPPRoster.h>
+#include <Sluift/SluiftGlobals.h>
+#include <Sluift/Lua/Exception.h>
+#include <Swiften/Elements/Message.h>
+#include <Swiften/Elements/PubSubEvent.h>
+#include <Swiften/Queries/RawRequest.h>
+#include <Sluift/ClientHelpers.h>
+#include <Swiften/Elements/Presence.h>
+
+using namespace Swift;
+
+SluiftClient::SluiftClient(
+		const JID& jid, 
+		const std::string& password, 
+		NetworkFactories* networkFactories, 
+		SimpleEventLoop* eventLoop,
+		SluiftGlobals* globals) :
+			networkFactories(networkFactories), 
+			eventLoop(eventLoop),
+			globals(globals),
+			tracer(NULL) {
+	client = new Client(jid, password, networkFactories);
+	client->setAlwaysTrustCertificates();
+	client->onDisconnected.connect(boost::bind(&SluiftClient::handleDisconnected, this, _1));
+	client->onMessageReceived.connect(boost::bind(&SluiftClient::handleIncomingMessage, this, _1));
+	client->onPresenceReceived.connect(boost::bind(&SluiftClient::handleIncomingPresence, this, _1));
+	client->getPubSubManager()->onEvent.connect(boost::bind(&SluiftClient::handleIncomingPubSubEvent, this, _1, _2));
+	client->getRoster()->onInitialRosterPopulated.connect(boost::bind(&SluiftClient::handleInitialRosterPopulated, this));
+	if (globals->debug) {
+		tracer = new ClientXMLTracer(client);
+	}
+}
+
+SluiftClient::~SluiftClient() {
+	delete tracer;
+	delete client;
+}
+
+void SluiftClient::connect() {
+	rosterReceived = false;
+	disconnectedError = boost::optional<ClientError>();
+	client->connect(options);
+}
+
+void SluiftClient::connect(const std::string& host) {
+	rosterReceived = false;
+	options.manualHostname = host;
+	client->connect(options);
+}
+
+void SluiftClient::waitConnected() {
+	Watchdog watchdog(globals->timeout, networkFactories->getTimerFactory());
+	while (!watchdog.getTimedOut() && client->isActive() && !client->isAvailable()) {
+		eventLoop->runUntilEvents();
+	}
+	if (watchdog.getTimedOut()) {
+		client->disconnect();
+		throw Lua::Exception("Timeout while connecting");
+	}
+	if (disconnectedError) {
+		throw Lua::Exception(getClientErrorString(*disconnectedError));
+	}
+}
+
+bool SluiftClient::isConnected() const {
+	return client->isAvailable();
+}
+
+void SluiftClient::disconnect() {
+	client->disconnect();
+	while (client->isActive()) {
+		eventLoop->runUntilEvents();
+	}
+}
+
+void SluiftClient::setSoftwareVersion(const std::string& name, const std::string& version, const std::string& os) {
+	client->setSoftwareVersion(name, version, os);
+}
+
+boost::optional<SluiftClient::Event> SluiftClient::getNextEvent(boost::optional<Event::Type> type, int timeout) {
+	Watchdog watchdog(timeout, networkFactories->getTimerFactory());
+	while (true) {
+		// Look for pending events in the queue
+		while (!pendingEvents.empty()) {
+			Event event = pendingEvents.front();
+			pendingEvents.pop_front();
+			if (!type || *type == event.type) {
+				return event;
+			}
+		}
+
+		// Wait for new events
+		while (!watchdog.getTimedOut() && pendingEvents.empty() && client->isActive()) {
+			eventLoop->runUntilEvents();
+		}
+
+		// Finish if we're disconnected or timed out
+		if (watchdog.getTimedOut() || !client->isActive()) {
+			return boost::optional<Event>();
+		}
+	}
+}
+
+std::vector<XMPPRosterItem> SluiftClient::getRoster() {
+	if (!rosterReceived) {
+		// If we haven't requested it yet, request it for the first time
+		client->requestRoster();
+	}
+	while (!rosterReceived) {
+		eventLoop->runUntilEvents();
+	}
+	return client->getRoster()->getItems();
+}
+
+void SluiftClient::handleIncomingMessage(boost::shared_ptr<Message> stanza) {
+	if (stanza->getPayload<PubSubEvent>()) {
+		// Already handled by pubsub manager
+		return;
+	}
+	pendingEvents.push_back(Event(stanza));
+}
+
+void SluiftClient::handleIncomingPresence(boost::shared_ptr<Presence> stanza) {
+	pendingEvents.push_back(Event(stanza));
+}
+
+void SluiftClient::handleIncomingPubSubEvent(const JID& from, boost::shared_ptr<PubSubEventPayload> event) {
+	pendingEvents.push_back(Event(from, event));
+}
+
+void SluiftClient::handleInitialRosterPopulated() {
+	rosterReceived = true;
+}
+
+void SluiftClient::handleRequestResponse(boost::shared_ptr<Payload> response, boost::shared_ptr<ErrorPayload> error) {
+	requestResponse = response;
+	requestError = error;
+	requestResponseReceived = true;
+}
+
+void SluiftClient::handleDisconnected(const boost::optional<ClientError>& error) {
+	disconnectedError = error;
+}
+
+Sluift::Response SluiftClient::doSendRequest(boost::shared_ptr<Request> request, int timeout) {
+	requestResponse.reset();
+	requestError.reset();
+	requestResponseReceived = false;
+	request->send();
+
+	Watchdog watchdog(timeout, networkFactories->getTimerFactory());
+	while (!watchdog.getTimedOut() && !requestResponseReceived) {
+		eventLoop->runUntilEvents();
+	}
+	return Sluift::Response(requestResponse, watchdog.getTimedOut() ? 
+			boost::make_shared<ErrorPayload>(ErrorPayload::RemoteServerTimeout) : requestError);
+}
diff --git a/Sluift/SluiftClient.h b/Sluift/SluiftClient.h
new file mode 100644
index 0000000..6515b7d
--- /dev/null
+++ b/Sluift/SluiftClient.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <deque>
+#include <boost/optional.hpp>
+#include <boost/bind.hpp>
+
+#include <Swiften/Client/ClientOptions.h>
+#include <Sluift/globals.h>
+#include <Swiften/Elements/IQ.h>
+#include <Swiften/Elements/Message.h>
+#include <Swiften/Elements/Presence.h>
+#include <Swiften/Queries/GenericRequest.h>
+#include <Swiften/Roster/XMPPRosterItem.h>
+#include <Swiften/Client/ClientError.h>
+#include <Swiften/Network/NetworkFactories.h>
+#include <Swiften/Client/Client.h>
+#include <Swiften/EventLoop/SimpleEventLoop.h>
+#include <Sluift/Watchdog.h>
+#include <Swiften/PubSub/PubSubManager.h>
+#include <Sluift/Response.h>
+
+namespace Swift {
+	struct SluiftGlobals;
+	class ClientXMLTracer;
+	class Client;
+	class Stanza;
+	class Payload;
+	class ErrorPayload;
+	class JID;
+
+	class SluiftClient {
+		public:
+			struct Event {
+				enum Type {
+					MessageType,
+					PresenceType,
+					PubSubEventType
+				};
+
+				Event(boost::shared_ptr<Message> stanza) : type(MessageType), stanza(stanza) {}
+				Event(boost::shared_ptr<Presence> stanza) : type(PresenceType), stanza(stanza) {}
+				Event(const JID& from, boost::shared_ptr<PubSubEventPayload> payload) : type(PubSubEventType), from(from), pubsubEvent(payload) {}
+
+				Type type;
+
+				// Message & Presence
+				boost::shared_ptr<Stanza> stanza;
+
+				// PubSubEvent
+				JID from;
+				boost::shared_ptr<PubSubEventPayload> pubsubEvent;
+			};
+
+			SluiftClient(
+					const JID& jid, 
+					const std::string& password, 
+					NetworkFactories* networkFactories, 
+					SimpleEventLoop* eventLoop, 
+					SluiftGlobals* globals);
+			~SluiftClient();
+
+			Client* getClient() {
+				return client;
+			}
+
+			ClientOptions& getOptions() {
+				return options;
+			}
+
+			void connect();
+			void connect(const std::string& host);
+			void waitConnected();
+			bool isConnected() const;
+
+			template<typename T>
+				Sluift::Response sendPubSubRequest(
+					IQ::Type type, const JID& jid, boost::shared_ptr<T> payload, int timeout) {
+				return sendRequest(client->getPubSubManager()->createRequest(
+							type, jid, payload), timeout);
+			}
+
+			template<typename REQUEST_TYPE>
+			Sluift::Response sendRequest(REQUEST_TYPE request, int timeout) {
+				boost::signals::scoped_connection c = request->onResponse.connect(
+						boost::bind(&SluiftClient::handleRequestResponse, this, _1, _2));
+				return doSendRequest(request, timeout);
+			}
+
+			template<typename REQUEST_TYPE>
+			Sluift::Response sendVoidRequest(REQUEST_TYPE request, int timeout) {
+				boost::signals::scoped_connection c = request->onResponse.connect(
+						boost::bind(&SluiftClient::handleRequestResponse, this, boost::shared_ptr<Payload>(), _1));
+				return doSendRequest(request, timeout);
+			}
+
+			void disconnect();
+			void setSoftwareVersion(const std::string& name, const std::string& version, const std::string& os);
+			boost::optional<SluiftClient::Event> getNextEvent(boost::optional<Event::Type> type, int timeout);
+			std::vector<XMPPRosterItem> getRoster();
+
+		private:
+			Sluift::Response doSendRequest(boost::shared_ptr<Request> request, int timeout);
+
+			void handleIncomingMessage(boost::shared_ptr<Message> stanza);
+			void handleIncomingPresence(boost::shared_ptr<Presence> stanza);
+			void handleIncomingPubSubEvent(const JID& from, boost::shared_ptr<PubSubEventPayload> event);
+			void handleInitialRosterPopulated();
+			void handleRequestResponse(boost::shared_ptr<Payload> response, boost::shared_ptr<ErrorPayload> error);
+			void handleDisconnected(const boost::optional<ClientError>& error);
+		
+		private:
+			NetworkFactories* networkFactories;
+			SimpleEventLoop* eventLoop;
+			SluiftGlobals* globals;
+			Client* client;
+			ClientOptions options;
+			ClientXMLTracer* tracer;
+			bool rosterReceived;
+			std::deque<Event> pendingEvents;
+			boost::optional<ClientError> disconnectedError;
+			bool requestResponseReceived;
+			boost::shared_ptr<Payload> requestResponse;
+			boost::shared_ptr<ErrorPayload> requestError;
+	};
+}
diff --git a/Sluift/SluiftGlobals.h b/Sluift/SluiftGlobals.h
new file mode 100644
index 0000000..03c1c1a
--- /dev/null
+++ b/Sluift/SluiftGlobals.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Sluift/LuaElementConvertors.h>
+#include <Swiften/EventLoop/SimpleEventLoop.h>
+#include <Swiften/Network/BoostNetworkFactories.h>
+
+namespace Swift {
+	struct SluiftGlobals {
+		SluiftGlobals() : networkFactories(&eventLoop) {}
+
+		int timeout;
+		bool debug;
+		LuaElementConvertors elementConvertor;
+		SimpleEventLoop eventLoop;
+		BoostNetworkFactories networkFactories;
+		int bootIndex;
+	};
+}
diff --git a/Sluift/Tests/ConnectTest.lua b/Sluift/Tests/ConnectTest.lua
new file mode 100644
index 0000000..0afa3fa
--- /dev/null
+++ b/Sluift/Tests/ConnectTest.lua
@@ -0,0 +1,6 @@
+-- Test connect with function parameter
+client = sluift.new_client(os.getenv("SLUIFT_JID"), os.getenv("SLUIFT_PASS"))
+x, y, z = client:connect(function (c) return 1, '2', true end)
+assert(x == 1)
+assert(y == '2')
+assert(z == true)
diff --git a/Sluift/Tests/DOMTest.lua b/Sluift/Tests/DOMTest.lua
new file mode 100644
index 0000000..0c31183
--- /dev/null
+++ b/Sluift/Tests/DOMTest.lua
@@ -0,0 +1,14 @@
+t = sluift.from_xml([[
+	<foo xmlns='http://swift.im/test' myattr1='myval1' myattr2='myval2'>
+		<bar myattr3='myval3'>
+			<baz/>
+		</bar>
+		Some Text
+		<bam myattr4='myval4'>
+			Some other text
+		</bam>
+	</foo>
+]])
+
+print(t)
+print(sluift.to_xml(t))
diff --git a/Sluift/Tests/FormTest.lua b/Sluift/Tests/FormTest.lua
new file mode 100644
index 0000000..813e05c
--- /dev/null
+++ b/Sluift/Tests/FormTest.lua
@@ -0,0 +1,73 @@
+--[[
+	Copyright (c) 2013 Remko Tronçon
+	Licensed under the GNU General Public License v3.
+	See Documentation/Licenses/GPLv3.txt for more information.
+--]]
+
+example_form = [[
+<x xmlns='jabber:x:data' type='form'>
+	<title>Bot Configuration</title>
+	<instructions>Fill out this form to configure your new bot!</instructions>
+	<field type='hidden' var='FORM_TYPE'>
+		<value>jabber:bot</value>
+	</field>
+	<field type='fixed'><value>Section 1: Bot Info</value></field>
+	<field type='text-single' label='The name of your bot' var='botname'/>
+	<field type='text-multi' label='Helpful description of your bot' var='description'/>
+	<field type='boolean' label='Public bot?' var='public'>
+		<required/>
+	</field>
+	<field type='text-private' label='Password for special access' var='password'/>
+	<field type='fixed'><value>Section 2: Features</value></field>
+	<field type='list-multi' label='What features will the bot support?' var='features'>
+		<option label='Contests'><value>contests</value></option>
+		<option label='News'><value>news</value></option>
+		<option label='Polls'><value>polls</value></option>
+		<option label='Reminders'><value>reminders</value></option>
+		<option label='Search'><value>search</value></option>
+		<value>news</value>
+		<value>search</value>
+	</field>
+	<field type='fixed'><value>Section 3: Subscriber List</value></field>
+	<field type='list-single' label='Maximum number of subscribers' var='maxsubs'>
+		<value>20</value>
+		<option label='10'><value>10</value></option>
+		<option label='20'><value>20</value></option>
+		<option label='30'><value>30</value></option>
+		<option label='50'><value>50</value></option>
+		<option label='100'><value>100</value></option>
+		<option label='None'><value>none</value></option>
+	</field>
+	<field type='fixed'><value>Section 4: Invitations</value></field>
+	<field type='jid-multi' label='People to invite' var='invitelist'>
+		<desc>Tell all your friends about your new bot!</desc>
+	</field>
+</x>]]
+
+form = sluift.from_xml(example_form)['data']
+print(form)
+
+-- Test form properties
+assert(form['title'] == 'Bot Configuration')
+
+-- Test boolean field
+public_field = form['fields'][5]
+assert(public_field['name'] == 'public')
+assert(type(public_field['value']) == 'boolean')
+assert(public_field['required'] == true)
+
+-- Test multi field
+features_field = form['fields'][8]
+assert(features_field['name'] == 'features')
+assert(type(features_field['values']) == 'table')
+assert(#features_field['values'] == 2)
+assert(features_field['values'][1] == 'news')
+assert(features_field['values'][2] == 'search')
+
+-- Test shortcut index
+assert(form['features']['name'] == 'features')
+assert(form['FORM_TYPE']['value'] == 'jabber:bot')
+
+-- Test response form
+print(form:create_submission())
+--print(sluift.to_xml({type = 'form', data = form}))
diff --git a/Sluift/boot.lua b/Sluift/boot.lua
new file mode 100644
index 0000000..ae8cc41
--- /dev/null
+++ b/Sluift/boot.lua
@@ -0,0 +1,381 @@
+--[[
+	Copyright (c) 2013 Remko Tronçon
+	Licensed under the GNU General Public License.
+	See the COPYING file for more information.
+--]]
+
+local Client = {}
+local PubSub = {}
+local PubSubNode = {}
+
+--------------------------------------------------------------------------------
+-- Utility methods
+--------------------------------------------------------------------------------
+
+local function merge_tables(...)
+	local result = {}
+	for _, table in ipairs({...}) do
+		for k, v in pairs(table) do
+			result[k] = v
+		end
+	end
+	return result
+end
+
+local function clone_table(table) 
+ return merge_tables(table)
+end
+
+local function parse_options(unnamed_parameters, arg1, arg2)
+	local options = {}
+	if type(arg1) == 'table' then
+		options = arg1
+		f = arg2
+	elseif type(arg1) == 'function' then
+		f = arg1
+	end
+	options.f = f or options.f
+	return clone_table(options)
+end
+
+
+local function table_value_tostring(value)
+	local result = tostring(value)
+	if type(value) == 'number' then return result
+	elseif type(value) == 'boolean' then return result
+	elseif type(value) == 'string' then return "'" .. result .. "'"
+	else return '<' .. result .. '>'
+	end
+end
+
+local function table_tostring(table, indent, accumulator)
+	local INDENT = '  '
+	local accumulator = accumulator or ''
+	local indent = indent or ''
+	accumulator = accumulator .. '{'
+	local is_first = true
+	for key, value in pairs(table) do
+		if type(value) ~= 'function' then
+			if not is_first then
+				accumulator = accumulator .. ','
+			end
+			is_first = false
+			accumulator = accumulator .. '\n' .. indent .. INDENT .. '[' .. table_value_tostring(key) .. '] = '
+			if type(value) == 'table' then
+				accumulator = table_tostring(value, indent .. INDENT, accumulator)
+			else
+				accumulator = accumulator .. table_value_tostring(value)
+			end
+		end
+	end
+	if not is_first then
+		accumulator = accumulator .. '\n' .. indent
+	end
+	accumulator = accumulator .. '}'
+	return accumulator
+end
+
+local function tprint(table)
+	print(table_tostring(table))
+end
+
+local function register_table_tostring(table)
+	if type(table) == 'table' then
+		local metatable = getmetatable(table)
+		if not metatable then
+			metatable = {}
+			setmetatable(table, metatable)
+		end
+		metatable.__tostring = table_tostring
+	end
+	return table
+end
+
+local function get_by_type(table, typ)
+	for _, v in ipairs(table) do
+		if v['_type'] == typ then
+			return v
+		end
+ end
+end
+
+local function register_get_by_type_index(table)
+	if type(table) == 'table' then
+		local metatable = getmetatable(table)
+		if not metatable then
+			metatable = {}
+			setmetatable(table, metatable)
+		end
+		metatable.__index = get_by_type
+	end
+	return table
+end
+
+--------------------------------------------------------------------------------
+-- Client
+--------------------------------------------------------------------------------
+
+function Client.connect (client, ...)
+	local options = parse_options({}, ...)
+	local f = options.f
+	client:async_connect(options)
+	client:wait_connected()
+	if f then
+		local result = { xpcall(function() return f(client) end, debug.traceback) }
+		client:disconnect()
+		if result[1] then
+			table.remove(result, 1)
+			return unpack(result)
+		else
+			error(result[2])
+		end
+	end
+	return true
+end
+
+function Client.events (client, options)
+	local function client_events_iterator(s)
+		return s['client']:get_next_event(s['options'])
+	end
+	return client_events_iterator, {client = client, options = options}
+end
+
+function Client.for_each_event (client, ...)
+	local options = parse_options({}, ...)
+	if not type(options.f) == 'function' then error('Expected function') end
+	for event in client:events(options) do
+		local result = options.f(event)
+		if result then
+			return result
+		end
+	end
+end
+
+for method, event_type in pairs({message = 'message', presence = 'presence', pubsub_event = 'pubsub'}) do
+	Client['for_each_' .. method] = function (client, ...)
+		local options = parse_options({}, ...)
+		options['type'] = event_type
+		return client:for_each_event (options)
+	end
+end
+
+for method, event_type in pairs({messages = 'message', pubsub_events = 'pubsub'}) do
+	Client[method] = function (client, ...)
+		local options = parse_options({}, ...)
+		options['type'] = event_type
+		return client:events (options)
+	end
+end
+
+-- Register get_* convenience methods for some type of queries
+for _, query_type in ipairs({'software_version', 'disco_items', 'xml', 'dom', 'vcard'}) do
+	Client['get_' .. query_type] = function (client, options)
+		options = options or {}
+		if type(options) ~= 'table' then error('Invalid options: ' .. options) end 
+		options['query'] = merge_tables({_type = query_type}, options['query'] or {})
+		return client:get(options)
+	end
+end
+
+function Client.pubsub (client, jid)
+	local result = { client = client, jid = jid }
+	setmetatable(result, PubSub)
+	return result
+end
+
+--------------------------------------------------------------------------------
+-- PubSub
+--------------------------------------------------------------------------------
+
+PubSub.__index = PubSub
+
+local function process_pubsub_event (event)
+	if event._type == 'pubsub_event_items' then
+		-- Add 'item' shortcut to payload of first item
+		event.item = event.items and event.items[1] and 
+			event.items[1].data and event.items[1].data[1]
+	end
+end
+
+function PubSub.list_nodes (service, options)
+	return service.client:get_disco_items(merge_tables({to = service.jid}, options))
+end
+
+function PubSub.node (service, node)
+	local result = { client = service.client, jid = service.jid, node = node }
+	setmetatable(result, PubSubNode)
+	return result
+end
+
+local simple_pubsub_queries = {
+	get_default_configuration = 'pubsub_owner_default',
+	get_subscriptions = 'pubsub_subscriptions',
+	get_affiliations = 'pubsub_affiliations',
+	get_default_subscription_options = 'pubsub_default',
+}
+for method, query_type in pairs(simple_pubsub_queries) do
+	PubSub[method] = function (service, options)
+		options = options or {}
+		return service.client:query_pubsub(merge_tables(
+			{ type = 'get', to = service.jid, query = { _type = query_type } },
+			options))
+	end
+end
+
+--------------------------------------------------------------------------------
+-- PubSubNode
+--------------------------------------------------------------------------------
+
+PubSubNode.__index = PubSubNode
+
+local function pubsub_node_configuration_to_form(configuration)
+	if not configuration then
+		return
+	end
+	local fields = { {name = 'form_type', value = 'http://jabber.org/protocol/pubsub#node_config'} }
+	for var, value in pairs(configuration) do
+		fields[#fields+1] = { name = var, value = value }
+	end
+	return { type = "submit", fields = fields }
+end
+
+function PubSubNode.list_items (node, options)
+	return node.client:get_disco_items(merge_tables({to = node.jid, query = { node = node.node }}, options))
+end
+
+local simple_pubsub_node_queries = {
+	get_configuration = 'pubsub_owner_configure',
+	get_subscriptions = 'pubsub_subscriptions',
+	get_affiliations = 'pubsub_affiliations',
+	get_items = 'pubsub_items',
+	get_default_subscription_options = 'pubsub_default',
+}
+for method, query_type in pairs(simple_pubsub_node_queries) do
+	PubSubNode[method] = function (node, options)
+		return node.client:query_pubsub(merge_tables({ 
+			type = 'get', to = node.jid, query = {
+					_type = query_type, node = node.node 
+			}}, options))
+	end
+end
+
+function PubSubNode.create (node, options)
+	options = options or {}
+	local configure
+	if options['configuration'] then
+		configure = { data = pubsub_node_configuration_to_form(options['configuration']) }
+	end
+	return node.client:query_pubsub(merge_tables(
+		{ type = 'set', to = node.jid, query = { 
+				_type = 'pubsub_create', node = node.node, configure = configure }
+		}, options))
+end
+
+function PubSubNode.delete (node, options)
+	options = options or {}
+	local redirect
+	if options['redirect'] then
+		redirect = {uri = options['redirect']}
+	end
+	return node.client:query_pubsub(merge_tables({ type = 'set', to = node.jid, query = { 
+			_type = 'pubsub_owner_delete', node = node.node, redirect = redirect 
+		}}, options))
+end
+
+function PubSubNode.set_configuration(node, options)
+	options = options or {}
+	local configuration = pubsub_node_configuration_to_form(options['configuration'])
+	return node.client:query_pubsub(merge_tables(
+		{ type = 'set', to = node.jid, query = { 
+				_type = 'pubsub_owner_configure', node = node.node, data = configuration }
+		}, options))
+end
+
+function PubSubNode.subscribe(node, options)
+	options = options or {}
+	return node.client:query_pubsub(merge_tables(
+		{ type = 'set', to = node.jid, query = { 
+				_type = 'pubsub_subscribe', node = node.node, jid = options['jid'] }
+		}, options))
+end
+
+function PubSubNode.unsubscribe(node, options)
+	options = options or {}
+	return node.client:query_pubsub(merge_tables(
+		{ type = 'set', to = node.jid, query = { 
+				_type = 'pubsub_unsubscribe', node = node.node, jid = options['jid'] }
+		}, options))
+end
+
+function PubSubNode.get_subscription_options (node, options)
+	return node.client:query_pubsub(merge_tables(
+		{ type = 'get', to = node.jid, query = { 
+				_type = 'pubsub_options', node = node.node, jid = options['jid'] }
+		}, options))
+end
+
+function PubSubNode.publish(node, ...)
+	local options = parse_options({}, ...)
+	local items = options.items or {}
+	if options.item then
+		if type(options.item) == 'string' or options.item._type then
+			items = {{id = options.id, data = { options.item } }}
+			options.id = nil 
+		else
+			items = { options.item }
+		end
+		options.item = nil
+	end
+	return node.client:query_pubsub(merge_tables(
+		{ type = 'set', to = node.jid, query = { 
+				_type = 'pubsub_publish', node = node.node, items = items }
+		}, options))
+end
+
+function PubSubNode.retract(node, options)
+	options = options or {}
+	local item_ids = options['items']
+	item_ids = item_ids or { options['item'] }
+	local items = {}
+	for _, item_id in ipairs(item_ids) do
+		items[#items+1] = { id = item_id }
+	end
+	return node.client:query_pubsub(merge_tables(
+		{ type = 'set', to = node.jid, query = { 
+				_type = 'pubsub_retract', node = node.node, items = items, notify = options['notify']
+		}}, options))
+end
+
+function PubSubNode.purge(node, options)
+	options = options or {}
+	return node.client:query_pubsub(merge_tables(
+		{ type = 'set', to = node.jid, query = { 
+				_type = 'pubsub_owner_purge', node = node.node
+		}}, options))
+end
+
+--------------------------------------------------------------------------------
+-- Service discovery
+--------------------------------------------------------------------------------
+
+local disco = {
+	features = {
+		DISCO_INFO = 'http://jabber.org/protocol/disco#info',
+		USER_LOCATION = 'http://jabber.org/protocol/geoloc',
+		USER_TUNE = 'http://jabber.org/protocol/tune',
+		USER_AVATAR_METADATA = 'urn:xmpp:avatar:metadata',
+		USER_ACTIVITY = 'http://jabber.org/protocol/activity',
+		USER_PROFILE = 'urn:xmpp:tmp:profile'
+	}
+}
+
+--------------------------------------------------------------------------------
+
+return {
+	Client = Client,
+	register_table_tostring = register_table_tostring,
+	register_get_by_type_index = register_get_by_type_index,
+	process_pubsub_event = process_pubsub_event,
+	tprint = tprint,
+	disco = disco,
+}
diff --git a/Sluift/client.cpp b/Sluift/client.cpp
new file mode 100644
index 0000000..6d8bee8
--- /dev/null
+++ b/Sluift/client.cpp
@@ -0,0 +1,517 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/SluiftClient.h>
+#include <Swiften/JID/JID.h>
+#include <Swiften/Elements/SoftwareVersion.h>
+#include <Swiften/Elements/Message.h>
+#include <Swiften/Elements/Presence.h>
+#include <Swiften/Elements/RawXMLPayload.h>
+#include <Swiften/Elements/RosterItemPayload.h>
+#include <Swiften/Elements/RosterPayload.h>
+#include <Swiften/Elements/DiscoInfo.h>
+#include <Swiften/Disco/ClientDiscoManager.h>
+#include <Swiften/Queries/GenericRequest.h>
+#include <Swiften/Presence/PresenceSender.h>
+#include <Swiften/Roster/XMPPRoster.h>
+#include <Swiften/Roster/SetRosterRequest.h>
+#include <Swiften/Presence/SubscriptionManager.h>
+#include <Swiften/Roster/XMPPRosterItem.h>
+#include <boost/assign/list_of.hpp>
+#include <Sluift/Watchdog.h>
+#include <Swiften/Queries/Requests/GetSoftwareVersionRequest.h>
+#include <Sluift/Lua/FunctionRegistration.h>
+#include <Swiften/Base/foreach.h>
+#include <Sluift/Lua/Check.h>
+#include <Sluift/Lua/Value.h>
+#include <Sluift/Lua/Exception.h>
+#include <Sluift/Lua/LuaUtils.h>
+#include <Sluift/globals.h>
+#include <iostream>
+
+using namespace Swift;
+
+static const std::string SLUIFT_CLIENT = Lua::FunctionRegistry::getMetaTableNameForType("Client");
+
+static inline SluiftClient* getClient(lua_State* L) {
+	return *Lua::checkUserData<SluiftClient>(L, 1, SLUIFT_CLIENT.c_str());
+}
+
+SLUIFT_LUA_FUNCTION(Client, async_connect) {
+	SluiftClient* client = getClient(L);
+
+	std::string host;
+	if (lua_istable(L, 2)) {
+		if (boost::optional<std::string> hostString = Lua::getStringField(L, 2, "host")) {
+			host = *hostString;
+		}
+	}
+	if (host.empty()) {
+		client->connect();
+	}
+	else {
+		client->connect(host);
+	}
+	return 0;
+}
+
+SLUIFT_LUA_FUNCTION(Client, wait_connected) {
+	getClient(L)->waitConnected();
+	return 0;
+}
+
+SLUIFT_LUA_FUNCTION(Client, is_connected) {
+	lua_pushboolean(L, getClient(L)->isConnected());
+	return 1;
+}
+
+SLUIFT_LUA_FUNCTION(Client, disconnect) {
+	getClient(L)->disconnect();
+	return 0;
+}
+
+SLUIFT_LUA_FUNCTION(Client, set_version) {
+	Sluift::globals.eventLoop.runOnce();
+	SluiftClient* client = getClient(L);
+	if (boost::shared_ptr<SoftwareVersion> version = boost::dynamic_pointer_cast<SoftwareVersion>(Sluift::globals.elementConvertor.convertFromLuaUntyped(L, 2, "software_version"))) {
+		client->setSoftwareVersion(version->getName(), version->getVersion(), version->getOS());
+	}
+	return 0;
+}
+
+SLUIFT_LUA_FUNCTION(Client, get_contacts) {
+	Sluift::globals.eventLoop.runOnce();
+
+	SluiftClient* client = getClient(L);
+	Lua::Table contactsTable;
+	foreach(const XMPPRosterItem& item, client->getRoster()) {
+		std::string subscription;
+		switch(item.getSubscription()) {
+			case RosterItemPayload::None: subscription = "none"; break;
+			case RosterItemPayload::To: subscription = "to"; break;
+			case RosterItemPayload::From: subscription = "from"; break;
+			case RosterItemPayload::Both: subscription = "both"; break;
+			case RosterItemPayload::Remove: subscription = "remove"; break;
+		}
+		Lua::Table itemTable = boost::assign::map_list_of
+			("jid", boost::make_shared<Lua::Value>(item.getJID().toString()))
+			("name", boost::make_shared<Lua::Value>(item.getName()))
+			("subscription", boost::make_shared<Lua::Value>(subscription))
+			("groups", boost::make_shared<Lua::Value>(std::vector<Lua::Value>(item.getGroups().begin(), item.getGroups().end())));
+		contactsTable[item.getJID().toString()] = boost::make_shared<Lua::Value>(itemTable);
+	}
+	pushValue(L, contactsTable);
+	Lua::registerTableToString(L, -1);
+	return 1;
+}
+
+SLUIFT_LUA_FUNCTION(Client, send_message) {
+	Sluift::globals.eventLoop.runOnce();
+	JID to;
+	std::string body;
+	int index = 2;
+	Message::Type type = Message::Chat;
+	if (lua_isstring(L, index)) {
+		to = std::string(lua_tostring(L, index));
+		++index;
+		if (!lua_isstring(L, index)) {
+			std::string body = lua_tostring(L, index);
+			++index;
+		}
+	}
+	if (lua_istable(L, index)) {
+		if (boost::optional<std::string> value = Lua::getStringField(L, index, "to")) {
+			to = *value;
+		}
+
+		if (boost::optional<std::string> value = Lua::getStringField(L, index, "body")) {
+			body = *value;
+		}
+
+		if (boost::optional<std::string> value = Lua::getStringField(L, index, "type")) {
+			if (*value == "normal") {
+				type = Message::Normal;
+			}
+			else if (*value == "chat") {
+				type = Message::Chat;
+			}
+			else if (*value == "error") {
+				type = Message::Error;
+			}
+			else if (*value == "groupchat") {
+				type = Message::Groupchat;
+			}
+			else if (*value == "headline") {
+				type = Message::Headline;
+			}
+		}
+	}
+
+	if (!to.isValid()) {
+		throw Lua::Exception("Missing 'to'");
+	}
+	if (body.empty()) {
+		throw Lua::Exception("Missing 'body'");
+	}
+
+	Message::ref message = boost::make_shared<Message>();
+	message->setTo(to);
+	message->setBody(body);
+	message->setType(type);
+	getClient(L)->getClient()->sendMessage(message);
+	return 0;
+}
+
+SLUIFT_LUA_FUNCTION(Client, send_presence) {
+	Sluift::globals.eventLoop.runOnce();
+	boost::shared_ptr<Presence> presence = boost::make_shared<Presence>();
+	
+	int index = 2;
+	if (lua_isstring(L, index)) {
+		presence->setStatus(lua_tostring(L, index));
+		++index;
+	}
+	if (lua_istable(L, index)) {
+		if (boost::optional<std::string> value = Lua::getStringField(L, index, "to")) {
+			presence->setTo(*value);
+		}
+		if (boost::optional<std::string> value = Lua::getStringField(L, index, "status")) {
+			presence->setStatus(*value);
+		}
+		if (boost::optional<int> value = Lua::getIntField(L, index, "priority")) {
+			presence->setPriority(*value);
+		}
+		if (boost::optional<std::string> value = Lua::getStringField(L, index, "type")) {
+			if (*value == "available") {
+				presence->setType(Presence::Available);
+			}
+			else if (*value == "error") {
+				presence->setType(Presence::Error);
+			}
+			else if (*value == "probe") {
+				presence->setType(Presence::Probe);
+			}
+			else if (*value == "subscribe") {
+				presence->setType(Presence::Subscribe);
+			}
+			else if (*value == "subscribed") {
+				presence->setType(Presence::Subscribed);
+			}
+			else if (*value == "unavailable") {
+				presence->setType(Presence::Unavailable);
+			}
+			else if (*value == "unsubscribe") {
+				presence->setType(Presence::Unsubscribe);
+			}
+			else if (*value == "unsubscribed") {
+				presence->setType(Presence::Unsubscribed);
+			}
+		}
+	}
+
+	getClient(L)->getClient()->getPresenceSender()->sendPresence(presence);
+	lua_pushvalue(L, 1);
+	return 0;
+}
+
+static int sendQuery(lua_State* L, IQ::Type type) {
+	SluiftClient* client = getClient(L);
+
+	JID to;
+	if (boost::optional<std::string> toString = Lua::getStringField(L, 2, "to")) {
+		to = JID(*toString);
+	}
+
+	int timeout = Sluift::globals.timeout;
+	if (boost::optional<int> timeoutInt = Lua::getIntField(L, 2, "timeout")) {
+		timeout = *timeoutInt;
+	}
+
+	boost::shared_ptr<Payload> payload;
+	lua_getfield(L, 2, "query");
+	if (lua_type(L, -1) == LUA_TTABLE) {
+		payload = Sluift::globals.elementConvertor.convertFromLua(L, -1);
+	}
+	else if (lua_type(L, -1) == LUA_TSTRING) {
+		payload = boost::make_shared<RawXMLPayload>(Lua::checkString(L, -1));
+	}
+	lua_pop(L, 1);
+
+	return client->sendRequest(
+		boost::make_shared< GenericRequest<Payload> >(type, to, payload, client->getClient()->getIQRouter()), timeout).convertToLuaResult(L);
+}
+
+#define DISPATCH_PUBSUB_PAYLOAD(payloadType, container, response) \
+	else if (boost::shared_ptr<payloadType> p = boost::dynamic_pointer_cast<payloadType>(payload)) { \
+		return client->sendPubSubRequest(type, to, p, timeout).convertToLuaResult(L); \
+	}
+
+SLUIFT_LUA_FUNCTION(Client, query_pubsub) {
+	SluiftClient* client = getClient(L);
+
+	JID to;
+	if (boost::optional<std::string> toString = Lua::getStringField(L, 2, "to")) {
+		to = JID(*toString);
+	}
+
+	int timeout = Sluift::globals.timeout;
+	if (boost::optional<int> timeoutInt = Lua::getIntField(L, 2, "timeout")) {
+		timeout = *timeoutInt;
+	}
+
+	IQ::Type type;
+	if (boost::optional<std::string> queryType = Lua::getStringField(L, 2, "type")) {
+		if (*queryType == "get") {
+			type = IQ::Get;
+		}
+		else if (*queryType == "set") {
+			type = IQ::Set;
+		}
+		else {
+			throw Lua::Exception("Illegal query type: '" + *queryType + "'");
+		}
+	}
+	else {
+		throw Lua::Exception("Missing query type");
+	}
+
+	lua_getfield(L, 2, "query");
+	if (!lua_istable(L, -1)) {
+		throw Lua::Exception("Missing/incorrect query");
+	}
+	boost::shared_ptr<Payload> payload = Sluift::globals.elementConvertor.convertFromLua(L, -1);
+
+	if (false) { }
+	SWIFTEN_PUBSUB_FOREACH_PUBSUB_PAYLOAD_TYPE(DISPATCH_PUBSUB_PAYLOAD)
+	else {
+		throw Lua::Exception("Incorrect PubSub payload");
+	}
+}
+
+
+SLUIFT_LUA_FUNCTION(Client, get) {
+	return sendQuery(L, IQ::Get);
+}
+
+SLUIFT_LUA_FUNCTION(Client, set) {
+	return sendQuery(L, IQ::Set);
+}
+
+SLUIFT_LUA_FUNCTION(Client, send) {
+	Sluift::globals.eventLoop.runOnce();
+
+	getClient(L)->getClient()->sendData(std::string(Lua::checkString(L, 2)));
+	lua_pushvalue(L, 1);
+	return 0;
+}
+
+SLUIFT_LUA_FUNCTION(Client, set_options) {
+	SluiftClient* client = getClient(L);
+	Lua::checkType(L, 2, LUA_TTABLE);
+	lua_getfield(L, 2, "ack");
+	if (!lua_isnil(L, -1)) {
+		client->getOptions().useAcks = lua_toboolean(L, -1);
+	}
+	lua_getfield(L, 2, "compress");
+	if (!lua_isnil(L, -1)) {
+		client->getOptions().useStreamCompression = lua_toboolean(L, -1);
+	}
+	lua_getfield(L, 2, "tls");
+	if (!lua_isnil(L, -1)) {
+		bool useTLS = lua_toboolean(L, -1);
+		client->getOptions().useTLS = (useTLS ? ClientOptions::UseTLSWhenAvailable : ClientOptions::NeverUseTLS);
+	}
+	lua_pushvalue(L, 1);
+	return 0;
+}
+
+static void pushEvent(lua_State* L, const SluiftClient::Event& event) {
+	switch (event.type) {
+		case SluiftClient::Event::MessageType: {
+			Message::ref message = boost::dynamic_pointer_cast<Message>(event.stanza);
+			Lua::Table result = boost::assign::map_list_of
+				("type", boost::make_shared<Lua::Value>(std::string("message")))
+				("from", boost::make_shared<Lua::Value>(message->getFrom().toString()))
+				("body", boost::make_shared<Lua::Value>(message->getBody()));
+			Lua::pushValue(L, result);
+			Lua::registerTableToString(L, -1);
+			break;
+		}
+		case SluiftClient::Event::PresenceType: {
+			Presence::ref presence = boost::dynamic_pointer_cast<Presence>(event.stanza);
+			Lua::Table result = boost::assign::map_list_of
+				("type", boost::make_shared<Lua::Value>(std::string("presence")))
+				("from", boost::make_shared<Lua::Value>(presence->getFrom().toString()))
+				("status", boost::make_shared<Lua::Value>(presence->getStatus()));
+			Lua::pushValue(L, result);
+			if (!presence->getPayloads().empty()) {
+				const std::vector<boost::shared_ptr<Payload> > payloads = presence->getPayloads();
+				lua_createtable(L, boost::numeric_cast<int>(payloads.size()), 0);
+				for (size_t i = 0; i < payloads.size(); ++i) {
+					Sluift::globals.elementConvertor.convertToLua(L, payloads[i]);
+					lua_rawseti(L, -2, boost::numeric_cast<int>(i+1));
+				}
+				Lua::registerGetByTypeIndex(L, -1);
+				lua_setfield(L, -2, "payloads");
+			}
+			Lua::registerTableToString(L, -1);
+			break;
+		}
+		case SluiftClient::Event::PubSubEventType: {
+			Sluift::globals.elementConvertor.convertToLua(L, event.pubsubEvent);
+			lua_pushstring(L, "pubsub");
+			lua_setfield(L, -2, "type");
+			lua_pushstring(L, event.from.toString().c_str());
+			lua_setfield(L, -2, "from");
+
+			lua_rawgeti(L, LUA_REGISTRYINDEX, Sluift::globals.bootIndex);
+			lua_getfield(L, -1, "process_pubsub_event");
+			lua_pushvalue(L, -3);
+			lua_call(L, 1, 0);
+			lua_pop(L, 1);
+		}
+	}
+}
+
+SLUIFT_LUA_FUNCTION(Client, get_next_event) {
+	Sluift::globals.eventLoop.runOnce();
+	SluiftClient* client = getClient(L);
+
+	int timeout = Sluift::globals.timeout;
+	boost::optional<SluiftClient::Event::Type> type;
+	if (lua_istable(L, 2)) {
+		if (boost::optional<std::string> typeString = Lua::getStringField(L, 2, "type")) {
+			if (*typeString == "message") {
+				type = SluiftClient::Event::MessageType;
+			}
+			else if (*typeString == "presence") {
+				type = SluiftClient::Event::PresenceType;
+			}
+			else if (*typeString == "pubsub") {
+				type = SluiftClient::Event::PubSubEventType;
+			}
+		}
+		if (boost::optional<int> timeoutInt = Lua::getIntField(L, 2, "timeout")) {
+			timeout = *timeoutInt;
+		}
+	}
+
+	if (boost::optional<SluiftClient::Event> event = client->getNextEvent(type, timeout)) {
+		pushEvent(L, *event);
+	}
+	else {
+		lua_pushnil(L);
+	}
+	return 1;
+}
+
+
+SLUIFT_LUA_FUNCTION(Client, add_contact) {
+	Sluift::globals.eventLoop.runOnce();
+	SluiftClient* client = getClient(L);
+	RosterItemPayload item;
+	if (lua_type(L, 2) == LUA_TTABLE) {
+		lua_getfield(L, 2, "jid");
+		const char* rawJID = lua_tostring(L, -1);
+		if (rawJID) {
+			item.setJID(std::string(rawJID));
+		}
+		lua_getfield(L, 2, "name");
+		const char* rawName = lua_tostring(L, -1);
+		if (rawName) {
+			item.setName(rawName);
+		}
+		lua_getfield(L, 2, "groups");
+		if (!lua_isnil(L, -1)) {
+			if (lua_type(L, -1) == LUA_TTABLE) {
+				for (size_t i = 1; i <= lua_objlen(L, -1); ++i) {
+					lua_rawgeti(L, -1, boost::numeric_cast<int>(i));
+					const char* rawGroup = lua_tostring(L, -1);
+					if (rawGroup) {
+						item.addGroup(rawGroup);
+					}
+					lua_pop(L, 1);
+				}
+			}
+			else {
+				throw Lua::Exception("Groups should be a table");
+			}
+		}
+	}
+	else {
+		item.setJID(Lua::checkString(L, 2));
+	}
+
+	client->getRoster();
+	if (!client->getClient()->getRoster()->containsJID(item.getJID())) {
+		RosterPayload::ref roster = boost::make_shared<RosterPayload>();
+		roster->addItem(item);
+
+		Sluift::Response response = client->sendVoidRequest(
+			SetRosterRequest::create(roster, client->getClient()->getIQRouter()), -1);
+		if (response.error) {
+			return response.convertToLuaResult(L);
+		}
+	}
+	client->getClient()->getSubscriptionManager()->requestSubscription(item.getJID());
+	lua_pushboolean(L, true);
+	return 1;
+}
+
+SLUIFT_LUA_FUNCTION(Client, remove_contact) {
+	Sluift::globals.eventLoop.runOnce();
+	SluiftClient* client = getClient(L);
+	JID jid(Lua::checkString(L, 2));
+
+	RosterPayload::ref roster = boost::make_shared<RosterPayload>();
+	roster->addItem(RosterItemPayload(JID(Lua::checkString(L, 2)), "", RosterItemPayload::Remove));
+		
+	return client->sendVoidRequest(
+		SetRosterRequest::create(roster, client->getClient()->getIQRouter()), -1).convertToLuaResult(L);
+}
+
+SLUIFT_LUA_FUNCTION(Client, confirm_subscription) {
+	Sluift::globals.eventLoop.runOnce();
+	SluiftClient* client = getClient(L);
+	JID jid(Lua::checkString(L, 2));
+	client->getClient()->getSubscriptionManager()->confirmSubscription(jid);
+	return 0;
+}
+
+SLUIFT_LUA_FUNCTION(Client, cancel_subscription) {
+	Sluift::globals.eventLoop.runOnce();
+	SluiftClient* client = getClient(L);
+	JID jid(Lua::checkString(L, 2));
+	client->getClient()->getSubscriptionManager()->cancelSubscription(jid);
+	return 0;
+}
+
+SLUIFT_LUA_FUNCTION(Client, set_disco_info) {
+	SluiftClient* client = getClient(L);
+	if (!lua_istable(L, 2)) {
+		throw Lua::Exception("Missing disco info");
+	}
+	if (boost::shared_ptr<DiscoInfo> discoInfo = boost::dynamic_pointer_cast<DiscoInfo>(Sluift::globals.elementConvertor.convertFromLuaUntyped(L, 2, "disco_info"))) {
+		client->getClient()->getDiscoManager()->setDiscoInfo(*discoInfo);
+	}
+	else {
+		throw Lua::Exception("Illegal disco info");
+	}
+	return 0;
+}
+
+SLUIFT_LUA_FUNCTION(Client, set_caps_node) {
+	SluiftClient* client = getClient(L);
+	std::string node(Lua::checkString(L, 2));
+	client->getClient()->getDiscoManager()->setCapsNode(Lua::checkString(L, 2));
+	return 0;
+}
+
+SLUIFT_LUA_FUNCTION(Client, __gc) {
+	SluiftClient* client = getClient(L);
+	delete client;
+	return 0;
+}
diff --git a/Sluift/globals.h b/Sluift/globals.h
new file mode 100644
index 0000000..3e7e1c9
--- /dev/null
+++ b/Sluift/globals.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Sluift/SluiftGlobals.h>
+
+namespace Swift {
+	namespace Sluift {
+		extern SluiftGlobals globals;
+	}
+}
diff --git a/Sluift/linit.c b/Sluift/linit.c
index 73f0522..8507609 100644
--- a/Sluift/linit.c
+++ b/Sluift/linit.c
@@ -3,35 +3,6 @@
 #include <lauxlib.h>
 #include "sluift.h"
 
-// A built-in table print function
-// From: http://lua-users.org/wiki/TableSerialization
-static const char tprint[] = 
-	"function tprint (tt, indent, done)\n"
-	"  done = done or {}\n"
-	"  indent = indent or 0\n"
-	"  if type(tt) == \"table\" then\n"
-	"    for key, value in pairs (tt) do\n"
-	"      io.write(string.rep (\" \", indent)) -- indent it\n"
-	"      if type (value) == \"table\" and not done [value] then\n"
-	"        done [value] = true\n"
-	"        io.write(string.format(\"[%s] => table\\n\", tostring (key)));\n"
-	"        io.write(string.rep (\" \", indent+4)) -- indent it\n"
-	"        io.write(\"(\\n\");\n"
-	"        tprint (value, indent + 7, done)\n"
-	"        io.write(string.rep (\" \", indent+4)) -- indent it\n"
-	"        io.write(\")\\n\");\n"
-	"      else\n"
-	"        io.write(string.format(\"[%s] => %s\\n\",\n"
-	"            tostring (key), tostring(value)))\n"
-	"      end\n"
-	"    end\n"
-	"  elseif type(tt) == \"nil\" then\n"
-	"    io.write(\"nil\\n\")\n"
-	"  else\n"
-	"    io.write(tt .. \"\\n\")\n"
-	"  end\n"
-	"end\n";
-
 static const luaL_Reg lualibs[] = {
   {"", luaopen_base},
   {LUA_LOADLIBNAME, luaopen_package},
@@ -53,8 +24,4 @@ LUALIB_API void luaL_openlibs (lua_State *L) {
     lua_pushstring(L, lib->name);
     lua_call(L, 1, 0);
   }
-	if (luaL_dostring(L, tprint) != 0) {
-		fprintf(stderr, "%s\n", lua_tostring(L, -1));
-		lua_pop(L, 1);	
-	}
 }
diff --git a/Sluift/sluift.cpp b/Sluift/sluift.cpp
index 722fb54..e6096a0 100644
--- a/Sluift/sluift.cpp
+++ b/Sluift/sluift.cpp
@@ -4,732 +4,277 @@
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
 
-#include "sluift.h"
-#include <lauxlib.h>
+#include <Sluift/sluift.h>
+
+#include <lua.hpp>
 
-#include <iostream>
 #include <string>
-#include <deque>
-#include <boost/assign/list_of.hpp>
+#include <boost/bind.hpp>
 #include <boost/numeric/conversion/cast.hpp>
-
-#include <Swiften/Base/foreach.h>
-#include <Swiften/Swiften.h>
+#include <boost/assign/list_of.hpp>
 
 #include "Watchdog.h"
-#include "ResponseSink.h"
-#include "Lua/Value.h"
-#include "ClientHelpers.h"
+#include <Sluift/Lua/Check.h>
+#include <Sluift/SluiftClient.h>
+#include <Sluift/globals.h>
+#include <Sluift/Lua/Exception.h>
+#include <Sluift/Lua/FunctionRegistration.h>
+#include <Swiften/Base/sleep.h>
+#include <Swiften/Base/foreach.h>
+#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h>
+#include <Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h>
+#include <Swiften/Serializer/PayloadSerializer.h>
+#include <Sluift/Lua/Debug.h>
+#include <Swiften/StringCodecs/Base64.h>
+#include <Swiften/StringCodecs/Hexify.h>
+#include <Swiften/Crypto/CryptoProvider.h>
+#include <Swiften/Crypto/PlatformCryptoProvider.h>
 
 using namespace Swift;
 
-#define SLUIFT_CLIENT "SluiftClient*"
-
-/*******************************************************************************
- * Forward declarations
- ******************************************************************************/
-
-static bool debug = false;
-static int globalTimeout = 30000;
-
-/*******************************************************************************
- * Helper classes
- ******************************************************************************/
-
-static SimpleEventLoop eventLoop;
-static BoostNetworkFactories networkFactories(&eventLoop);
-
-
-class SluiftClient {
-	public:
-		SluiftClient(const JID& jid, const std::string& password, lua_State* L) : L(L), tracer(NULL) {
-			client = new Client(jid, password, &networkFactories);
-			client->setAlwaysTrustCertificates();
-			client->onDisconnected.connect(boost::bind(&SluiftClient::handleDisconnected, this, _1));
-			client->onMessageReceived.connect(boost::bind(&SluiftClient::handleIncomingEvent, this, _1));
-			client->onPresenceReceived.connect(boost::bind(&SluiftClient::handleIncomingEvent, this, _1));
-			client->getRoster()->onInitialRosterPopulated.connect(boost::bind(&SluiftClient::handleInitialRosterPopulated, this));
-			if (debug) {
-				tracer = new ClientXMLTracer(client);
-			}
-		}
-
-		~SluiftClient() {
-			delete tracer;
-			delete client;
-		}
-
-		Client* getClient() {
-			return client;
-		}
-
-		ClientOptions& getOptions() {
-			return options;
-		}
-
-		void connect() {
-			rosterReceived = false;
-			client->connect(options);
-		}
-
-		void connect(const std::string& host) {
-			rosterReceived = false;
-			options.manualHostname = host;
-			client->connect(options);
-		}
-
-		void waitConnected() {
-			Watchdog watchdog(globalTimeout, networkFactories.getTimerFactory());
-			while (!watchdog.getTimedOut() && client->isActive() && !client->isAvailable()) {
-				eventLoop.runUntilEvents();
-			}
-			if (watchdog.getTimedOut()) {
-				client->disconnect();
-				luaL_error(L, "Timeout while connecting");
-			}
-		}
-
-		bool isConnected() const {
-			return client->isAvailable();
-		}
-
-		void sendMessage(const JID& to, const std::string& body) {
-			Message::ref message = boost::make_shared<Message>();
-			message->setTo(to);
-			message->setBody(body);
-			client->sendMessage(message);
-		}
-
-		void sendPresence(const std::string& status) {
-			client->sendPresence(boost::make_shared<Presence>(status));
-		}
-
-		boost::optional<std::string> sendQuery(const JID& jid, IQ::Type type, const std::string& data, int timeout) {
-			rawRequestResponse.reset();
-			RawRequest::ref request = RawRequest::create(type, jid, data, client->getIQRouter());
-			boost::signals::scoped_connection c = request->onResponse.connect(boost::bind(&SluiftClient::handleRawRequestResponse, this, _1));
-			request->send();
-
-			Watchdog watchdog(timeout, networkFactories.getTimerFactory());
-			while (!watchdog.getTimedOut() && !rawRequestResponse) {
-				eventLoop.runUntilEvents();
-			}
-
-			if (watchdog.getTimedOut()) {
-				return boost::optional<std::string>();
-			}
-			else {
-				return *rawRequestResponse;
-			}
-		}
-
-		void disconnect() {
-			client->disconnect();
-			while (client->isActive()) {
-				eventLoop.runUntilEvents();
-			}
-		}
-
-		void setSoftwareVersion(const std::string& name, const std::string& version, const std::string& os) {
-			client->setSoftwareVersion(name, version, os);
-		}
-
-		Stanza::ref getNextEvent(int timeout) {
-			if (!pendingEvents.empty()) {
-				Stanza::ref event = pendingEvents.front();
-				pendingEvents.pop_front();
-				return event;
-			}
-			Watchdog watchdog(timeout, networkFactories.getTimerFactory());
-			while (!watchdog.getTimedOut() && pendingEvents.empty() && client->isActive()) {
-				eventLoop.runUntilEvents();
-			}
-			if (watchdog.getTimedOut() || !client->isActive()) {
-				return Stanza::ref();
-			}
-			else if (!pendingEvents.empty()) {
-				Stanza::ref event = pendingEvents.front();
-				pendingEvents.pop_front();
-				return event;
-			}
-			else {
-				return Stanza::ref();
-			}
-		}
-
-		std::vector<XMPPRosterItem> getRoster() {
-			if (!rosterReceived) {
-				// If we haven't requested it yet, request it for the first time
-				client->requestRoster();
-			}
-			while (!rosterReceived) {
-				eventLoop.runUntilEvents();
-			}
-			return client->getRoster()->getItems();
-		}
-
-	private:
-		void handleIncomingEvent(Stanza::ref stanza) {
-			pendingEvents.push_back(stanza);
-		}
-
-		void handleInitialRosterPopulated() {
-			rosterReceived = true;
-		}
-
-		void handleRawRequestResponse(const std::string& response) {
-			rawRequestResponse = response;
-		}
-
-		void handleDisconnected(const boost::optional<ClientError>& error) {
-			if (error) {
-				luaL_error(L, getClientErrorString(*error).c_str());
-			}
-		}
-	
-	private:
-		lua_State* L;
-		Client* client;
-		ClientOptions options;
-		ClientXMLTracer* tracer;
-		bool rosterReceived;
-		std::deque<Stanza::ref> pendingEvents;
-		boost::optional<std::string> rawRequestResponse;
-};
-
-/*******************************************************************************
- * Client functions.
- ******************************************************************************/
-
-static inline SluiftClient* getClient(lua_State* L) {
-	return *reinterpret_cast<SluiftClient**>(luaL_checkudata(L, 1, SLUIFT_CLIENT));
-}
-
-static int sluift_client_connect(lua_State *L) {
-	SluiftClient* client = getClient(L);
-	std::string host;
-	if (lua_type(L, 2) != LUA_TNONE) {
-		host = luaL_checkstring(L, 2);
+namespace Swift {
+	namespace Sluift {
+		SluiftGlobals globals;
 	}
-	if (host.empty()) {
-		client->connect();
-	}
-	else {
-		client->connect(host);
-	}
-	client->waitConnected();
-	return 1;
 }
 
-static int sluift_client_async_connect(lua_State *L) {
-	getClient(L)->connect();
-	return 1;
-}
+extern "C" const char boot_lua[];
 
-static int sluift_client_wait_connected(lua_State *L) {
-	getClient(L)->waitConnected();
-	return 1;
-}
+/*******************************************************************************
+ * Module functions
+ ******************************************************************************/
 
-static int sluift_client_is_connected(lua_State *L) {
-	lua_pushboolean(L, getClient(L)->isConnected());
-	return 1;
-}
+SLUIFT_LUA_FUNCTION(Sluift, new_client) {
+	Lua::checkString(L, 1);
+	JID jid(std::string(Lua::checkString(L, 1)));
+	std::string password(Lua::checkString(L, 2));
 
-static int sluift_client_disconnect(lua_State *L) {
-	getClient(L)->disconnect();
-	return 1;
-}
+	SluiftClient** client = reinterpret_cast<SluiftClient**>(lua_newuserdata(L, sizeof(SluiftClient*)));
+	luaL_getmetatable(L, Lua::FunctionRegistry::getMetaTableNameForType("Client").c_str());
+	lua_setmetatable(L, -2);
 
-static int sluift_client_set_version(lua_State *L) {
-	eventLoop.runOnce();
-
-	SluiftClient* client = getClient(L);
-	luaL_checktype(L, 2, LUA_TTABLE);
-	lua_getfield(L, 2, "name");
-	const char* rawName = lua_tostring(L, -1);
-	lua_getfield(L, 2, "version");
-	const char* rawVersion = lua_tostring(L, -1);
-	lua_getfield(L, 2, "os");
-	const char* rawOS = lua_tostring(L, -1);
-	client->setSoftwareVersion(rawName ? rawName : "", rawVersion ? rawVersion : "", rawOS ? rawOS : "");
-	lua_pop(L, 3);
-	lua_pushvalue(L, 1);
+	*client = new SluiftClient(jid, password, &Sluift::globals.networkFactories, &Sluift::globals.eventLoop, &Sluift::globals);
 	return 1;
 }
 
-static int sluift_client_get_contacts(lua_State *L) {
-	eventLoop.runOnce();
-
-	SluiftClient* client = getClient(L);
-	Lua::Table contactsTable;
-	foreach(const XMPPRosterItem& item, client->getRoster()) {
-		std::string subscription;
-		switch(item.getSubscription()) {
-			case RosterItemPayload::None: subscription = "none"; break;
-			case RosterItemPayload::To: subscription = "to"; break;
-			case RosterItemPayload::From: subscription = "from"; break;
-			case RosterItemPayload::Both: subscription = "both"; break;
-			case RosterItemPayload::Remove: subscription = "remove"; break;
-		}
-		Lua::Value groups(std::vector<Lua::Value>(item.getGroups().begin(), item.getGroups().end()));
-		Lua::Table itemTable = boost::assign::map_list_of
-			("jid", boost::make_shared<Lua::Value>(item.getJID().toString()))
-			("name", boost::make_shared<Lua::Value>(item.getName()))
-			("subscription", boost::make_shared<Lua::Value>(subscription))
-			("groups", boost::make_shared<Lua::Value>(std::vector<Lua::Value>(item.getGroups().begin(), item.getGroups().end())));
-		contactsTable[item.getJID().toString()] = boost::make_shared<Lua::Value>(itemTable);
+SLUIFT_LUA_FUNCTION(Sluift, sha1) {
+	static boost::shared_ptr<CryptoProvider> crypto(PlatformCryptoProvider::create());
+	if (!lua_isstring(L, 1)) {
+		throw Lua::Exception("Expected string");
 	}
-	pushValue(L, contactsTable);
+	size_t len;
+	const char* data = lua_tolstring(L, 1, &len);
+	ByteArray result = crypto->getSHA1Hash(createByteArray(data, len));
+	lua_pushlstring(L, reinterpret_cast<char*>(vecptr(result)), result.size());
 	return 1;
 }
 
-static int sluift_client_get_version(lua_State *L) {
-	SluiftClient* client = getClient(L);
-	int timeout = -1;
-	if (lua_type(L, 3) != LUA_TNONE) {
-		timeout = boost::numeric_cast<int>(luaL_checknumber(L, 3));
-	}
-
-	ResponseSink<SoftwareVersion> sink;
-	GetSoftwareVersionRequest::ref request = GetSoftwareVersionRequest::create(std::string(luaL_checkstring(L, 2)), client->getClient()->getIQRouter());
-	boost::signals::scoped_connection c = request->onResponse.connect(boost::ref(sink));
-	request->send();
-
-	Watchdog watchdog(timeout, networkFactories.getTimerFactory());
-	while (!watchdog.getTimedOut() && !sink.hasResponse()) {
-		eventLoop.runUntilEvents();
-	}
-
-	ErrorPayload::ref error = sink.getResponseError();
-	if (error || watchdog.getTimedOut()) {
-		lua_pushnil(L);
-		if (watchdog.getTimedOut()) {
-			lua_pushstring(L, "Timeout");
-		}
-		else if (error->getCondition() == ErrorPayload::RemoteServerNotFound) {
-			lua_pushstring(L, "Remote server not found");
-		}
-		// TODO
-		else {
-			lua_pushstring(L, "Error");
-		}
-		return 2;
-	}
-	else if (SoftwareVersion::ref version = sink.getResponsePayload()) {
-		Lua::Table result = boost::assign::map_list_of
-			("name", boost::make_shared<Lua::Value>(version->getName()))
-			("version", boost::make_shared<Lua::Value>(version->getVersion()))
-			("os", boost::make_shared<Lua::Value>(version->getOS()));
-		Lua::pushValue(L, result);
-	}
-	else {
-		lua_pushnil(L);
+SLUIFT_LUA_FUNCTION(Sluift, sleep) {
+	Sluift::globals.eventLoop.runOnce();
+	int timeout = Lua::checkIntNumber(L, 1);
+	Watchdog watchdog(timeout, Sluift::globals.networkFactories.getTimerFactory());
+	while (!watchdog.getTimedOut()) {
+		Swift::sleep(boost::numeric_cast<unsigned int>(std::min(100, timeout)));
+		Sluift::globals.eventLoop.runOnce();
 	}
-	return 1;
-}
-
-static int sluift_client_send_message(lua_State *L) {
-	eventLoop.runOnce();
-
-	getClient(L)->sendMessage(std::string(luaL_checkstring(L, 2)), luaL_checkstring(L, 3));
-	lua_pushvalue(L, 1);
-	return 1;
-}
-
-static int sluift_client_send_presence(lua_State *L) {
-	eventLoop.runOnce();
-
-	getClient(L)->sendPresence(std::string(luaL_checkstring(L, 2)));
-	lua_pushvalue(L, 1);
 	return 0;
 }
 
-static int sluift_client_get(lua_State *L) {
-	SluiftClient* client = getClient(L);
-	JID jid;
-	std::string data;
-	int timeout = -1;
-	if (lua_type(L, 3) == LUA_TSTRING) {
-		jid = JID(std::string(luaL_checkstring(L, 2)));
-		data = std::string(luaL_checkstring(L, 3));
-		if (lua_type(L, 4) != LUA_TNONE) {
-			timeout = boost::numeric_cast<int>(luaL_checknumber(L, 4));
+static int sluift_index(lua_State* L) {
+	try {
+		std::string key(Lua::checkString(L, 2));
+		if (key == "debug") {
+			lua_pushboolean(L, Sluift::globals.debug);
+			return 1;
 		}
-	}
-	else {
-		data = std::string(luaL_checkstring(L, 2));
-		if (lua_type(L, 3) != LUA_TNONE) {
-			timeout = boost::numeric_cast<int>(luaL_checknumber(L, 3));
+		else if (key == "timeout") {
+			lua_pushnumber(L, Sluift::globals.timeout);
+			return 1;
 		}
+		throw Lua::Exception("Unknown property");
 	}
-	boost::optional<std::string> result = client->sendQuery(jid, IQ::Get, data, timeout);
-	if (result) {
-		lua_pushstring(L, result->c_str());
-	}
-	else {
-		lua_pushnil(L);
+	catch (const std::exception& e) {
+		return luaL_error(L, e.what());
 	}
-	return 1;
 }
 
-static int sluift_client_set(lua_State *L) {
-	SluiftClient* client = getClient(L);
-	JID jid;
-	std::string data;
-	int timeout = -1;
-	if (lua_type(L, 3) == LUA_TSTRING) {
-		jid = JID(std::string(luaL_checkstring(L, 2)));
-		data = std::string(luaL_checkstring(L, 3));
-		if (lua_type(L, 4) != LUA_TNONE) {
-			timeout = boost::numeric_cast<int>(luaL_checknumber(L, 4));
+
+static int sluift_newindex(lua_State* L) {
+	try {
+		std::string key(Lua::checkString(L, 2));
+		if (key == "debug") {
+			Sluift::globals.debug = lua_toboolean(L, 3);
 		}
-	}
-	else {
-		data = std::string(luaL_checkstring(L, 2));
-		if (lua_type(L, 3) != LUA_TNONE) {
-			timeout = boost::numeric_cast<int>(luaL_checknumber(L, 3));
+		else if (key == "timeout") {
+			Sluift::globals.timeout = Lua::checkIntNumber(L, 3);
 		}
+		return 0;
 	}
-	boost::optional<std::string> result = client->sendQuery(jid, IQ::Set, data, timeout);
-	if (result) {
-		lua_pushstring(L, result->c_str());
-	}
-	else {
-		lua_pushnil(L);
-	}
-	return 1;
-}
-
-static int sluift_client_send(lua_State *L) {
-	eventLoop.runOnce();
-
-	getClient(L)->getClient()->sendData(std::string(luaL_checkstring(L, 2)));
-	lua_pushvalue(L, 1);
-	return 0;
-}
-
-static int sluift_client_set_options(lua_State* L) {
-	SluiftClient* client = getClient(L);
-	luaL_checktype(L, 2, LUA_TTABLE);
-	lua_getfield(L, 2, "ack");
-	if (!lua_isnil(L, -1)) {
-		client->getOptions().useAcks = lua_toboolean(L, -1);
-	}
-	lua_getfield(L, 2, "compress");
-	if (!lua_isnil(L, -1)) {
-		client->getOptions().useStreamCompression = lua_toboolean(L, -1);
-	}
-	lua_getfield(L, 2, "tls");
-	if (!lua_isnil(L, -1)) {
-		bool useTLS = lua_toboolean(L, -1);
-		client->getOptions().useTLS = (useTLS ? ClientOptions::UseTLSWhenAvailable : ClientOptions::NeverUseTLS);
+	catch (const std::exception& e) {
+		return luaL_error(L, e.what());
 	}
-	lua_pushvalue(L, 1);
-	return 0;
 }
 
-static void pushEvent(lua_State* L, Stanza::ref event) {
-	if (Message::ref message = boost::dynamic_pointer_cast<Message>(event)) {
-		Lua::Table result = boost::assign::map_list_of
-			("type", boost::make_shared<Lua::Value>(std::string("message")))
-			("from", boost::make_shared<Lua::Value>(message->getFrom().toString()))
-			("body", boost::make_shared<Lua::Value>(message->getBody()));
-		Lua::pushValue(L, result);
-	}
-	else if (Presence::ref presence = boost::dynamic_pointer_cast<Presence>(event)) {
-		Lua::Table result = boost::assign::map_list_of
-			("type", boost::make_shared<Lua::Value>(std::string("presence")))
-			("from", boost::make_shared<Lua::Value>(presence->getFrom().toString()))
-			("status", boost::make_shared<Lua::Value>(presence->getStatus()));
-		Lua::pushValue(L, result);
-	}
-	else {
-		lua_pushnil(L);
+SLUIFT_LUA_FUNCTION(Sluift, from_xml) {
+	PayloadsParserTester parser;
+	if (!parser.parse(Lua::checkString(L, 1))) {
+		throw Lua::Exception("Error in XML");
 	}
+	return Sluift::globals.elementConvertor.convertToLua(L, parser.getPayload());
 }
 
-static int sluift_client_for_event(lua_State *L) {
-	eventLoop.runOnce();
-
-	SluiftClient* client = getClient(L);
-	luaL_checktype(L, 2, LUA_TFUNCTION);
-	int timeout = -1;
-	if (lua_type(L, 3) != LUA_TNONE) {
-		timeout = boost::numeric_cast<int>(lua_tonumber(L, 3));
+SLUIFT_LUA_FUNCTION(Sluift, to_xml) {
+	static FullPayloadSerializerCollection serializers;
+	boost::shared_ptr<Payload> payload = Sluift::globals.elementConvertor.convertFromLua(L, 1);
+	if (!payload) {
+		throw Lua::Exception("Unrecognized XML");
 	}
-
-	while (true) {
-		Stanza::ref event = client->getNextEvent(timeout);
-		if (!event) {
-			// We got a timeout
-			lua_pushnil(L);
-			return 1;
-		}
-		else {
-			// Push the function and event on the stack
-			lua_pushvalue(L, 2);
-			pushEvent(L, event);
-			int oldTop = lua_gettop(L) - 2;
-			lua_call(L, 1, LUA_MULTRET);
-			int returnValues = lua_gettop(L) - oldTop;
-			if (returnValues > 0) {
-				lua_remove(L, -1 - returnValues);
-				return returnValues;
-			}
-		}
-	}
-}
-
-static int sluift_client_get_next_event(lua_State *L) {
-	eventLoop.runOnce();
-
-	SluiftClient* client = getClient(L);
-	int timeout = -1;
-	if (lua_type(L, 2) != LUA_TNONE) {
-		timeout = boost::numeric_cast<int>(lua_tonumber(L, 2));
+	PayloadSerializer* serializer = serializers.getPayloadSerializer(payload);
+	if (!payload) {
+		throw Lua::Exception("Unrecognized XML");
 	}
-	pushEvent(L, client->getNextEvent(timeout));
+	lua_pushstring(L, serializer->serialize(payload).c_str());
 	return 1;
 }
 
-
-static int sluift_client_add_contact(lua_State* L) {
-	eventLoop.runOnce();
-	SluiftClient* client = getClient(L);
-	RosterItemPayload item;
-	if (lua_type(L, 2) == LUA_TTABLE) {
-		lua_getfield(L, 2, "jid");
-		const char* rawJID = lua_tostring(L, -1);
-		if (rawJID) {
-			item.setJID(std::string(rawJID));
-		}
-		lua_getfield(L, 2, "name");
-		const char* rawName = lua_tostring(L, -1);
-		if (rawName) {
-			item.setName(rawName);
-		}
-		lua_getfield(L, 2, "groups");
-		if (!lua_isnil(L, -1)) {
-			if (lua_type(L, -1) == LUA_TTABLE) {
-				for (size_t i = 1; i <= lua_objlen(L, -1); ++i) {
-					lua_rawgeti(L, -1, boost::numeric_cast<int>(i));
-					const char* rawGroup = lua_tostring(L, -1);
-					if (rawGroup) {
-						item.addGroup(rawGroup);
-					}
-					lua_pop(L, 1);
-				}
-			}
-			else {
-				return luaL_error(L, "Groups should be a table");
-			}
-		}
-	}
-	else {
-		item.setJID(luaL_checkstring(L, 2));
-	}
-
-	client->getRoster();
-	if (!client->getClient()->getRoster()->containsJID(item.getJID())) {
-		RosterPayload::ref roster = boost::make_shared<RosterPayload>();
-		roster->addItem(item);
-
-		ResponseSink<RosterPayload> sink;
-		SetRosterRequest::ref request = SetRosterRequest::create(roster, client->getClient()->getIQRouter());
-		boost::signals::scoped_connection c = request->onResponse.connect(boost::ref(sink));
-		request->send();
-		while (!sink.hasResponse()) {
-			eventLoop.runUntilEvents();
-		}
-		if (sink.getResponseError()) {
-			lua_pushboolean(L, false);
-			return 1;
-		}
+SLUIFT_LUA_FUNCTION(Sluift, hexify) {
+	if (!lua_isstring(L, 1)) {
+		throw Lua::Exception("Expected string");
 	}
-	client->getClient()->getSubscriptionManager()->requestSubscription(item.getJID());
-	lua_pushboolean(L, true);
+	size_t len;
+	const char* data = lua_tolstring(L, 1, &len);
+	lua_pushstring(L, Hexify::hexify(createByteArray(data, len)).c_str());
 	return 1;
 }
 
-static int sluift_client_remove_contact(lua_State* L) {
-	eventLoop.runOnce();
-	SluiftClient* client = getClient(L);
-	JID jid(luaL_checkstring(L, 2));
-
-	RosterPayload::ref roster = boost::make_shared<RosterPayload>();
-	roster->addItem(RosterItemPayload(JID(luaL_checkstring(L, 2)), "", RosterItemPayload::Remove));
-	ResponseSink<RosterPayload> sink;
-	SetRosterRequest::ref request = SetRosterRequest::create(roster, client->getClient()->getIQRouter());
-	boost::signals::scoped_connection c = request->onResponse.connect(boost::ref(sink));
-	request->send();
-	while (!sink.hasResponse()) {
-		eventLoop.runUntilEvents();
+SLUIFT_LUA_FUNCTION(Sluift, unhexify) {
+	if (!lua_isstring(L, 1)) {
+		throw Lua::Exception("Expected string");
 	}
-	lua_pushboolean(L, !sink.getResponseError());
+	ByteArray result = Hexify::unhexify(lua_tostring(L, 1));
+	lua_pushlstring(L, reinterpret_cast<char*>(vecptr(result)), result.size());
 	return 1;
 }
 
-static int sluift_client_confirm_subscription(lua_State* L) {
-	eventLoop.runOnce();
-	SluiftClient* client = getClient(L);
-	JID jid(luaL_checkstring(L, 2));
-	client->getClient()->getSubscriptionManager()->confirmSubscription(jid);
-	return 0;
-}
-
-static int sluift_client_cancel_subscription(lua_State* L) {
-	eventLoop.runOnce();
-	SluiftClient* client = getClient(L);
-	JID jid(luaL_checkstring(L, 2));
-	client->getClient()->getSubscriptionManager()->cancelSubscription(jid);
-	return 0;
-}
-
-static int sluift_client_gc (lua_State *L) {
-	SluiftClient* client = getClient(L);
-	delete client;
-	return 0;
-}
-
-static const luaL_reg sluift_client_functions[] = {
-	{"connect",  sluift_client_connect},
-	{"async_connect",  sluift_client_async_connect},
-	{"wait_connected", sluift_client_wait_connected},
-	{"is_connected", sluift_client_is_connected},
-	{"disconnect",  sluift_client_disconnect},
-	{"send_message", sluift_client_send_message},
-	{"send_presence", sluift_client_send_presence},
-	{"get", sluift_client_get},
-	{"set", sluift_client_set},
-	{"send", sluift_client_send},
-	{"set_version", sluift_client_set_version},
-	{"get_contacts", sluift_client_get_contacts},
-	{"get_version", sluift_client_get_version},
-	{"set_options", sluift_client_set_options},
-	{"for_event", sluift_client_for_event},
-	{"get_next_event", sluift_client_get_next_event},
-	{"add_contact", sluift_client_add_contact},
-	{"remove_contact", sluift_client_remove_contact},
-	{"confirm_subscription", sluift_client_confirm_subscription},
-	{"cancel_subscription", sluift_client_cancel_subscription},
-	{"__gc", sluift_client_gc},
-	{NULL, NULL}
-};
 
 /*******************************************************************************
- * Module functions
+ * JID Functions
  ******************************************************************************/
 
-static int sluift_new_client(lua_State *L) {
-	luaL_checkstring(L, 1);
-	JID jid(std::string(luaL_checkstring(L, 1)));
-	std::string password(luaL_checkstring(L, 2));
-
-	SluiftClient** client = reinterpret_cast<SluiftClient**>(lua_newuserdata(L, sizeof(SluiftClient*)));
-	luaL_getmetatable(L, SLUIFT_CLIENT);
-	lua_setmetatable(L, -2);
-
-	*client = new SluiftClient(jid, password, L);
-	return 1;
-}
-
-static int sluift_jid_to_bare(lua_State *L) {
-	JID jid(std::string(luaL_checkstring(L, 1)));
+SLUIFT_LUA_FUNCTION(JID, to_bare) {
+	JID jid(std::string(Lua::checkString(L, 1)));
 	lua_pushstring(L, jid.toBare().toString().c_str());
 	return 1;
 }
 
-static int sluift_jid_node(lua_State *L) {
-	JID jid(std::string(luaL_checkstring(L, 1)));
+SLUIFT_LUA_FUNCTION(JID, node) {
+	JID jid(std::string(Lua::checkString(L, 1)));
 	lua_pushstring(L, jid.getNode().c_str());
 	return 1;
 }
 
-static int sluift_jid_domain(lua_State *L) {
-	JID jid(std::string(luaL_checkstring(L, 1)));
+SLUIFT_LUA_FUNCTION(JID, domain) {
+	JID jid(std::string(Lua::checkString(L, 1)));
 	lua_pushstring(L, jid.getDomain().c_str());
 	return 1;
 }
 
-static int sluift_jid_resource(lua_State *L) {
-	JID jid(std::string(luaL_checkstring(L, 1)));
+SLUIFT_LUA_FUNCTION(JID, resource) {
+	JID jid(std::string(Lua::checkString(L, 1)));
 	lua_pushstring(L, jid.getResource().c_str());
 	return 1;
 }
 
-static int sluift_sleep(lua_State *L) {
-	eventLoop.runOnce();
-
-	int timeout = boost::numeric_cast<int>(luaL_checknumber(L, 1));
-	Watchdog watchdog(timeout, networkFactories.getTimerFactory());
-	while (!watchdog.getTimedOut()) {
-		Swift::sleep(boost::numeric_cast<unsigned int>(std::min(100, timeout)));
-		eventLoop.runOnce();
-	}
-	return 0;
+SLUIFT_LUA_FUNCTION(JID, escape_node) {
+	lua_pushstring(L, JID::getEscapedNode(Lua::checkString(L, 1)).c_str());
+	return 1;
 }
 
-static int sluift_index(lua_State *L) {
-	std::string key(luaL_checkstring(L, 2));
-	if (key == "debug") {
-		lua_pushboolean(L, debug);
-		return 1;
-	}
-	else if (key == "timeout") {
-		lua_pushnumber(L, globalTimeout);
-		return 1;
-	}
-	else {
-		return luaL_error(L, "Invalid index");
+/*******************************************************************************
+ * Base64 Functions
+ ******************************************************************************/
+
+SLUIFT_LUA_FUNCTION(Base64, encode) {
+	if (!lua_isstring(L, 1)) {
+		throw Lua::Exception("Expected string");
 	}
+	size_t len;
+	const char* data = lua_tolstring(L, 1, &len);
+	lua_pushstring(L, Base64::encode(createByteArray(data, len)).c_str());
+	return 1;
 }
 
-static int sluift_newindex(lua_State *L) {
-	std::string key(luaL_checkstring(L, 2));
-	if (key == "debug") {
-		debug = lua_toboolean(L, 3);
-		return 0;
-	}
-	else if (key == "timeout") {
-		globalTimeout = boost::numeric_cast<int>(luaL_checknumber(L, 3));
-		return 0;
-	}
-	else {
-		return luaL_error(L, "Invalid index");
+SLUIFT_LUA_FUNCTION(Base64, decode) {
+	if (!lua_isstring(L, 1)) {
+		throw Lua::Exception("Expected string");
 	}
+	ByteArray result = Base64::decode(lua_tostring(L, 1));
+	lua_pushlstring(L, reinterpret_cast<char*>(vecptr(result)), result.size());
+	return 1;
 }
 
-static const luaL_reg sluift_functions[] = {
-	{"new_client", sluift_new_client},
-	{"jid_to_bare", sluift_jid_to_bare},
-	{"jid_node", sluift_jid_node},
-	{"jid_domain", sluift_jid_domain},
-	{"jid_resource", sluift_jid_resource},
-	{"sleep", sluift_sleep},
-	{NULL, NULL}
-};
-
-
 /*******************************************************************************
  * Module registration
  ******************************************************************************/
 
-SLUIFT_API int luaopen_sluift(lua_State *L) {
-	// Register functions
+static const luaL_reg sluift_functions[] = { {NULL, NULL} };
+
+SLUIFT_API int luaopen_sluift(lua_State* L) {
+	// Initialize globals
+	Sluift::globals.debug = false;
+	Sluift::globals.timeout = -1;
+
 	luaL_register(L, "sluift", sluift_functions);
+
+	// Load bootstrap code
+	if (luaL_loadbuffer(L, boot_lua, strlen(boot_lua), "boot.lua") != 0) {
+		lua_error(L);
+	}
+	lua_call(L, 0, 1);
+	Sluift::globals.bootIndex = luaL_ref(L, LUA_REGISTRYINDEX);
+
+	// Register functions
+	Lua::FunctionRegistry::getInstance().addFunctionsToTable(L, "Sluift");
+	Lua::FunctionRegistry::getInstance().createFunctionTable(L, "JID");
+	lua_setfield(L, -2, "jid");
+	Lua::FunctionRegistry::getInstance().createFunctionTable(L, "Base64");
+	lua_setfield(L, -2, "base64");
+
+	// Register convenience functions
+	lua_rawgeti(L, LUA_REGISTRYINDEX, Sluift::globals.bootIndex);
+	lua_getfield(L, -1, "tprint");
+	lua_setfield(L, -3, "tprint");
+	lua_pop(L, 1);
+
+	lua_rawgeti(L, LUA_REGISTRYINDEX, Sluift::globals.bootIndex);
+	lua_getfield(L, -1, "disco");
+	lua_setfield(L, -3, "disco");
+	lua_pop(L, 1);
+
+	// Set read only
 	lua_createtable(L, 0, 0);
 	lua_pushcclosure(L, sluift_index, 0);
 	lua_setfield(L, -2, "__index");
 	lua_pushcclosure(L, sluift_newindex, 0);
 	lua_setfield(L, -2, "__newindex");
 	lua_setmetatable(L, -2);
-
-	// Register the client metatable
-	luaL_newmetatable(L, SLUIFT_CLIENT);
-	lua_pushvalue(L, -1);
-	lua_setfield(L, -2, "__index");
-	luaL_register(L, NULL, sluift_client_functions);
-
+	
+	// Load client metatable
+	std::vector<std::string> tables = boost::assign::list_of("Client");
+	foreach (const std::string& table, tables) {
+		Lua::FunctionRegistry::getInstance().registerTypeMetaTable(L, table);
+		luaL_getmetatable(L, Lua::FunctionRegistry::getMetaTableNameForType(table).c_str());
+		lua_rawgeti(L, LUA_REGISTRYINDEX, Sluift::globals.bootIndex);
+		lua_getfield(L, -1, table.c_str());
+		if (!lua_isnil(L, -1)) {
+			for (lua_pushnil(L); lua_next(L, -2); ) {
+				lua_pushvalue(L, -2);
+				lua_pushvalue(L, -2);
+				lua_settable(L, -7);
+				lua_pop(L, 1);
+			}
+		}
+		lua_pop(L, 2);
+	}
 	return 1;
 }
diff --git a/Swiften/Client/Client.cpp b/Swiften/Client/Client.cpp
index da497bc..f158370 100644
--- a/Swiften/Client/Client.cpp
+++ b/Swiften/Client/Client.cpp
@@ -14,6 +14,7 @@
 #include <Swiften/Presence/DirectedPresenceSender.h>
 #include <Swiften/MUC/MUCRegistry.h>
 #include <Swiften/MUC/MUCManager.h>
+#include <Swiften/PubSub/PubSubManagerImpl.h>
 #include <Swiften/Client/MemoryStorages.h>
 #include <Swiften/VCards/VCardManager.h>
 #include <Swiften/VCards/VCardManager.h>
@@ -76,9 +77,12 @@ Client::Client(const JID& jid, const SafeString& password, NetworkFactories* net
 #ifdef SWIFT_EXPERIMENTAL_WB
 	whiteboardSessionManager = new WhiteboardSessionManager(getIQRouter(), getStanzaChannel(), presenceOracle, getEntityCapsProvider());
 #endif
+
+	pubsubManager = new PubSubManagerImpl(getStanzaChannel(), getIQRouter());
 }
 
 Client::~Client() {
+	delete pubsubManager;
 	delete whiteboardSessionManager;
 
 	delete fileTransferManager;
diff --git a/Swiften/Client/Client.h b/Swiften/Client/Client.h
index f192539..9253074 100644
--- a/Swiften/Client/Client.h
+++ b/Swiften/Client/Client.h
@@ -38,6 +38,7 @@ namespace Swift {
 	class FileTransferManager;
 	class WhiteboardSessionManager;
 	class ClientBlockListManager;
+	class PubSubManager;
 
 	/**
 	 * Provides the core functionality for writing XMPP client software.
@@ -158,6 +159,11 @@ namespace Swift {
 			void setAlwaysTrustCertificates();
 
 			WhiteboardSessionManager* getWhiteboardSessionManager() const;
+
+			PubSubManager* getPubSubManager() const {
+				return pubsubManager;
+			}
+
 		
 		public:
 			/**
@@ -195,5 +201,6 @@ namespace Swift {
 			BlindCertificateTrustChecker* blindCertificateTrustChecker;
 			WhiteboardSessionManager* whiteboardSessionManager;
 			ClientBlockListManager* blockListManager;
+			PubSubManager* pubsubManager;
 	};
 }
diff --git a/Swiften/Client/ClientXMLTracer.cpp b/Swiften/Client/ClientXMLTracer.cpp
index d2b5446..b413f40 100644
--- a/Swiften/Client/ClientXMLTracer.cpp
+++ b/Swiften/Client/ClientXMLTracer.cpp
@@ -9,10 +9,16 @@
 #include <iostream>
 #include <boost/bind.hpp>
 
+#include <Swiften/Base/Platform.h>
+
 namespace Swift {
 
 ClientXMLTracer::ClientXMLTracer(CoreClient* client, bool bosh) : bosh(bosh) {
+#ifdef SWIFTEN_PLATFORM_WIN32
+	beautifier = new XMLBeautifier(true, false);
+#else
 	beautifier = new XMLBeautifier(true, true);
+#endif
 	client->onDataRead.connect(boost::bind(&ClientXMLTracer::printData, this, '<', _1));
 	client->onDataWritten.connect(boost::bind(&ClientXMLTracer::printData, this, '>', _1));
 }
diff --git a/Swiften/Elements/ContainerPayload.h b/Swiften/Elements/ContainerPayload.h
new file mode 100644
index 0000000..e2a4682
--- /dev/null
+++ b/Swiften/Elements/ContainerPayload.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <boost/shared_ptr.hpp>
+#include <vector>
+
+namespace Swift {
+	template<typename T>
+	class SWIFTEN_API ContainerPayload : public Payload {
+		public:
+			ContainerPayload() {}
+			ContainerPayload(boost::shared_ptr<T> payload) : payload(payload) {}
+
+			void setPayload(boost::shared_ptr<T> payload) {
+				this->payload = payload;
+			}
+			
+			boost::shared_ptr<T> getPayload() const {
+				return payload;
+			}
+
+		private:
+			boost::shared_ptr<T> payload;
+	};
+}
diff --git a/Swiften/Elements/Form.h b/Swiften/Elements/Form.h
index bd4a2aa..76ed674 100644
--- a/Swiften/Elements/Form.h
+++ b/Swiften/Elements/Form.h
@@ -35,6 +35,7 @@ namespace Swift {
 			 */
 			void addField(boost::shared_ptr<FormField> field) {assert(field);  fields_.push_back(field); }
 			const std::vector<boost::shared_ptr<FormField> >& getFields() const { return fields_; }
+			void clearFields() { fields_.clear(); }
 			void setTitle(const std::string& title) { title_ = title; }
 			const std::string& getTitle() const { return title_; }
 
@@ -50,9 +51,12 @@ namespace Swift {
 
 			void addReportedField(FormField::ref field);
 			const std::vector<FormField::ref>& getReportedFields() const;
+			void clearReportedFields() { reportedFields_.clear(); }
 
 			void addItem(const FormItem& item);
 			const std::vector<FormItem>& getItems() const;
+			void clearItems() { items_.clear(); }
+
 		private:
 			std::vector<boost::shared_ptr<FormField> > fields_;
 			std::vector<boost::shared_ptr<FormField> > reportedFields_;
diff --git a/Swiften/Elements/FormField.cpp b/Swiften/Elements/FormField.cpp
index 27ced82..e9e4f77 100644
--- a/Swiften/Elements/FormField.cpp
+++ b/Swiften/Elements/FormField.cpp
@@ -27,7 +27,6 @@ void FormField::setTextMultiValue(const std::string& value) {
 }
 
 void FormField::setBoolValue(bool b) {
-	assert(type == BooleanType || type == UnknownType);
 	values.clear();
 	values.push_back(b ? "1" : "0");
 }
diff --git a/Swiften/Elements/FormField.h b/Swiften/Elements/FormField.h
index 26e70bb..f0bebd9 100644
--- a/Swiften/Elements/FormField.h
+++ b/Swiften/Elements/FormField.h
@@ -63,6 +63,10 @@ namespace Swift {
 				return options;
 			}
 
+			void clearOptions() {
+				options.clear();
+			}
+
 			const std::vector<std::string>& getValues() const {
 				return values;
 			}
diff --git a/Swiften/Elements/PubSub.cpp b/Swiften/Elements/PubSub.cpp
new file mode 100644
index 0000000..30a6376
--- /dev/null
+++ b/Swiften/Elements/PubSub.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSub.h>
+
+using namespace Swift;
+
+PubSub::PubSub() {
+}
+
+PubSub::~PubSub() {
+}
diff --git a/Swiften/Elements/PubSub.h b/Swiften/Elements/PubSub.h
new file mode 100644
index 0000000..cd8bf43
--- /dev/null
+++ b/Swiften/Elements/PubSub.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/ContainerPayload.h>
+
+#include <Swiften/Elements/PubSubPayload.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSub : public ContainerPayload<PubSubPayload> {
+		public:
+			PubSub();
+			virtual ~PubSub();
+	};
+}
diff --git a/Swiften/Elements/PubSubAffiliation.cpp b/Swiften/Elements/PubSubAffiliation.cpp
new file mode 100644
index 0000000..0b04494
--- /dev/null
+++ b/Swiften/Elements/PubSubAffiliation.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubAffiliation.h>
+
+using namespace Swift;
+
+PubSubAffiliation::PubSubAffiliation() : type(None) {
+}
+
+PubSubAffiliation::~PubSubAffiliation() {
+}
diff --git a/Swiften/Elements/PubSubAffiliation.h b/Swiften/Elements/PubSubAffiliation.h
new file mode 100644
index 0000000..2ea9376
--- /dev/null
+++ b/Swiften/Elements/PubSubAffiliation.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <string>
+
+
+
+namespace Swift {
+	class SWIFTEN_API PubSubAffiliation : public Payload {
+		public:
+			enum Type {
+				None,
+				Member,
+				Outcast,
+				Owner,
+				Publisher,
+				PublishOnly
+			};
+
+			PubSubAffiliation();
+			PubSubAffiliation(const std::string& node) : node(node), type(None) {}
+			virtual ~PubSubAffiliation();
+
+			const std::string& getNode() const {
+				return node;
+			}
+
+			void setNode(const std::string& value) {
+				this->node = value ;
+			}
+
+			Type getType() const {
+				return type;
+			}
+
+			void setType(Type value) {
+				this->type = value ;
+			}
+
+
+		private:
+			std::string node;
+			Type type;
+	};
+}
diff --git a/Swiften/Elements/PubSubAffiliations.cpp b/Swiften/Elements/PubSubAffiliations.cpp
new file mode 100644
index 0000000..a53215d
--- /dev/null
+++ b/Swiften/Elements/PubSubAffiliations.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubAffiliations.h>
+
+using namespace Swift;
+
+PubSubAffiliations::PubSubAffiliations() {
+}
+
+PubSubAffiliations::~PubSubAffiliations() {
+}
diff --git a/Swiften/Elements/PubSubAffiliations.h b/Swiften/Elements/PubSubAffiliations.h
new file mode 100644
index 0000000..6a413fe
--- /dev/null
+++ b/Swiften/Elements/PubSubAffiliations.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <boost/optional.hpp>
+#include <boost/shared_ptr.hpp>
+#include <vector>
+#include <string>
+
+#include <Swiften/Elements/PubSubAffiliation.h>
+#include <Swiften/Elements/PubSubPayload.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubAffiliations : public PubSubPayload {
+		public:
+			
+			PubSubAffiliations();
+			
+			virtual ~PubSubAffiliations();
+
+			const boost::optional< std::string >& getNode() const {
+				return node;
+			}
+
+			void setNode(const boost::optional< std::string >& value) {
+				this->node = value ;
+			}
+
+			const std::vector< boost::shared_ptr<PubSubAffiliation> >& getAffiliations() const {
+				return affiliations;
+			}
+
+			void setAffiliations(const std::vector< boost::shared_ptr<PubSubAffiliation> >& value) {
+				this->affiliations = value ;
+			}
+
+			void addAffiliation(boost::shared_ptr<PubSubAffiliation> value) {
+				this->affiliations.push_back(value);
+			}
+
+
+		private:
+			boost::optional< std::string > node;
+			std::vector< boost::shared_ptr<PubSubAffiliation> > affiliations;
+	};
+}
diff --git a/Swiften/Elements/PubSubConfigure.cpp b/Swiften/Elements/PubSubConfigure.cpp
new file mode 100644
index 0000000..b1a6cb3
--- /dev/null
+++ b/Swiften/Elements/PubSubConfigure.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubConfigure.h>
+
+using namespace Swift;
+
+PubSubConfigure::PubSubConfigure() {
+}
+
+PubSubConfigure::~PubSubConfigure() {
+}
diff --git a/Swiften/Elements/PubSubConfigure.h b/Swiften/Elements/PubSubConfigure.h
new file mode 100644
index 0000000..ed91832
--- /dev/null
+++ b/Swiften/Elements/PubSubConfigure.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Elements/Form.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubConfigure : public Payload {
+		public:
+			
+			PubSubConfigure();
+			
+			virtual ~PubSubConfigure();
+
+			boost::shared_ptr<Form> getData() const {
+				return data;
+			}
+
+			void setData(boost::shared_ptr<Form> value) {
+				this->data = value ;
+			}
+
+
+		private:
+			boost::shared_ptr<Form> data;
+	};
+}
diff --git a/Swiften/Elements/PubSubCreate.cpp b/Swiften/Elements/PubSubCreate.cpp
new file mode 100644
index 0000000..9c60de3
--- /dev/null
+++ b/Swiften/Elements/PubSubCreate.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubCreate.h>
+
+using namespace Swift;
+
+PubSubCreate::PubSubCreate() {
+}
+
+PubSubCreate::~PubSubCreate() {
+}
diff --git a/Swiften/Elements/PubSubCreate.h b/Swiften/Elements/PubSubCreate.h
new file mode 100644
index 0000000..4e4eb92
--- /dev/null
+++ b/Swiften/Elements/PubSubCreate.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <boost/shared_ptr.hpp>
+#include <string>
+
+#include <Swiften/Elements/PubSubConfigure.h>
+#include <Swiften/Elements/PubSubPayload.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubCreate : public PubSubPayload {
+		public:
+			
+			PubSubCreate();
+			PubSubCreate(const std::string& node) : node(node) {}
+			virtual ~PubSubCreate();
+
+			const std::string& getNode() const {
+				return node;
+			}
+
+			void setNode(const std::string& value) {
+				this->node = value ;
+			}
+
+			boost::shared_ptr<PubSubConfigure> getConfigure() const {
+				return configure;
+			}
+
+			void setConfigure(boost::shared_ptr<PubSubConfigure> value) {
+				this->configure = value ;
+			}
+
+
+		private:
+			std::string node;
+			boost::shared_ptr<PubSubConfigure> configure;
+	};
+}
diff --git a/Swiften/Elements/PubSubDefault.cpp b/Swiften/Elements/PubSubDefault.cpp
new file mode 100644
index 0000000..923d0ad
--- /dev/null
+++ b/Swiften/Elements/PubSubDefault.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubDefault.h>
+
+using namespace Swift;
+
+PubSubDefault::PubSubDefault() : type(None) {
+}
+
+PubSubDefault::~PubSubDefault() {
+}
diff --git a/Swiften/Elements/PubSubDefault.h b/Swiften/Elements/PubSubDefault.h
new file mode 100644
index 0000000..08326e7
--- /dev/null
+++ b/Swiften/Elements/PubSubDefault.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <boost/optional.hpp>
+#include <string>
+
+#include <Swiften/Elements/PubSubPayload.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubDefault : public PubSubPayload {
+		public:
+			enum Type {
+				None,
+				Collection,
+				Leaf
+			};
+
+			PubSubDefault();
+			
+			virtual ~PubSubDefault();
+
+			const boost::optional< std::string >& getNode() const {
+				return node;
+			}
+
+			void setNode(const boost::optional< std::string >& value) {
+				this->node = value ;
+			}
+
+			Type getType() const {
+				return type;
+			}
+
+			void setType(Type value) {
+				this->type = value ;
+			}
+
+
+		private:
+			boost::optional< std::string > node;
+			Type type;
+	};
+}
diff --git a/Swiften/Elements/PubSubError.cpp b/Swiften/Elements/PubSubError.cpp
new file mode 100644
index 0000000..db07972
--- /dev/null
+++ b/Swiften/Elements/PubSubError.cpp
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubError.h>
+
+using namespace Swift;
+
+PubSubError::~PubSubError() {
+}
diff --git a/Swiften/Elements/PubSubError.h b/Swiften/Elements/PubSubError.h
new file mode 100644
index 0000000..3748e44
--- /dev/null
+++ b/Swiften/Elements/PubSubError.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Elements/Payload.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubError : public Payload {
+		public:
+			enum Type {
+				UnknownType = 0,
+				ClosedNode,
+				ConfigurationRequired,
+				InvalidJID,
+				InvalidOptions,
+				InvalidPayload,
+				InvalidSubscriptionID,
+				ItemForbidden,
+				ItemRequired,
+				JIDRequired,
+				MaximumItemsExceeded,
+				MaximumNodesExceeded,
+				NodeIDRequired,
+				NotInRosterGroup,
+				NotSubscribed,
+				PayloadTooBig,
+				PayloadRequired,
+				PendingSubscription,
+				PresenceSubscriptionRequired,
+				SubscriptionIDRequired,
+				TooManySubscriptions,
+				Unsupported,
+				UnsupportedAccessModel
+			};
+
+			enum UnsupportedFeatureType {
+				UnknownUnsupportedFeatureType = 0,
+				AccessAuthorize,
+				AccessOpen,
+				AccessPresence,
+				AccessRoster,
+				AccessWhitelist,
+				AutoCreate,
+				AutoSubscribe,
+				Collections,
+				ConfigNode,
+				CreateAndConfigure,
+				CreateNodes,
+				DeleteItems,
+				DeleteNodes,
+				FilteredNotifications,
+				GetPending,
+				InstantNodes,
+				ItemIDs,
+				LastPublished,
+				LeasedSubscription,
+				ManageSubscriptions,
+				MemberAffiliation,
+				MetaData,
+				ModifyAffiliations,
+				MultiCollection,
+				MultiSubscribe,
+				OutcastAffiliation,
+				PersistentItems,
+				PresenceNotifications,
+				PresenceSubscribe,
+				Publish,
+				PublishOptions,
+				PublishOnlyAffiliation,
+				PublisherAffiliation,
+				PurgeNodes,
+				RetractItems,
+				RetrieveAffiliations,
+				RetrieveDefault,
+				RetrieveItems,
+				RetrieveSubscriptions,
+				Subscribe,
+				SubscriptionOptions,
+				SubscriptionNotifications
+			};
+
+			PubSubError(Type type = UnknownType) : type(type), unsupportedType(UnknownUnsupportedFeatureType) {
+			}
+
+			virtual ~PubSubError();
+
+			Type getType() const {
+				return type;
+			}
+
+			void setType(Type type) {
+				this->type = type;
+			}
+
+			UnsupportedFeatureType getUnsupportedFeatureType() const {
+				return unsupportedType;
+			}
+
+			void setUnsupportedFeatureType(UnsupportedFeatureType unsupportedType) {
+				this->unsupportedType = unsupportedType;
+			}
+
+		private:
+			Type type;
+			UnsupportedFeatureType unsupportedType;
+	};
+}
diff --git a/Swiften/Elements/PubSubEvent.cpp b/Swiften/Elements/PubSubEvent.cpp
new file mode 100644
index 0000000..1b63134
--- /dev/null
+++ b/Swiften/Elements/PubSubEvent.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubEvent.h>
+
+using namespace Swift;
+
+PubSubEvent::PubSubEvent() {
+}
+
+PubSubEvent::~PubSubEvent() {
+}
diff --git a/Swiften/Elements/PubSubEvent.h b/Swiften/Elements/PubSubEvent.h
new file mode 100644
index 0000000..9ef6d89
--- /dev/null
+++ b/Swiften/Elements/PubSubEvent.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Elements/ContainerPayload.h>
+#include <Swiften/Elements/PubSubEventPayload.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubEvent : public ContainerPayload<PubSubEventPayload> {
+		public:
+			PubSubEvent();
+			virtual ~PubSubEvent();
+	};
+}
diff --git a/Swiften/Elements/PubSubEventAssociate.cpp b/Swiften/Elements/PubSubEventAssociate.cpp
new file mode 100644
index 0000000..cb81b46
--- /dev/null
+++ b/Swiften/Elements/PubSubEventAssociate.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubEventAssociate.h>
+
+using namespace Swift;
+
+PubSubEventAssociate::PubSubEventAssociate() {
+}
+
+PubSubEventAssociate::~PubSubEventAssociate() {
+}
diff --git a/Swiften/Elements/PubSubEventAssociate.h b/Swiften/Elements/PubSubEventAssociate.h
new file mode 100644
index 0000000..a752345
--- /dev/null
+++ b/Swiften/Elements/PubSubEventAssociate.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <string>
+
+
+
+namespace Swift {
+	class SWIFTEN_API PubSubEventAssociate : public Payload {
+		public:
+			
+			PubSubEventAssociate();
+			
+			virtual ~PubSubEventAssociate();
+
+			const std::string& getNode() const {
+				return node;
+			}
+
+			void setNode(const std::string& value) {
+				this->node = value ;
+			}
+
+
+		private:
+			std::string node;
+	};
+}
diff --git a/Swiften/Elements/PubSubEventCollection.cpp b/Swiften/Elements/PubSubEventCollection.cpp
new file mode 100644
index 0000000..a8b2a56
--- /dev/null
+++ b/Swiften/Elements/PubSubEventCollection.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubEventCollection.h>
+
+using namespace Swift;
+
+PubSubEventCollection::PubSubEventCollection() {
+}
+
+PubSubEventCollection::~PubSubEventCollection() {
+}
diff --git a/Swiften/Elements/PubSubEventCollection.h b/Swiften/Elements/PubSubEventCollection.h
new file mode 100644
index 0000000..e4498aa
--- /dev/null
+++ b/Swiften/Elements/PubSubEventCollection.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <boost/optional.hpp>
+#include <boost/shared_ptr.hpp>
+#include <string>
+
+#include <Swiften/Elements/PubSubEventDisassociate.h>
+#include <Swiften/Elements/PubSubEventAssociate.h>
+#include <Swiften/Elements/PubSubEventPayload.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubEventCollection : public PubSubEventPayload {
+		public:
+			
+			PubSubEventCollection();
+			
+			virtual ~PubSubEventCollection();
+
+			const boost::optional< std::string >& getNode() const {
+				return node;
+			}
+
+			void setNode(const boost::optional< std::string >& value) {
+				this->node = value ;
+			}
+
+			boost::shared_ptr<PubSubEventDisassociate> getDisassociate() const {
+				return disassociate;
+			}
+
+			void setDisassociate(boost::shared_ptr<PubSubEventDisassociate> value) {
+				this->disassociate = value ;
+			}
+
+			boost::shared_ptr<PubSubEventAssociate> getAssociate() const {
+				return associate;
+			}
+
+			void setAssociate(boost::shared_ptr<PubSubEventAssociate> value) {
+				this->associate = value ;
+			}
+
+
+		private:
+			boost::optional< std::string > node;
+			boost::shared_ptr<PubSubEventDisassociate> disassociate;
+			boost::shared_ptr<PubSubEventAssociate> associate;
+	};
+}
diff --git a/Swiften/Elements/PubSubEventConfiguration.cpp b/Swiften/Elements/PubSubEventConfiguration.cpp
new file mode 100644
index 0000000..93ce6a3
--- /dev/null
+++ b/Swiften/Elements/PubSubEventConfiguration.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubEventConfiguration.h>
+
+using namespace Swift;
+
+PubSubEventConfiguration::PubSubEventConfiguration() {
+}
+
+PubSubEventConfiguration::~PubSubEventConfiguration() {
+}
diff --git a/Swiften/Elements/PubSubEventConfiguration.h b/Swiften/Elements/PubSubEventConfiguration.h
new file mode 100644
index 0000000..7ebfce1
--- /dev/null
+++ b/Swiften/Elements/PubSubEventConfiguration.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <boost/shared_ptr.hpp>
+#include <string>
+
+#include <Swiften/Elements/Form.h>
+#include <Swiften/Elements/PubSubEventPayload.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubEventConfiguration : public PubSubEventPayload {
+		public:
+			
+			PubSubEventConfiguration();
+			
+			virtual ~PubSubEventConfiguration();
+
+			const std::string& getNode() const {
+				return node;
+			}
+
+			void setNode(const std::string& value) {
+				this->node = value ;
+			}
+
+			boost::shared_ptr<Form> getData() const {
+				return data;
+			}
+
+			void setData(boost::shared_ptr<Form> value) {
+				this->data = value ;
+			}
+
+
+		private:
+			std::string node;
+			boost::shared_ptr<Form> data;
+	};
+}
diff --git a/Swiften/Elements/PubSubEventDelete.cpp b/Swiften/Elements/PubSubEventDelete.cpp
new file mode 100644
index 0000000..85bbf2e
--- /dev/null
+++ b/Swiften/Elements/PubSubEventDelete.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubEventDelete.h>
+
+using namespace Swift;
+
+PubSubEventDelete::PubSubEventDelete() {
+}
+
+PubSubEventDelete::~PubSubEventDelete() {
+}
diff --git a/Swiften/Elements/PubSubEventDelete.h b/Swiften/Elements/PubSubEventDelete.h
new file mode 100644
index 0000000..fecfb0e
--- /dev/null
+++ b/Swiften/Elements/PubSubEventDelete.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <boost/shared_ptr.hpp>
+#include <string>
+
+#include <Swiften/Elements/PubSubEventRedirect.h>
+#include <Swiften/Elements/PubSubEventPayload.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubEventDelete : public PubSubEventPayload {
+		public:
+			
+			PubSubEventDelete();
+			
+			virtual ~PubSubEventDelete();
+
+			const std::string& getNode() const {
+				return node;
+			}
+
+			void setNode(const std::string& value) {
+				this->node = value ;
+			}
+
+			boost::shared_ptr<PubSubEventRedirect> getRedirects() const {
+				return redirects;
+			}
+
+			void setRedirects(boost::shared_ptr<PubSubEventRedirect> value) {
+				this->redirects = value ;
+			}
+
+
+		private:
+			std::string node;
+			boost::shared_ptr<PubSubEventRedirect> redirects;
+	};
+}
diff --git a/Swiften/Elements/PubSubEventDisassociate.cpp b/Swiften/Elements/PubSubEventDisassociate.cpp
new file mode 100644
index 0000000..55e1c4e
--- /dev/null
+++ b/Swiften/Elements/PubSubEventDisassociate.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubEventDisassociate.h>
+
+using namespace Swift;
+
+PubSubEventDisassociate::PubSubEventDisassociate() {
+}
+
+PubSubEventDisassociate::~PubSubEventDisassociate() {
+}
diff --git a/Swiften/Elements/PubSubEventDisassociate.h b/Swiften/Elements/PubSubEventDisassociate.h
new file mode 100644
index 0000000..cad9843
--- /dev/null
+++ b/Swiften/Elements/PubSubEventDisassociate.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <string>
+
+
+
+namespace Swift {
+	class SWIFTEN_API PubSubEventDisassociate : public Payload {
+		public:
+			
+			PubSubEventDisassociate();
+			
+			virtual ~PubSubEventDisassociate();
+
+			const std::string& getNode() const {
+				return node;
+			}
+
+			void setNode(const std::string& value) {
+				this->node = value ;
+			}
+
+
+		private:
+			std::string node;
+	};
+}
diff --git a/Swiften/Elements/PubSubEventItem.cpp b/Swiften/Elements/PubSubEventItem.cpp
new file mode 100644
index 0000000..6bb3823
--- /dev/null
+++ b/Swiften/Elements/PubSubEventItem.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubEventItem.h>
+
+using namespace Swift;
+
+PubSubEventItem::PubSubEventItem() {
+}
+
+PubSubEventItem::~PubSubEventItem() {
+}
diff --git a/Swiften/Elements/PubSubEventItem.h b/Swiften/Elements/PubSubEventItem.h
new file mode 100644
index 0000000..25ebc82
--- /dev/null
+++ b/Swiften/Elements/PubSubEventItem.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <boost/optional.hpp>
+#include <boost/shared_ptr.hpp>
+#include <vector>
+#include <string>
+
+#include <Swiften/Elements/Payload.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubEventItem : public Payload {
+		public:
+			
+			PubSubEventItem();
+			
+			virtual ~PubSubEventItem();
+
+			const boost::optional< std::string >& getNode() const {
+				return node;
+			}
+
+			void setNode(const boost::optional< std::string >& value) {
+				this->node = value ;
+			}
+
+			const boost::optional< std::string >& getPublisher() const {
+				return publisher;
+			}
+
+			void setPublisher(const boost::optional< std::string >& value) {
+				this->publisher = value ;
+			}
+
+			const std::vector< boost::shared_ptr<Payload> >& getData() const {
+				return data;
+			}
+
+			void setData(const std::vector< boost::shared_ptr<Payload> >& value) {
+				this->data = value ;
+			}
+
+			void addData(boost::shared_ptr<Payload> value) {
+				this->data.push_back(value);
+			}
+
+			const boost::optional< std::string >& getID() const {
+				return id;
+			}
+
+			void setID(const boost::optional< std::string >& value) {
+				this->id = value ;
+			}
+
+
+		private:
+			boost::optional< std::string > node;
+			boost::optional< std::string > publisher;
+			std::vector< boost::shared_ptr<Payload> > data;
+			boost::optional< std::string > id;
+	};
+}
diff --git a/Swiften/Elements/PubSubEventItems.cpp b/Swiften/Elements/PubSubEventItems.cpp
new file mode 100644
index 0000000..01f3429
--- /dev/null
+++ b/Swiften/Elements/PubSubEventItems.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubEventItems.h>
+
+using namespace Swift;
+
+PubSubEventItems::PubSubEventItems() {
+}
+
+PubSubEventItems::~PubSubEventItems() {
+}
diff --git a/Swiften/Elements/PubSubEventItems.h b/Swiften/Elements/PubSubEventItems.h
new file mode 100644
index 0000000..a121728
--- /dev/null
+++ b/Swiften/Elements/PubSubEventItems.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <boost/shared_ptr.hpp>
+#include <vector>
+#include <string>
+
+#include <Swiften/Elements/PubSubEventItem.h>
+#include <Swiften/Elements/PubSubEventRetract.h>
+#include <Swiften/Elements/PubSubEventPayload.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubEventItems : public PubSubEventPayload {
+		public:
+			
+			PubSubEventItems();
+			
+			virtual ~PubSubEventItems();
+
+			const std::string& getNode() const {
+				return node;
+			}
+
+			void setNode(const std::string& value) {
+				this->node = value ;
+			}
+
+			const std::vector< boost::shared_ptr<PubSubEventItem> >& getItems() const {
+				return items;
+			}
+
+			void setItems(const std::vector< boost::shared_ptr<PubSubEventItem> >& value) {
+				this->items = value ;
+			}
+
+			void addItem(boost::shared_ptr<PubSubEventItem> value) {
+				this->items.push_back(value);
+			}
+
+			const std::vector< boost::shared_ptr<PubSubEventRetract> >& getRetracts() const {
+				return retracts;
+			}
+
+			void setRetracts(const std::vector< boost::shared_ptr<PubSubEventRetract> >& value) {
+				this->retracts = value ;
+			}
+
+			void addRetract(boost::shared_ptr<PubSubEventRetract> value) {
+				this->retracts.push_back(value);
+			}
+
+
+		private:
+			std::string node;
+			std::vector< boost::shared_ptr<PubSubEventItem> > items;
+			std::vector< boost::shared_ptr<PubSubEventRetract> > retracts;
+	};
+}
diff --git a/Swiften/Elements/PubSubEventPayload.cpp b/Swiften/Elements/PubSubEventPayload.cpp
new file mode 100644
index 0000000..0019942
--- /dev/null
+++ b/Swiften/Elements/PubSubEventPayload.cpp
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubEventPayload.h>
+
+using namespace Swift;
+
+PubSubEventPayload::~PubSubEventPayload() {
+}
diff --git a/Swiften/Elements/PubSubEventPayload.h b/Swiften/Elements/PubSubEventPayload.h
new file mode 100644
index 0000000..81fb9a8
--- /dev/null
+++ b/Swiften/Elements/PubSubEventPayload.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubEventPayload : public Payload {
+		public:
+			virtual ~PubSubEventPayload();
+	};
+}
diff --git a/Swiften/Elements/PubSubEventPurge.cpp b/Swiften/Elements/PubSubEventPurge.cpp
new file mode 100644
index 0000000..3fd77ed
--- /dev/null
+++ b/Swiften/Elements/PubSubEventPurge.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubEventPurge.h>
+
+using namespace Swift;
+
+PubSubEventPurge::PubSubEventPurge() {
+}
+
+PubSubEventPurge::~PubSubEventPurge() {
+}
diff --git a/Swiften/Elements/PubSubEventPurge.h b/Swiften/Elements/PubSubEventPurge.h
new file mode 100644
index 0000000..5f04049
--- /dev/null
+++ b/Swiften/Elements/PubSubEventPurge.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <string>
+
+#include <Swiften/Elements/PubSubEventPayload.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubEventPurge : public PubSubEventPayload {
+		public:
+			
+			PubSubEventPurge();
+			
+			virtual ~PubSubEventPurge();
+
+			const std::string& getNode() const {
+				return node;
+			}
+
+			void setNode(const std::string& value) {
+				this->node = value ;
+			}
+
+
+		private:
+			std::string node;
+	};
+}
diff --git a/Swiften/Elements/PubSubEventRedirect.cpp b/Swiften/Elements/PubSubEventRedirect.cpp
new file mode 100644
index 0000000..adde8bc
--- /dev/null
+++ b/Swiften/Elements/PubSubEventRedirect.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubEventRedirect.h>
+
+using namespace Swift;
+
+PubSubEventRedirect::PubSubEventRedirect() {
+}
+
+PubSubEventRedirect::~PubSubEventRedirect() {
+}
diff --git a/Swiften/Elements/PubSubEventRedirect.h b/Swiften/Elements/PubSubEventRedirect.h
new file mode 100644
index 0000000..918c7f4
--- /dev/null
+++ b/Swiften/Elements/PubSubEventRedirect.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <string>
+
+
+
+namespace Swift {
+	class SWIFTEN_API PubSubEventRedirect : public Payload {
+		public:
+			
+			PubSubEventRedirect();
+			
+			virtual ~PubSubEventRedirect();
+
+			const std::string& getURI() const {
+				return uri;
+			}
+
+			void setURI(const std::string& value) {
+				this->uri = value ;
+			}
+
+
+		private:
+			std::string uri;
+	};
+}
diff --git a/Swiften/Elements/PubSubEventRetract.cpp b/Swiften/Elements/PubSubEventRetract.cpp
new file mode 100644
index 0000000..bb3ebb1
--- /dev/null
+++ b/Swiften/Elements/PubSubEventRetract.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubEventRetract.h>
+
+using namespace Swift;
+
+PubSubEventRetract::PubSubEventRetract() {
+}
+
+PubSubEventRetract::~PubSubEventRetract() {
+}
diff --git a/Swiften/Elements/PubSubEventRetract.h b/Swiften/Elements/PubSubEventRetract.h
new file mode 100644
index 0000000..3c2d9c4
--- /dev/null
+++ b/Swiften/Elements/PubSubEventRetract.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <string>
+
+
+
+namespace Swift {
+	class SWIFTEN_API PubSubEventRetract : public Payload {
+		public:
+			
+			PubSubEventRetract();
+			
+			virtual ~PubSubEventRetract();
+
+			const std::string& getID() const {
+				return id;
+			}
+
+			void setID(const std::string& value) {
+				this->id = value ;
+			}
+
+
+		private:
+			std::string id;
+	};
+}
diff --git a/Swiften/Elements/PubSubEventSubscription.cpp b/Swiften/Elements/PubSubEventSubscription.cpp
new file mode 100644
index 0000000..fb069f9
--- /dev/null
+++ b/Swiften/Elements/PubSubEventSubscription.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubEventSubscription.h>
+
+using namespace Swift;
+
+PubSubEventSubscription::PubSubEventSubscription() : subscription(None) {
+}
+
+PubSubEventSubscription::~PubSubEventSubscription() {
+}
diff --git a/Swiften/Elements/PubSubEventSubscription.h b/Swiften/Elements/PubSubEventSubscription.h
new file mode 100644
index 0000000..b74d4f5
--- /dev/null
+++ b/Swiften/Elements/PubSubEventSubscription.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <boost/optional.hpp>
+#include <string>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include <Swiften/JID/JID.h>
+#include <Swiften/Elements/PubSubEventPayload.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubEventSubscription : public PubSubEventPayload {
+		public:
+			enum SubscriptionType {
+				None,
+				Pending,
+				Subscribed,
+				Unconfigured
+			};
+
+			PubSubEventSubscription();
+			
+			virtual ~PubSubEventSubscription();
+
+			const std::string& getNode() const {
+				return node;
+			}
+
+			void setNode(const std::string& value) {
+				this->node = value ;
+			}
+
+			const JID& getJID() const {
+				return jid;
+			}
+
+			void setJID(const JID& value) {
+				this->jid = value ;
+			}
+
+			SubscriptionType getSubscription() const {
+				return subscription;
+			}
+
+			void setSubscription(SubscriptionType value) {
+				this->subscription = value ;
+			}
+
+			const boost::optional< std::string >& getSubscriptionID() const {
+				return subscriptionID;
+			}
+
+			void setSubscriptionID(const boost::optional< std::string >& value) {
+				this->subscriptionID = value ;
+			}
+
+			const boost::posix_time::ptime& getExpiry() const {
+				return expiry;
+			}
+
+			void setExpiry(const boost::posix_time::ptime& value) {
+				this->expiry = value ;
+			}
+
+
+		private:
+			std::string node;
+			JID jid;
+			SubscriptionType subscription;
+			boost::optional< std::string > subscriptionID;
+			boost::posix_time::ptime expiry;
+	};
+}
diff --git a/Swiften/Elements/PubSubItem.cpp b/Swiften/Elements/PubSubItem.cpp
new file mode 100644
index 0000000..ae6206f
--- /dev/null
+++ b/Swiften/Elements/PubSubItem.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubItem.h>
+
+using namespace Swift;
+
+PubSubItem::PubSubItem() {
+}
+
+PubSubItem::~PubSubItem() {
+}
diff --git a/Swiften/Elements/PubSubItem.h b/Swiften/Elements/PubSubItem.h
new file mode 100644
index 0000000..93ff03a
--- /dev/null
+++ b/Swiften/Elements/PubSubItem.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <boost/shared_ptr.hpp>
+#include <vector>
+#include <string>
+
+#include <Swiften/Elements/Payload.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubItem : public Payload {
+		public:
+			
+			PubSubItem();
+			
+			virtual ~PubSubItem();
+
+			const std::vector< boost::shared_ptr<Payload> >& getData() const {
+				return data;
+			}
+
+			void setData(const std::vector< boost::shared_ptr<Payload> >& value) {
+				this->data = value ;
+			}
+
+			void addData(boost::shared_ptr<Payload> value) {
+				this->data.push_back(value);
+			}
+
+			const std::string& getID() const {
+				return id;
+			}
+
+			void setID(const std::string& value) {
+				this->id = value ;
+			}
+
+
+		private:
+			std::vector< boost::shared_ptr<Payload> > data;
+			std::string id;
+	};
+}
diff --git a/Swiften/Elements/PubSubItems.cpp b/Swiften/Elements/PubSubItems.cpp
new file mode 100644
index 0000000..f235e11
--- /dev/null
+++ b/Swiften/Elements/PubSubItems.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubItems.h>
+
+using namespace Swift;
+
+PubSubItems::PubSubItems() {
+}
+
+PubSubItems::~PubSubItems() {
+}
diff --git a/Swiften/Elements/PubSubItems.h b/Swiften/Elements/PubSubItems.h
new file mode 100644
index 0000000..7cd279b
--- /dev/null
+++ b/Swiften/Elements/PubSubItems.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <boost/optional.hpp>
+#include <boost/shared_ptr.hpp>
+#include <vector>
+#include <string>
+
+#include <Swiften/Elements/PubSubItem.h>
+#include <Swiften/Elements/PubSubPayload.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubItems : public PubSubPayload {
+		public:
+			
+			PubSubItems();
+			PubSubItems(const std::string& node) : node(node) {}
+			virtual ~PubSubItems();
+
+			const std::string& getNode() const {
+				return node;
+			}
+
+			void setNode(const std::string& value) {
+				this->node = value ;
+			}
+
+			const std::vector< boost::shared_ptr<PubSubItem> >& getItems() const {
+				return items;
+			}
+
+			void setItems(const std::vector< boost::shared_ptr<PubSubItem> >& value) {
+				this->items = value ;
+			}
+
+			void addItem(boost::shared_ptr<PubSubItem> value) {
+				this->items.push_back(value);
+			}
+
+			const boost::optional< unsigned int >& getMaximumItems() const {
+				return maximumItems;
+			}
+
+			void setMaximumItems(const boost::optional< unsigned int >& value) {
+				this->maximumItems = value ;
+			}
+
+			const boost::optional< std::string >& getSubscriptionID() const {
+				return subscriptionID;
+			}
+
+			void setSubscriptionID(const boost::optional< std::string >& value) {
+				this->subscriptionID = value ;
+			}
+
+
+		private:
+			std::string node;
+			std::vector< boost::shared_ptr<PubSubItem> > items;
+			boost::optional< unsigned int > maximumItems;
+			boost::optional< std::string > subscriptionID;
+	};
+}
diff --git a/Swiften/Elements/PubSubOptions.cpp b/Swiften/Elements/PubSubOptions.cpp
new file mode 100644
index 0000000..22c4054
--- /dev/null
+++ b/Swiften/Elements/PubSubOptions.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubOptions.h>
+
+using namespace Swift;
+
+PubSubOptions::PubSubOptions() {
+}
+
+PubSubOptions::~PubSubOptions() {
+}
diff --git a/Swiften/Elements/PubSubOptions.h b/Swiften/Elements/PubSubOptions.h
new file mode 100644
index 0000000..0e9483e
--- /dev/null
+++ b/Swiften/Elements/PubSubOptions.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <boost/optional.hpp>
+#include <boost/shared_ptr.hpp>
+#include <string>
+
+#include <Swiften/Elements/Form.h>
+#include <Swiften/Elements/PubSubPayload.h>
+#include <Swiften/JID/JID.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubOptions : public PubSubPayload {
+		public:
+			
+			PubSubOptions();
+			
+			virtual ~PubSubOptions();
+
+			const std::string& getNode() const {
+				return node;
+			}
+
+			void setNode(const std::string& value) {
+				this->node = value ;
+			}
+
+			const JID& getJID() const {
+				return jid;
+			}
+
+			void setJID(const JID& value) {
+				this->jid = value ;
+			}
+
+			boost::shared_ptr<Form> getData() const {
+				return data;
+			}
+
+			void setData(boost::shared_ptr<Form> value) {
+				this->data = value ;
+			}
+
+			const boost::optional< std::string >& getSubscriptionID() const {
+				return subscriptionID;
+			}
+
+			void setSubscriptionID(const boost::optional< std::string >& value) {
+				this->subscriptionID = value ;
+			}
+
+
+		private:
+			std::string node;
+			JID jid;
+			boost::shared_ptr<Form> data;
+			boost::optional< std::string > subscriptionID;
+	};
+}
diff --git a/Swiften/Elements/PubSubOwnerAffiliation.cpp b/Swiften/Elements/PubSubOwnerAffiliation.cpp
new file mode 100644
index 0000000..8dc8be6
--- /dev/null
+++ b/Swiften/Elements/PubSubOwnerAffiliation.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubOwnerAffiliation.h>
+
+using namespace Swift;
+
+PubSubOwnerAffiliation::PubSubOwnerAffiliation() : type(None) {
+}
+
+PubSubOwnerAffiliation::~PubSubOwnerAffiliation() {
+}
diff --git a/Swiften/Elements/PubSubOwnerAffiliation.h b/Swiften/Elements/PubSubOwnerAffiliation.h
new file mode 100644
index 0000000..68851d3
--- /dev/null
+++ b/Swiften/Elements/PubSubOwnerAffiliation.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+
+
+#include <Swiften/JID/JID.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubOwnerAffiliation : public Payload {
+		public:
+			enum Type {
+				None,
+				Member,
+				Outcast,
+				Owner,
+				Publisher,
+				PublishOnly
+			};
+
+			PubSubOwnerAffiliation();
+			
+			virtual ~PubSubOwnerAffiliation();
+
+			const JID& getJID() const {
+				return jid;
+			}
+
+			void setJID(const JID& value) {
+				this->jid = value ;
+			}
+
+			Type getType() const {
+				return type;
+			}
+
+			void setType(Type value) {
+				this->type = value ;
+			}
+
+
+		private:
+			JID jid;
+			Type type;
+	};
+}
diff --git a/Swiften/Elements/PubSubOwnerAffiliations.cpp b/Swiften/Elements/PubSubOwnerAffiliations.cpp
new file mode 100644
index 0000000..b87a78a
--- /dev/null
+++ b/Swiften/Elements/PubSubOwnerAffiliations.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubOwnerAffiliations.h>
+
+using namespace Swift;
+
+PubSubOwnerAffiliations::PubSubOwnerAffiliations() {
+}
+
+PubSubOwnerAffiliations::~PubSubOwnerAffiliations() {
+}
diff --git a/Swiften/Elements/PubSubOwnerAffiliations.h b/Swiften/Elements/PubSubOwnerAffiliations.h
new file mode 100644
index 0000000..75578df
--- /dev/null
+++ b/Swiften/Elements/PubSubOwnerAffiliations.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <boost/shared_ptr.hpp>
+#include <vector>
+#include <string>
+
+#include <Swiften/Elements/PubSubOwnerPayload.h>
+#include <Swiften/Elements/PubSubOwnerAffiliation.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubOwnerAffiliations : public PubSubOwnerPayload {
+		public:
+			
+			PubSubOwnerAffiliations();
+			
+			virtual ~PubSubOwnerAffiliations();
+
+			const std::string& getNode() const {
+				return node;
+			}
+
+			void setNode(const std::string& value) {
+				this->node = value ;
+			}
+
+			const std::vector< boost::shared_ptr<PubSubOwnerAffiliation> >& getAffiliations() const {
+				return affiliations;
+			}
+
+			void setAffiliations(const std::vector< boost::shared_ptr<PubSubOwnerAffiliation> >& value) {
+				this->affiliations = value ;
+			}
+
+			void addAffiliation(boost::shared_ptr<PubSubOwnerAffiliation> value) {
+				this->affiliations.push_back(value);
+			}
+
+
+		private:
+			std::string node;
+			std::vector< boost::shared_ptr<PubSubOwnerAffiliation> > affiliations;
+	};
+}
diff --git a/Swiften/Elements/PubSubOwnerConfigure.cpp b/Swiften/Elements/PubSubOwnerConfigure.cpp
new file mode 100644
index 0000000..8db923d
--- /dev/null
+++ b/Swiften/Elements/PubSubOwnerConfigure.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubOwnerConfigure.h>
+
+using namespace Swift;
+
+PubSubOwnerConfigure::PubSubOwnerConfigure() {
+}
+
+PubSubOwnerConfigure::~PubSubOwnerConfigure() {
+}
diff --git a/Swiften/Elements/PubSubOwnerConfigure.h b/Swiften/Elements/PubSubOwnerConfigure.h
new file mode 100644
index 0000000..d882ec4
--- /dev/null
+++ b/Swiften/Elements/PubSubOwnerConfigure.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <boost/optional.hpp>
+#include <boost/shared_ptr.hpp>
+#include <string>
+
+#include <Swiften/Elements/PubSubOwnerPayload.h>
+#include <Swiften/Elements/Form.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubOwnerConfigure : public PubSubOwnerPayload {
+		public:
+			
+			PubSubOwnerConfigure();
+			PubSubOwnerConfigure(const std::string& node) : node(node) {}
+			virtual ~PubSubOwnerConfigure();
+
+			const boost::optional< std::string >& getNode() const {
+				return node;
+			}
+
+			void setNode(const boost::optional< std::string >& value) {
+				this->node = value ;
+			}
+
+			boost::shared_ptr<Form> getData() const {
+				return data;
+			}
+
+			void setData(boost::shared_ptr<Form> value) {
+				this->data = value ;
+			}
+
+
+		private:
+			boost::optional< std::string > node;
+			boost::shared_ptr<Form> data;
+	};
+}
diff --git a/Swiften/Elements/PubSubOwnerDefault.cpp b/Swiften/Elements/PubSubOwnerDefault.cpp
new file mode 100644
index 0000000..ebb51a7
--- /dev/null
+++ b/Swiften/Elements/PubSubOwnerDefault.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubOwnerDefault.h>
+
+using namespace Swift;
+
+PubSubOwnerDefault::PubSubOwnerDefault() {
+}
+
+PubSubOwnerDefault::~PubSubOwnerDefault() {
+}
diff --git a/Swiften/Elements/PubSubOwnerDefault.h b/Swiften/Elements/PubSubOwnerDefault.h
new file mode 100644
index 0000000..1dbd3a2
--- /dev/null
+++ b/Swiften/Elements/PubSubOwnerDefault.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Elements/PubSubOwnerPayload.h>
+#include <Swiften/Elements/Form.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubOwnerDefault : public PubSubOwnerPayload {
+		public:
+			
+			PubSubOwnerDefault();
+			
+			virtual ~PubSubOwnerDefault();
+
+			boost::shared_ptr<Form> getData() const {
+				return data;
+			}
+
+			void setData(boost::shared_ptr<Form> value) {
+				this->data = value ;
+			}
+
+
+		private:
+			boost::shared_ptr<Form> data;
+	};
+}
diff --git a/Swiften/Elements/PubSubOwnerDelete.cpp b/Swiften/Elements/PubSubOwnerDelete.cpp
new file mode 100644
index 0000000..a785424
--- /dev/null
+++ b/Swiften/Elements/PubSubOwnerDelete.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubOwnerDelete.h>
+
+using namespace Swift;
+
+PubSubOwnerDelete::PubSubOwnerDelete() {
+}
+
+PubSubOwnerDelete::~PubSubOwnerDelete() {
+}
diff --git a/Swiften/Elements/PubSubOwnerDelete.h b/Swiften/Elements/PubSubOwnerDelete.h
new file mode 100644
index 0000000..c6bb3e9
--- /dev/null
+++ b/Swiften/Elements/PubSubOwnerDelete.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <boost/shared_ptr.hpp>
+#include <string>
+
+#include <Swiften/Elements/PubSubOwnerPayload.h>
+#include <Swiften/Elements/PubSubOwnerRedirect.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubOwnerDelete : public PubSubOwnerPayload {
+		public:
+			
+			PubSubOwnerDelete();
+			PubSubOwnerDelete(const std::string& node) : node(node) {}
+			virtual ~PubSubOwnerDelete();
+
+			const std::string& getNode() const {
+				return node;
+			}
+
+			void setNode(const std::string& value) {
+				this->node = value ;
+			}
+
+			boost::shared_ptr<PubSubOwnerRedirect> getRedirect() const {
+				return redirect;
+			}
+
+			void setRedirect(boost::shared_ptr<PubSubOwnerRedirect> value) {
+				this->redirect = value ;
+			}
+
+
+		private:
+			std::string node;
+			boost::shared_ptr<PubSubOwnerRedirect> redirect;
+	};
+}
diff --git a/Swiften/Elements/PubSubOwnerPayload.cpp b/Swiften/Elements/PubSubOwnerPayload.cpp
new file mode 100644
index 0000000..92c1dd2
--- /dev/null
+++ b/Swiften/Elements/PubSubOwnerPayload.cpp
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubOwnerPayload.h>
+
+using namespace Swift;
+
+PubSubOwnerPayload::~PubSubOwnerPayload() {
+}
diff --git a/Swiften/Elements/PubSubOwnerPayload.h b/Swiften/Elements/PubSubOwnerPayload.h
new file mode 100644
index 0000000..a2ddaaa
--- /dev/null
+++ b/Swiften/Elements/PubSubOwnerPayload.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubOwnerPayload : public Payload {
+		public:
+			virtual ~PubSubOwnerPayload();
+	};
+}
diff --git a/Swiften/Elements/PubSubOwnerPubSub.cpp b/Swiften/Elements/PubSubOwnerPubSub.cpp
new file mode 100644
index 0000000..022452d
--- /dev/null
+++ b/Swiften/Elements/PubSubOwnerPubSub.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubOwnerPubSub.h>
+
+using namespace Swift;
+
+PubSubOwnerPubSub::PubSubOwnerPubSub() {
+}
+
+PubSubOwnerPubSub::~PubSubOwnerPubSub() {
+}
diff --git a/Swiften/Elements/PubSubOwnerPubSub.h b/Swiften/Elements/PubSubOwnerPubSub.h
new file mode 100644
index 0000000..dd72abe
--- /dev/null
+++ b/Swiften/Elements/PubSubOwnerPubSub.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/ContainerPayload.h>
+
+#include <Swiften/Elements/PubSubOwnerPayload.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubOwnerPubSub : public ContainerPayload<PubSubOwnerPayload> {
+		public:
+			PubSubOwnerPubSub();
+			virtual ~PubSubOwnerPubSub();
+	};
+}
diff --git a/Swiften/Elements/PubSubOwnerPurge.cpp b/Swiften/Elements/PubSubOwnerPurge.cpp
new file mode 100644
index 0000000..d0ac57d
--- /dev/null
+++ b/Swiften/Elements/PubSubOwnerPurge.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubOwnerPurge.h>
+
+using namespace Swift;
+
+PubSubOwnerPurge::PubSubOwnerPurge() {
+}
+
+PubSubOwnerPurge::~PubSubOwnerPurge() {
+}
diff --git a/Swiften/Elements/PubSubOwnerPurge.h b/Swiften/Elements/PubSubOwnerPurge.h
new file mode 100644
index 0000000..fc410f8
--- /dev/null
+++ b/Swiften/Elements/PubSubOwnerPurge.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <string>
+
+#include <Swiften/Elements/PubSubOwnerPayload.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubOwnerPurge : public PubSubOwnerPayload {
+		public:
+			
+			PubSubOwnerPurge();
+			
+			virtual ~PubSubOwnerPurge();
+
+			const std::string& getNode() const {
+				return node;
+			}
+
+			void setNode(const std::string& value) {
+				this->node = value ;
+			}
+
+
+		private:
+			std::string node;
+	};
+}
diff --git a/Swiften/Elements/PubSubOwnerRedirect.cpp b/Swiften/Elements/PubSubOwnerRedirect.cpp
new file mode 100644
index 0000000..164c216
--- /dev/null
+++ b/Swiften/Elements/PubSubOwnerRedirect.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubOwnerRedirect.h>
+
+using namespace Swift;
+
+PubSubOwnerRedirect::PubSubOwnerRedirect() {
+}
+
+PubSubOwnerRedirect::~PubSubOwnerRedirect() {
+}
diff --git a/Swiften/Elements/PubSubOwnerRedirect.h b/Swiften/Elements/PubSubOwnerRedirect.h
new file mode 100644
index 0000000..61db1d1
--- /dev/null
+++ b/Swiften/Elements/PubSubOwnerRedirect.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <string>
+
+
+
+namespace Swift {
+	class SWIFTEN_API PubSubOwnerRedirect : public Payload {
+		public:
+			
+			PubSubOwnerRedirect();
+			
+			virtual ~PubSubOwnerRedirect();
+
+			const std::string& getURI() const {
+				return uri;
+			}
+
+			void setURI(const std::string& value) {
+				this->uri = value ;
+			}
+
+
+		private:
+			std::string uri;
+	};
+}
diff --git a/Swiften/Elements/PubSubOwnerSubscription.cpp b/Swiften/Elements/PubSubOwnerSubscription.cpp
new file mode 100644
index 0000000..3334e36
--- /dev/null
+++ b/Swiften/Elements/PubSubOwnerSubscription.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubOwnerSubscription.h>
+
+using namespace Swift;
+
+PubSubOwnerSubscription::PubSubOwnerSubscription() : subscription(None) {
+}
+
+PubSubOwnerSubscription::~PubSubOwnerSubscription() {
+}
diff --git a/Swiften/Elements/PubSubOwnerSubscription.h b/Swiften/Elements/PubSubOwnerSubscription.h
new file mode 100644
index 0000000..1c302df
--- /dev/null
+++ b/Swiften/Elements/PubSubOwnerSubscription.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+
+
+#include <Swiften/JID/JID.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubOwnerSubscription : public Payload {
+		public:
+			enum SubscriptionType {
+				None,
+				Pending,
+				Subscribed,
+				Unconfigured
+			};
+
+			PubSubOwnerSubscription();
+			
+			virtual ~PubSubOwnerSubscription();
+
+			const JID& getJID() const {
+				return jid;
+			}
+
+			void setJID(const JID& value) {
+				this->jid = value ;
+			}
+
+			SubscriptionType getSubscription() const {
+				return subscription;
+			}
+
+			void setSubscription(SubscriptionType value) {
+				this->subscription = value ;
+			}
+
+
+		private:
+			JID jid;
+			SubscriptionType subscription;
+	};
+}
diff --git a/Swiften/Elements/PubSubOwnerSubscriptions.cpp b/Swiften/Elements/PubSubOwnerSubscriptions.cpp
new file mode 100644
index 0000000..a4deb59
--- /dev/null
+++ b/Swiften/Elements/PubSubOwnerSubscriptions.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubOwnerSubscriptions.h>
+
+using namespace Swift;
+
+PubSubOwnerSubscriptions::PubSubOwnerSubscriptions() {
+}
+
+PubSubOwnerSubscriptions::~PubSubOwnerSubscriptions() {
+}
diff --git a/Swiften/Elements/PubSubOwnerSubscriptions.h b/Swiften/Elements/PubSubOwnerSubscriptions.h
new file mode 100644
index 0000000..08a2f5c
--- /dev/null
+++ b/Swiften/Elements/PubSubOwnerSubscriptions.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <boost/shared_ptr.hpp>
+#include <vector>
+#include <string>
+
+#include <Swiften/Elements/PubSubOwnerPayload.h>
+#include <Swiften/Elements/PubSubOwnerSubscription.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubOwnerSubscriptions : public PubSubOwnerPayload {
+		public:
+			
+			PubSubOwnerSubscriptions();
+			
+			virtual ~PubSubOwnerSubscriptions();
+
+			const std::string& getNode() const {
+				return node;
+			}
+
+			void setNode(const std::string& value) {
+				this->node = value ;
+			}
+
+			const std::vector< boost::shared_ptr<PubSubOwnerSubscription> >& getSubscriptions() const {
+				return subscriptions;
+			}
+
+			void setSubscriptions(const std::vector< boost::shared_ptr<PubSubOwnerSubscription> >& value) {
+				this->subscriptions = value ;
+			}
+
+			void addSubscription(boost::shared_ptr<PubSubOwnerSubscription> value) {
+				this->subscriptions.push_back(value);
+			}
+
+
+		private:
+			std::string node;
+			std::vector< boost::shared_ptr<PubSubOwnerSubscription> > subscriptions;
+	};
+}
diff --git a/Swiften/Elements/PubSubPayload.cpp b/Swiften/Elements/PubSubPayload.cpp
new file mode 100644
index 0000000..b529959
--- /dev/null
+++ b/Swiften/Elements/PubSubPayload.cpp
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubPayload.h>
+
+using namespace Swift;
+
+PubSubPayload::~PubSubPayload() {
+}
diff --git a/Swiften/Elements/PubSubPayload.h b/Swiften/Elements/PubSubPayload.h
new file mode 100644
index 0000000..476939b
--- /dev/null
+++ b/Swiften/Elements/PubSubPayload.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubPayload : public Payload {
+		public:
+			virtual ~PubSubPayload();
+	};
+}
diff --git a/Swiften/Elements/PubSubPublish.cpp b/Swiften/Elements/PubSubPublish.cpp
new file mode 100644
index 0000000..2ee3880
--- /dev/null
+++ b/Swiften/Elements/PubSubPublish.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubPublish.h>
+
+using namespace Swift;
+
+PubSubPublish::PubSubPublish() {
+}
+
+PubSubPublish::~PubSubPublish() {
+}
diff --git a/Swiften/Elements/PubSubPublish.h b/Swiften/Elements/PubSubPublish.h
new file mode 100644
index 0000000..1d99420
--- /dev/null
+++ b/Swiften/Elements/PubSubPublish.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <boost/shared_ptr.hpp>
+#include <vector>
+#include <string>
+
+#include <Swiften/Elements/PubSubItem.h>
+#include <Swiften/Elements/PubSubPayload.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubPublish : public PubSubPayload {
+		public:
+			
+			PubSubPublish();
+			
+			virtual ~PubSubPublish();
+
+			const std::string& getNode() const {
+				return node;
+			}
+
+			void setNode(const std::string& value) {
+				this->node = value ;
+			}
+
+			const std::vector< boost::shared_ptr<PubSubItem> >& getItems() const {
+				return items;
+			}
+
+			void setItems(const std::vector< boost::shared_ptr<PubSubItem> >& value) {
+				this->items = value ;
+			}
+
+			void addItem(boost::shared_ptr<PubSubItem> value) {
+				this->items.push_back(value);
+			}
+
+
+		private:
+			std::string node;
+			std::vector< boost::shared_ptr<PubSubItem> > items;
+	};
+}
diff --git a/Swiften/Elements/PubSubRetract.cpp b/Swiften/Elements/PubSubRetract.cpp
new file mode 100644
index 0000000..7e3676e
--- /dev/null
+++ b/Swiften/Elements/PubSubRetract.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubRetract.h>
+
+using namespace Swift;
+
+PubSubRetract::PubSubRetract() {
+}
+
+PubSubRetract::~PubSubRetract() {
+}
diff --git a/Swiften/Elements/PubSubRetract.h b/Swiften/Elements/PubSubRetract.h
new file mode 100644
index 0000000..e55897b
--- /dev/null
+++ b/Swiften/Elements/PubSubRetract.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <boost/shared_ptr.hpp>
+#include <vector>
+#include <string>
+
+#include <Swiften/Elements/PubSubItem.h>
+#include <Swiften/Elements/PubSubPayload.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubRetract : public PubSubPayload {
+		public:
+			
+			PubSubRetract();
+			
+			virtual ~PubSubRetract();
+
+			const std::string& getNode() const {
+				return node;
+			}
+
+			void setNode(const std::string& value) {
+				this->node = value ;
+			}
+
+			const std::vector< boost::shared_ptr<PubSubItem> >& getItems() const {
+				return items;
+			}
+
+			void setItems(const std::vector< boost::shared_ptr<PubSubItem> >& value) {
+				this->items = value ;
+			}
+
+			void addItem(boost::shared_ptr<PubSubItem> value) {
+				this->items.push_back(value);
+			}
+
+			bool isNotify() const {
+				return notify;
+			}
+
+			void setNotify(bool value) {
+				this->notify = value ;
+			}
+
+
+		private:
+			std::string node;
+			std::vector< boost::shared_ptr<PubSubItem> > items;
+			bool notify;
+	};
+}
diff --git a/Swiften/Elements/PubSubSubscribe.cpp b/Swiften/Elements/PubSubSubscribe.cpp
new file mode 100644
index 0000000..4720321
--- /dev/null
+++ b/Swiften/Elements/PubSubSubscribe.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubSubscribe.h>
+
+using namespace Swift;
+
+PubSubSubscribe::PubSubSubscribe() {
+}
+
+PubSubSubscribe::~PubSubSubscribe() {
+}
diff --git a/Swiften/Elements/PubSubSubscribe.h b/Swiften/Elements/PubSubSubscribe.h
new file mode 100644
index 0000000..e2cc4ae
--- /dev/null
+++ b/Swiften/Elements/PubSubSubscribe.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <boost/optional.hpp>
+#include <boost/shared_ptr.hpp>
+#include <string>
+
+#include <Swiften/Elements/PubSubOptions.h>
+#include <Swiften/Elements/PubSubPayload.h>
+#include <Swiften/JID/JID.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubSubscribe : public PubSubPayload {
+		public:
+			
+			PubSubSubscribe();
+			
+			virtual ~PubSubSubscribe();
+
+			const boost::optional< std::string >& getNode() const {
+				return node;
+			}
+
+			void setNode(const boost::optional< std::string >& value) {
+				this->node = value ;
+			}
+
+			const JID& getJID() const {
+				return jid;
+			}
+
+			void setJID(const JID& value) {
+				this->jid = value ;
+			}
+
+			boost::shared_ptr<PubSubOptions> getOptions() const {
+				return options;
+			}
+
+			void setOptions(boost::shared_ptr<PubSubOptions> value) {
+				this->options = value ;
+			}
+
+
+		private:
+			boost::optional< std::string > node;
+			JID jid;
+			boost::shared_ptr<PubSubOptions> options;
+	};
+}
diff --git a/Swiften/Elements/PubSubSubscribeOptions.cpp b/Swiften/Elements/PubSubSubscribeOptions.cpp
new file mode 100644
index 0000000..8770620
--- /dev/null
+++ b/Swiften/Elements/PubSubSubscribeOptions.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubSubscribeOptions.h>
+
+using namespace Swift;
+
+PubSubSubscribeOptions::PubSubSubscribeOptions() {
+}
+
+PubSubSubscribeOptions::~PubSubSubscribeOptions() {
+}
diff --git a/Swiften/Elements/PubSubSubscribeOptions.h b/Swiften/Elements/PubSubSubscribeOptions.h
new file mode 100644
index 0000000..6612d82
--- /dev/null
+++ b/Swiften/Elements/PubSubSubscribeOptions.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+
+
+
+
+namespace Swift {
+	class SWIFTEN_API PubSubSubscribeOptions : public Payload {
+		public:
+			
+			PubSubSubscribeOptions();
+			
+			virtual ~PubSubSubscribeOptions();
+
+			bool isRequired() const {
+				return required;
+			}
+
+			void setRequired(bool value) {
+				this->required = value ;
+			}
+
+
+		private:
+			bool required;
+	};
+}
diff --git a/Swiften/Elements/PubSubSubscription.cpp b/Swiften/Elements/PubSubSubscription.cpp
new file mode 100644
index 0000000..a25fc06
--- /dev/null
+++ b/Swiften/Elements/PubSubSubscription.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubSubscription.h>
+
+using namespace Swift;
+
+PubSubSubscription::PubSubSubscription() : subscription(None) {
+}
+
+PubSubSubscription::~PubSubSubscription() {
+}
diff --git a/Swiften/Elements/PubSubSubscription.h b/Swiften/Elements/PubSubSubscription.h
new file mode 100644
index 0000000..977cd55
--- /dev/null
+++ b/Swiften/Elements/PubSubSubscription.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <boost/optional.hpp>
+#include <boost/shared_ptr.hpp>
+#include <string>
+
+#include <Swiften/Elements/PubSubSubscribeOptions.h>
+#include <Swiften/Elements/PubSubPayload.h>
+#include <Swiften/JID/JID.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubSubscription : public PubSubPayload {
+		public:
+			enum SubscriptionType {
+				None,
+				Pending,
+				Subscribed,
+				Unconfigured
+			};
+
+			PubSubSubscription();
+			
+			virtual ~PubSubSubscription();
+
+			const boost::optional< std::string >& getNode() const {
+				return node;
+			}
+
+			void setNode(const boost::optional< std::string >& value) {
+				this->node = value ;
+			}
+
+			const boost::optional< std::string >& getSubscriptionID() const {
+				return subscriptionID;
+			}
+
+			void setSubscriptionID(const boost::optional< std::string >& value) {
+				this->subscriptionID = value ;
+			}
+
+			const JID& getJID() const {
+				return jid;
+			}
+
+			void setJID(const JID& value) {
+				this->jid = value ;
+			}
+
+			boost::shared_ptr<PubSubSubscribeOptions> getOptions() const {
+				return options;
+			}
+
+			void setOptions(boost::shared_ptr<PubSubSubscribeOptions> value) {
+				this->options = value ;
+			}
+
+			SubscriptionType getSubscription() const {
+				return subscription;
+			}
+
+			void setSubscription(SubscriptionType value) {
+				this->subscription = value ;
+			}
+
+
+		private:
+			boost::optional< std::string > node;
+			boost::optional< std::string > subscriptionID;
+			JID jid;
+			boost::shared_ptr<PubSubSubscribeOptions> options;
+			SubscriptionType subscription;
+	};
+}
diff --git a/Swiften/Elements/PubSubSubscriptions.cpp b/Swiften/Elements/PubSubSubscriptions.cpp
new file mode 100644
index 0000000..626e122
--- /dev/null
+++ b/Swiften/Elements/PubSubSubscriptions.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubSubscriptions.h>
+
+using namespace Swift;
+
+PubSubSubscriptions::PubSubSubscriptions() {
+}
+
+PubSubSubscriptions::~PubSubSubscriptions() {
+}
diff --git a/Swiften/Elements/PubSubSubscriptions.h b/Swiften/Elements/PubSubSubscriptions.h
new file mode 100644
index 0000000..c7c19c5
--- /dev/null
+++ b/Swiften/Elements/PubSubSubscriptions.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <boost/optional.hpp>
+#include <boost/shared_ptr.hpp>
+#include <vector>
+#include <string>
+
+#include <Swiften/Elements/PubSubSubscription.h>
+#include <Swiften/Elements/PubSubPayload.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubSubscriptions : public PubSubPayload {
+		public:
+			
+			PubSubSubscriptions();
+			PubSubSubscriptions(const std::string& node) : node(node) {}
+			virtual ~PubSubSubscriptions();
+
+			const boost::optional< std::string >& getNode() const {
+				return node;
+			}
+
+			void setNode(const boost::optional< std::string >& value) {
+				this->node = value ;
+			}
+
+			const std::vector< boost::shared_ptr<PubSubSubscription> >& getSubscriptions() const {
+				return subscriptions;
+			}
+
+			void setSubscriptions(const std::vector< boost::shared_ptr<PubSubSubscription> >& value) {
+				this->subscriptions = value ;
+			}
+
+			void addSubscription(boost::shared_ptr<PubSubSubscription> value) {
+				this->subscriptions.push_back(value);
+			}
+
+
+		private:
+			boost::optional< std::string > node;
+			std::vector< boost::shared_ptr<PubSubSubscription> > subscriptions;
+	};
+}
diff --git a/Swiften/Elements/PubSubUnsubscribe.cpp b/Swiften/Elements/PubSubUnsubscribe.cpp
new file mode 100644
index 0000000..a4b8318
--- /dev/null
+++ b/Swiften/Elements/PubSubUnsubscribe.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/PubSubUnsubscribe.h>
+
+using namespace Swift;
+
+PubSubUnsubscribe::PubSubUnsubscribe() {
+}
+
+PubSubUnsubscribe::~PubSubUnsubscribe() {
+}
diff --git a/Swiften/Elements/PubSubUnsubscribe.h b/Swiften/Elements/PubSubUnsubscribe.h
new file mode 100644
index 0000000..3969376
--- /dev/null
+++ b/Swiften/Elements/PubSubUnsubscribe.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <boost/optional.hpp>
+#include <string>
+
+#include <Swiften/Elements/PubSubPayload.h>
+#include <Swiften/JID/JID.h>
+
+namespace Swift {
+	class SWIFTEN_API PubSubUnsubscribe : public PubSubPayload {
+		public:
+			
+			PubSubUnsubscribe();
+			
+			virtual ~PubSubUnsubscribe();
+
+			const boost::optional< std::string >& getNode() const {
+				return node;
+			}
+
+			void setNode(const boost::optional< std::string >& value) {
+				this->node = value ;
+			}
+
+			const JID& getJID() const {
+				return jid;
+			}
+
+			void setJID(const JID& value) {
+				this->jid = value ;
+			}
+
+			const boost::optional< std::string >& getSubscriptionID() const {
+				return subscriptionID;
+			}
+
+			void setSubscriptionID(const boost::optional< std::string >& value) {
+				this->subscriptionID = value ;
+			}
+
+
+		private:
+			boost::optional< std::string > node;
+			JID jid;
+			boost::optional< std::string > subscriptionID;
+	};
+}
diff --git a/Swiften/Elements/UserLocation.cpp b/Swiften/Elements/UserLocation.cpp
new file mode 100644
index 0000000..f22973e
--- /dev/null
+++ b/Swiften/Elements/UserLocation.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/UserLocation.h>
+
+using namespace Swift;
+
+UserLocation::UserLocation() {
+}
+
+UserLocation::~UserLocation() {
+}
diff --git a/Swiften/Elements/UserLocation.h b/Swiften/Elements/UserLocation.h
new file mode 100644
index 0000000..2355838
--- /dev/null
+++ b/Swiften/Elements/UserLocation.h
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <boost/optional.hpp>
+#include <string>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+
+
+namespace Swift {
+	class SWIFTEN_API UserLocation : public Payload {
+		public:
+			
+			UserLocation();
+			
+			virtual ~UserLocation();
+
+			const boost::optional< std::string >& getArea() const {
+				return area;
+			}
+
+			void setArea(const boost::optional< std::string >& value) {
+				this->area = value ;
+			}
+
+			const boost::optional< float >& getAltitude() const {
+				return altitude;
+			}
+
+			void setAltitude(const boost::optional< float >& value) {
+				this->altitude = value ;
+			}
+
+			const boost::optional< std::string >& getLocality() const {
+				return locality;
+			}
+
+			void setLocality(const boost::optional< std::string >& value) {
+				this->locality = value ;
+			}
+
+			const boost::optional< float >& getLatitude() const {
+				return latitude;
+			}
+
+			void setLatitude(const boost::optional< float >& value) {
+				this->latitude = value ;
+			}
+
+			const boost::optional< float >& getAccuracy() const {
+				return accuracy;
+			}
+
+			void setAccuracy(const boost::optional< float >& value) {
+				this->accuracy = value ;
+			}
+
+			const boost::optional< std::string >& getDescription() const {
+				return description;
+			}
+
+			void setDescription(const boost::optional< std::string >& value) {
+				this->description = value ;
+			}
+
+			const boost::optional< std::string >& getCountryCode() const {
+				return countryCode;
+			}
+
+			void setCountryCode(const boost::optional< std::string >& value) {
+				this->countryCode = value ;
+			}
+
+			const boost::optional< boost::posix_time::ptime >& getTimestamp() const {
+				return timestamp;
+			}
+
+			void setTimestamp(const boost::optional< boost::posix_time::ptime >& value) {
+				this->timestamp = value ;
+			}
+
+			const boost::optional< std::string >& getFloor() const {
+				return floor;
+			}
+
+			void setFloor(const boost::optional< std::string >& value) {
+				this->floor = value ;
+			}
+
+			const boost::optional< std::string >& getBuilding() const {
+				return building;
+			}
+
+			void setBuilding(const boost::optional< std::string >& value) {
+				this->building = value ;
+			}
+
+			const boost::optional< std::string >& getRoom() const {
+				return room;
+			}
+
+			void setRoom(const boost::optional< std::string >& value) {
+				this->room = value ;
+			}
+
+			const boost::optional< std::string >& getCountry() const {
+				return country;
+			}
+
+			void setCountry(const boost::optional< std::string >& value) {
+				this->country = value ;
+			}
+
+			const boost::optional< std::string >& getRegion() const {
+				return region;
+			}
+
+			void setRegion(const boost::optional< std::string >& value) {
+				this->region = value ;
+			}
+
+			const boost::optional< std::string >& getURI() const {
+				return uri;
+			}
+
+			void setURI(const boost::optional< std::string >& value) {
+				this->uri = value ;
+			}
+
+			const boost::optional< float >& getLongitude() const {
+				return longitude;
+			}
+
+			void setLongitude(const boost::optional< float >& value) {
+				this->longitude = value ;
+			}
+
+			const boost::optional< float >& getError() const {
+				return error;
+			}
+
+			void setError(const boost::optional< float >& value) {
+				this->error = value ;
+			}
+
+			const boost::optional< std::string >& getPostalCode() const {
+				return postalCode;
+			}
+
+			void setPostalCode(const boost::optional< std::string >& value) {
+				this->postalCode = value ;
+			}
+
+			const boost::optional< float >& getBearing() const {
+				return bearing;
+			}
+
+			void setBearing(const boost::optional< float >& value) {
+				this->bearing = value ;
+			}
+
+			const boost::optional< std::string >& getText() const {
+				return text;
+			}
+
+			void setText(const boost::optional< std::string >& value) {
+				this->text = value ;
+			}
+
+			const boost::optional< std::string >& getDatum() const {
+				return datum;
+			}
+
+			void setDatum(const boost::optional< std::string >& value) {
+				this->datum = value ;
+			}
+
+			const boost::optional< std::string >& getStreet() const {
+				return street;
+			}
+
+			void setStreet(const boost::optional< std::string >& value) {
+				this->street = value ;
+			}
+
+			const boost::optional< float >& getSpeed() const {
+				return speed;
+			}
+
+			void setSpeed(const boost::optional< float >& value) {
+				this->speed = value ;
+			}
+
+
+		private:
+			boost::optional< std::string > area;
+			boost::optional< float > altitude;
+			boost::optional< std::string > locality;
+			boost::optional< float > latitude;
+			boost::optional< float > accuracy;
+			boost::optional< std::string > description;
+			boost::optional< std::string > countryCode;
+			boost::optional< boost::posix_time::ptime > timestamp;
+			boost::optional< std::string > floor;
+			boost::optional< std::string > building;
+			boost::optional< std::string > room;
+			boost::optional< std::string > country;
+			boost::optional< std::string > region;
+			boost::optional< std::string > uri;
+			boost::optional< float > longitude;
+			boost::optional< float > error;
+			boost::optional< std::string > postalCode;
+			boost::optional< float > bearing;
+			boost::optional< std::string > text;
+			boost::optional< std::string > datum;
+			boost::optional< std::string > street;
+			boost::optional< float > speed;
+	};
+}
diff --git a/Swiften/JID/JID.cpp b/Swiften/JID/JID.cpp
index e1502f1..0f2d8d1 100644
--- a/Swiften/JID/JID.cpp
+++ b/Swiften/JID/JID.cpp
@@ -18,6 +18,7 @@
 #include <boost/assign/list_of.hpp>
 #include <boost/algorithm/string/find_format.hpp>
 #include <boost/algorithm/string/finder.hpp>
+#include <boost/optional.hpp>
 #include <iostream>
 #include <sstream>
 
@@ -317,4 +318,9 @@ std::ostream& operator<<(std::ostream& os, const JID& j) {
 	return os;
 }
 
+boost::optional<JID> JID::parse(const std::string& s) {
+	JID jid(s);
+	return jid.isValid() ? jid : boost::optional<JID>();
+}
+
 }
diff --git a/Swiften/JID/JID.h b/Swiften/JID/JID.h
index eac1e2a..126a7b1 100644
--- a/Swiften/JID/JID.h
+++ b/Swiften/JID/JID.h
@@ -10,7 +10,7 @@
 #include <iosfwd>
 
 #include <Swiften/Base/API.h>
-
+#include <boost/optional/optional_fwd.hpp>
 
 namespace Swift {
 	class IDNConverter;
@@ -160,6 +160,11 @@ namespace Swift {
 				return a.compare(b, Swift::JID::WithResource) != 0;
 			}
 
+			/**
+			 * Returns an empty optional if the JID is invalid, and an
+			 * optional with a value if the JID is valid.
+			 */
+			static boost::optional<JID> parse(const std::string&);
 
 			/**
 			 * If Swiften was compiled with SWIFTEN_JID_NO_DEFAULT_IDN_CONVERTER (not default), use this method at 
diff --git a/Swiften/Parser/GenericPayloadParserFactory2.h b/Swiften/Parser/GenericPayloadParserFactory2.h
new file mode 100644
index 0000000..f24b64e
--- /dev/null
+++ b/Swiften/Parser/GenericPayloadParserFactory2.h
@@ -0,0 +1,39 @@
+/*
+ * 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/Parser/PayloadParserFactory.h>
+#include <string>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+
+	/**
+	 * A generic class for PayloadParserFactories that parse a specific payload (given as the template parameter of the class).
+	 */
+	template<typename PARSER_TYPE>
+	class GenericPayloadParserFactory2 : public PayloadParserFactory {
+		public:
+			/**
+			 * Construct a parser factory that can parse the given top-level tag in the given namespace.
+			 */
+			GenericPayloadParserFactory2(const std::string& tag, const std::string& xmlns, PayloadParserFactoryCollection* parsers) : tag_(tag), xmlns_(xmlns), parsers_(parsers) {}
+
+			virtual bool canParse(const std::string& element, const std::string& ns, const AttributeMap&) const {
+				return (tag_.empty() ? true : element == tag_) && (xmlns_.empty() ? true : xmlns_ == ns);
+			}
+
+			virtual PayloadParser* createPayloadParser() {
+				return new PARSER_TYPE(parsers_);
+			}
+
+		private:
+			std::string tag_;
+			std::string xmlns_;
+			PayloadParserFactoryCollection* parsers_;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp
index 1797e45..3ec5a7a 100644
--- a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp
+++ b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2012 Remko Tronçon
+ * Copyright (c) 2010-2013 Remko Tronçon
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -10,6 +10,8 @@
 #include <Swiften/Elements/UnblockPayload.h>
 #include <Swiften/Elements/BlockListPayload.h>
 #include <Swiften/Parser/GenericPayloadParser.h>
+#include <Swiften/Parser/GenericPayloadParserFactory.h>
+#include <Swiften/Parser/GenericPayloadParserFactory2.h>
 #include <Swiften/Parser/PayloadParserFactory.h>
 #include <Swiften/Parser/PayloadParsers/ErrorParser.h>
 #include <Swiften/Parser/PayloadParsers/ErrorParserFactory.h>
@@ -68,6 +70,11 @@
 #include <Swiften/Parser/PayloadParsers/DeliveryReceiptRequestParserFactory.h>
 #include <Swiften/Parser/PayloadParsers/WhiteboardParser.h>
 #include <Swiften/Parser/PayloadParsers/IdleParser.h>
+#include <Swiften/Parser/PayloadParsers/PubSubParser.h>
+#include <Swiften/Parser/PayloadParsers/PubSubOwnerPubSubParser.h>
+#include <Swiften/Parser/PayloadParsers/PubSubEventParser.h>
+#include <Swiften/Parser/PayloadParsers/PubSubErrorParserFactory.h>
+#include <Swiften/Parser/PayloadParsers/UserLocationParser.h>
 
 using namespace boost;
 
@@ -127,9 +134,14 @@ FullPayloadParserFactoryCollection::FullPayloadParserFactoryCollection() {
 	factories_.push_back(boost::make_shared<GenericPayloadParserFactory<JingleFileTransferHashParser> >("checksum"));
 	factories_.push_back(boost::make_shared<GenericPayloadParserFactory<S5BProxyRequestParser> >("query", "http://jabber.org/protocol/bytestreams"));
 	factories_.push_back(boost::make_shared<GenericPayloadParserFactory<WhiteboardParser> >("wb", "http://swift.im/whiteboard"));
+	factories_.push_back(boost::make_shared<GenericPayloadParserFactory<UserLocationParser> >("geoloc", "http://jabber.org/protocol/geoloc"));
 	factories_.push_back(boost::make_shared<DeliveryReceiptParserFactory>());
 	factories_.push_back(boost::make_shared<DeliveryReceiptRequestParserFactory>());
 	factories_.push_back(boost::make_shared<GenericPayloadParserFactory<IdleParser> >("idle", "urn:xmpp:idle:1"));
+	factories_.push_back(boost::make_shared<GenericPayloadParserFactory2<PubSubParser> >("pubsub", "http://jabber.org/protocol/pubsub", this));
+	factories_.push_back(boost::make_shared<GenericPayloadParserFactory2<PubSubOwnerPubSubParser> >("pubsub", "http://jabber.org/protocol/pubsub#owner", this));
+	factories_.push_back(boost::make_shared<GenericPayloadParserFactory2<PubSubEventParser> >("event", "http://jabber.org/protocol/pubsub#event", this));
+	factories_.push_back(boost::make_shared<PubSubErrorParserFactory>());
 
 	foreach(shared_ptr<PayloadParserFactory> factory, factories_) {
 		addFactory(factory.get());
diff --git a/Swiften/Parser/PayloadParsers/PubSubAffiliationParser.cpp b/Swiften/Parser/PayloadParsers/PubSubAffiliationParser.cpp
new file mode 100644
index 0000000..05fa119
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubAffiliationParser.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubAffiliationParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+#include <Swiften/Parser/EnumParser.h>
+
+using namespace Swift;
+
+PubSubAffiliationParser::PubSubAffiliationParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubAffiliationParser::~PubSubAffiliationParser() {
+}
+
+void PubSubAffiliationParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) {
+			getPayloadInternal()->setNode(*attributeValue);
+		}
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("affiliation")) {
+			if (boost::optional<PubSubAffiliation::Type> value = EnumParser<PubSubAffiliation::Type>()(PubSubAffiliation::None, "none")(PubSubAffiliation::Member, "member")(PubSubAffiliation::Outcast, "outcast")(PubSubAffiliation::Owner, "owner")(PubSubAffiliation::Publisher, "publisher")(PubSubAffiliation::PublishOnly, "publish-only").parse(*attributeValue)) {
+				getPayloadInternal()->setType(*value);
+			}
+		}
+	}
+
+	
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubAffiliationParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubAffiliationParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubAffiliationParser.h b/Swiften/Parser/PayloadParsers/PubSubAffiliationParser.h
new file mode 100644
index 0000000..43c619d
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubAffiliationParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubAffiliation.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubAffiliationParser : public GenericPayloadParser<PubSubAffiliation> {
+		public:
+			PubSubAffiliationParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubAffiliationParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubAffiliationsParser.cpp b/Swiften/Parser/PayloadParsers/PubSubAffiliationsParser.cpp
new file mode 100644
index 0000000..b75e339
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubAffiliationsParser.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubAffiliationsParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+#include <Swiften/Parser/PayloadParsers/PubSubAffiliationParser.h>
+
+using namespace Swift;
+
+PubSubAffiliationsParser::PubSubAffiliationsParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubAffiliationsParser::~PubSubAffiliationsParser() {
+}
+
+void PubSubAffiliationsParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) {
+			getPayloadInternal()->setNode(*attributeValue);
+		}
+	}
+
+	if (level == 1) {
+		if (element == "affiliation" && ns == "http://jabber.org/protocol/pubsub") {
+			currentPayloadParser = boost::make_shared<PubSubAffiliationParser>(parsers);
+		}
+	}
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubAffiliationsParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			if (element == "affiliation" && ns == "http://jabber.org/protocol/pubsub") {
+				getPayloadInternal()->addAffiliation(boost::dynamic_pointer_cast<PubSubAffiliation>(currentPayloadParser->getPayload()));
+			}
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubAffiliationsParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubAffiliationsParser.h b/Swiften/Parser/PayloadParsers/PubSubAffiliationsParser.h
new file mode 100644
index 0000000..646e7a8
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubAffiliationsParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubAffiliations.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubAffiliationsParser : public GenericPayloadParser<PubSubAffiliations> {
+		public:
+			PubSubAffiliationsParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubAffiliationsParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubConfigureParser.cpp b/Swiften/Parser/PayloadParsers/PubSubConfigureParser.cpp
new file mode 100644
index 0000000..773c1c7
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubConfigureParser.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubConfigureParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+#include <Swiften/Parser/PayloadParsers/FormParser.h>
+
+using namespace Swift;
+
+PubSubConfigureParser::PubSubConfigureParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubConfigureParser::~PubSubConfigureParser() {
+}
+
+void PubSubConfigureParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	
+
+	if (level == 1) {
+		if (element == "x" && ns == "jabber:x:data") {
+			currentPayloadParser = boost::make_shared<FormParser>();
+		}
+	}
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubConfigureParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			if (element == "x" && ns == "jabber:x:data") {
+				getPayloadInternal()->setData(boost::dynamic_pointer_cast<Form>(currentPayloadParser->getPayload()));
+			}
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubConfigureParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubConfigureParser.h b/Swiften/Parser/PayloadParsers/PubSubConfigureParser.h
new file mode 100644
index 0000000..8300140
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubConfigureParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubConfigure.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubConfigureParser : public GenericPayloadParser<PubSubConfigure> {
+		public:
+			PubSubConfigureParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubConfigureParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubCreateParser.cpp b/Swiften/Parser/PayloadParsers/PubSubCreateParser.cpp
new file mode 100644
index 0000000..47f35c9
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubCreateParser.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubCreateParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+
+
+using namespace Swift;
+
+PubSubCreateParser::PubSubCreateParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubCreateParser::~PubSubCreateParser() {
+}
+
+void PubSubCreateParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) {
+			getPayloadInternal()->setNode(*attributeValue);
+		}
+	}
+
+	
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubCreateParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubCreateParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubCreateParser.h b/Swiften/Parser/PayloadParsers/PubSubCreateParser.h
new file mode 100644
index 0000000..865b8ec
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubCreateParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubCreate.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubCreateParser : public GenericPayloadParser<PubSubCreate> {
+		public:
+			PubSubCreateParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubCreateParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubDefaultParser.cpp b/Swiften/Parser/PayloadParsers/PubSubDefaultParser.cpp
new file mode 100644
index 0000000..7a370cd
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubDefaultParser.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubDefaultParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+#include <Swiften/Parser/EnumParser.h>
+
+using namespace Swift;
+
+PubSubDefaultParser::PubSubDefaultParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubDefaultParser::~PubSubDefaultParser() {
+}
+
+void PubSubDefaultParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) {
+			getPayloadInternal()->setNode(*attributeValue);
+		}
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("type")) {
+			if (boost::optional<PubSubDefault::Type> value = EnumParser<PubSubDefault::Type>()(PubSubDefault::None, "none")(PubSubDefault::Collection, "collection")(PubSubDefault::Leaf, "leaf").parse(*attributeValue)) {
+				getPayloadInternal()->setType(*value);
+			}
+		}
+	}
+
+	
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubDefaultParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubDefaultParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubDefaultParser.h b/Swiften/Parser/PayloadParsers/PubSubDefaultParser.h
new file mode 100644
index 0000000..7bd8d66
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubDefaultParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubDefault.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubDefaultParser : public GenericPayloadParser<PubSubDefault> {
+		public:
+			PubSubDefaultParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubDefaultParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubErrorParser.cpp b/Swiften/Parser/PayloadParsers/PubSubErrorParser.cpp
new file mode 100644
index 0000000..9752cd2
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubErrorParser.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Parser/PayloadParsers/PubSubErrorParser.h>
+
+using namespace Swift;
+
+PubSubErrorParser::PubSubErrorParser() : level(0) {
+	typeParser
+		(PubSubError::ClosedNode, "closed-node")
+		(PubSubError::ConfigurationRequired, "configuration-required")
+		(PubSubError::InvalidJID, "invalid-jid")
+		(PubSubError::InvalidOptions, "invalid-options")
+		(PubSubError::InvalidPayload, "invalid-payload")
+		(PubSubError::InvalidSubscriptionID, "invalid-subid")
+		(PubSubError::ItemForbidden, "item-forbidden")
+		(PubSubError::ItemRequired, "item-required")
+		(PubSubError::JIDRequired, "jid-required")
+		(PubSubError::MaximumItemsExceeded, "max-items-exceeded")
+		(PubSubError::MaximumNodesExceeded, "max-nodes-exceeded")
+		(PubSubError::NodeIDRequired, "nodeid-required")
+		(PubSubError::NotInRosterGroup, "not-in-roster-group")
+		(PubSubError::NotSubscribed, "not-subscribed")
+		(PubSubError::PayloadTooBig, "payload-too-big")
+		(PubSubError::PayloadRequired, "payload-required")
+		(PubSubError::PendingSubscription, "pending-subscription")
+		(PubSubError::PresenceSubscriptionRequired, "presence-subscription-required")
+		(PubSubError::SubscriptionIDRequired, "subid-required")
+		(PubSubError::TooManySubscriptions, "too-many-subscriptions")
+		(PubSubError::Unsupported, "unsupported")
+		(PubSubError::UnsupportedAccessModel, "unsupported-access-model");
+	unsupportedTypeParser
+		(PubSubError::AccessAuthorize, "access-authorize")
+		(PubSubError::AccessOpen, "access-open")
+		(PubSubError::AccessPresence, "access-presence")
+		(PubSubError::AccessRoster, "access-roster")
+		(PubSubError::AccessWhitelist, "access-whitelist")
+		(PubSubError::AutoCreate, "auto-create")
+		(PubSubError::AutoSubscribe, "auto-subscribe")
+		(PubSubError::Collections, "collections")
+		(PubSubError::ConfigNode, "config-node")
+		(PubSubError::CreateAndConfigure, "create-and-configure")
+		(PubSubError::CreateNodes, "create-nodes")
+		(PubSubError::DeleteItems, "delete-items")
+		(PubSubError::DeleteNodes, "delete-nodes")
+		(PubSubError::FilteredNotifications, "filtered-notifications")
+		(PubSubError::GetPending, "get-pending")
+		(PubSubError::InstantNodes, "instant-nodes")
+		(PubSubError::ItemIDs, "item-ids")
+		(PubSubError::LastPublished, "last-published")
+		(PubSubError::LeasedSubscription, "leased-subscription")
+		(PubSubError::ManageSubscriptions, "manage-subscriptions")
+		(PubSubError::MemberAffiliation, "member-affiliation")
+		(PubSubError::MetaData, "meta-data")
+		(PubSubError::ModifyAffiliations, "modify-affiliations")
+		(PubSubError::MultiCollection, "multi-collection")
+		(PubSubError::MultiSubscribe, "multi-subscribe")
+		(PubSubError::OutcastAffiliation, "outcast-affiliation")
+		(PubSubError::PersistentItems, "persistent-items")
+		(PubSubError::PresenceNotifications, "presence-notifications")
+		(PubSubError::PresenceSubscribe, "presence-subscribe")
+		(PubSubError::Publish, "publish")
+		(PubSubError::PublishOptions, "publish-options")
+		(PubSubError::PublishOnlyAffiliation, "publish-only-affiliation")
+		(PubSubError::PublisherAffiliation, "publisher-affiliation")
+		(PubSubError::PurgeNodes, "purge-nodes")
+		(PubSubError::RetractItems, "retract-items")
+		(PubSubError::RetrieveAffiliations, "retrieve-affiliations")
+		(PubSubError::RetrieveDefault, "retrieve-default")
+		(PubSubError::RetrieveItems, "retrieve-items")
+		(PubSubError::RetrieveSubscriptions, "retrieve-subscriptions")
+		(PubSubError::Subscribe, "subscribe")
+		(PubSubError::SubscriptionOptions, "subscription-options")
+		(PubSubError::SubscriptionNotifications, "subscription-notifications");
+}
+
+PubSubErrorParser::~PubSubErrorParser() {
+}
+
+void PubSubErrorParser::handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) {
+	if (level == 1) {
+		if (boost::optional<PubSubError::Type> type = typeParser.parse(element)) {
+			getPayloadInternal()->setType(*type);
+			if (type == PubSubError::Unsupported) {
+				if (boost::optional<std::string> feature = attributes.getAttributeValue("feature")) {
+					if (boost::optional<PubSubError::UnsupportedFeatureType> unsupportedType = unsupportedTypeParser.parse(*feature)) {
+						getPayloadInternal()->setUnsupportedFeatureType(*unsupportedType);
+					}
+				}
+			}
+		}
+	}
+	++level;
+}
+
+void PubSubErrorParser::handleEndElement(const std::string&, const std::string&) {
+	--level;
+}
+
+void PubSubErrorParser::handleCharacterData(const std::string&) {
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubErrorParser.h b/Swiften/Parser/PayloadParsers/PubSubErrorParser.h
new file mode 100644
index 0000000..eb7dcfe
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubErrorParser.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubError.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+#include <Swiften/Parser/EnumParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubErrorParser : public GenericPayloadParser<PubSubError> {
+		public:
+			PubSubErrorParser();
+			virtual ~PubSubErrorParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			int level;
+			EnumParser<PubSubError::Type> typeParser;
+			EnumParser<PubSubError::UnsupportedFeatureType> unsupportedTypeParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubErrorParserFactory.cpp b/Swiften/Parser/PayloadParsers/PubSubErrorParserFactory.cpp
new file mode 100644
index 0000000..10dfd63
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubErrorParserFactory.cpp
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Parser/PayloadParsers/PubSubErrorParserFactory.h>
+
+using namespace Swift;
+
+PubSubErrorParserFactory::~PubSubErrorParserFactory() {
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubErrorParserFactory.h b/Swiften/Parser/PayloadParsers/PubSubErrorParserFactory.h
new file mode 100644
index 0000000..e2386da
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubErrorParserFactory.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Parser/PayloadParserFactory.h>
+#include <Swiften/Parser/PayloadParsers/PubSubErrorParser.h>
+
+namespace Swift {
+	class PubSubErrorParserFactory : public PayloadParserFactory {
+		public:
+			PubSubErrorParserFactory() {
+			}
+			~PubSubErrorParserFactory();
+
+			virtual bool canParse(const std::string&, const std::string& ns, const AttributeMap&) const {
+				return ns == "http://jabber.org/protocol/pubsub#errors";
+			}
+
+			virtual PayloadParser* createPayloadParser() {
+				return new PubSubErrorParser();
+			}
+	};
+}
+
+
diff --git a/Swiften/Parser/PayloadParsers/PubSubEventAssociateParser.cpp b/Swiften/Parser/PayloadParsers/PubSubEventAssociateParser.cpp
new file mode 100644
index 0000000..f187be8
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubEventAssociateParser.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubEventAssociateParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+
+
+using namespace Swift;
+
+PubSubEventAssociateParser::PubSubEventAssociateParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubEventAssociateParser::~PubSubEventAssociateParser() {
+}
+
+void PubSubEventAssociateParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) {
+			getPayloadInternal()->setNode(*attributeValue);
+		}
+	}
+
+	
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubEventAssociateParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubEventAssociateParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubEventAssociateParser.h b/Swiften/Parser/PayloadParsers/PubSubEventAssociateParser.h
new file mode 100644
index 0000000..000edf2
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubEventAssociateParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubEventAssociate.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubEventAssociateParser : public GenericPayloadParser<PubSubEventAssociate> {
+		public:
+			PubSubEventAssociateParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubEventAssociateParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubEventCollectionParser.cpp b/Swiften/Parser/PayloadParsers/PubSubEventCollectionParser.cpp
new file mode 100644
index 0000000..08b9c65
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubEventCollectionParser.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubEventCollectionParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+#include <Swiften/Parser/PayloadParsers/PubSubEventAssociateParser.h>
+#include <Swiften/Parser/PayloadParsers/PubSubEventDisassociateParser.h>
+
+using namespace Swift;
+
+PubSubEventCollectionParser::PubSubEventCollectionParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubEventCollectionParser::~PubSubEventCollectionParser() {
+}
+
+void PubSubEventCollectionParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) {
+			getPayloadInternal()->setNode(*attributeValue);
+		}
+	}
+
+	if (level == 1) {
+		if (element == "disassociate" && ns == "http://jabber.org/protocol/pubsub#event") {
+			currentPayloadParser = boost::make_shared<PubSubEventDisassociateParser>(parsers);
+		}
+		if (element == "associate" && ns == "http://jabber.org/protocol/pubsub#event") {
+			currentPayloadParser = boost::make_shared<PubSubEventAssociateParser>(parsers);
+		}
+	}
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubEventCollectionParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			if (element == "disassociate" && ns == "http://jabber.org/protocol/pubsub#event") {
+				getPayloadInternal()->setDisassociate(boost::dynamic_pointer_cast<PubSubEventDisassociate>(currentPayloadParser->getPayload()));
+			}
+			if (element == "associate" && ns == "http://jabber.org/protocol/pubsub#event") {
+				getPayloadInternal()->setAssociate(boost::dynamic_pointer_cast<PubSubEventAssociate>(currentPayloadParser->getPayload()));
+			}
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubEventCollectionParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubEventCollectionParser.h b/Swiften/Parser/PayloadParsers/PubSubEventCollectionParser.h
new file mode 100644
index 0000000..aad97d2
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubEventCollectionParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubEventCollection.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubEventCollectionParser : public GenericPayloadParser<PubSubEventCollection> {
+		public:
+			PubSubEventCollectionParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubEventCollectionParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubEventConfigurationParser.cpp b/Swiften/Parser/PayloadParsers/PubSubEventConfigurationParser.cpp
new file mode 100644
index 0000000..f905299
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubEventConfigurationParser.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubEventConfigurationParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+#include <Swiften/Parser/PayloadParsers/FormParser.h>
+
+using namespace Swift;
+
+PubSubEventConfigurationParser::PubSubEventConfigurationParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubEventConfigurationParser::~PubSubEventConfigurationParser() {
+}
+
+void PubSubEventConfigurationParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) {
+			getPayloadInternal()->setNode(*attributeValue);
+		}
+	}
+
+	if (level == 1) {
+		if (element == "x" && ns == "jabber:x:data") {
+			currentPayloadParser = boost::make_shared<FormParser>();
+		}
+	}
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubEventConfigurationParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			if (element == "x" && ns == "jabber:x:data") {
+				getPayloadInternal()->setData(boost::dynamic_pointer_cast<Form>(currentPayloadParser->getPayload()));
+			}
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubEventConfigurationParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubEventConfigurationParser.h b/Swiften/Parser/PayloadParsers/PubSubEventConfigurationParser.h
new file mode 100644
index 0000000..7189460
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubEventConfigurationParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubEventConfiguration.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubEventConfigurationParser : public GenericPayloadParser<PubSubEventConfiguration> {
+		public:
+			PubSubEventConfigurationParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubEventConfigurationParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubEventDeleteParser.cpp b/Swiften/Parser/PayloadParsers/PubSubEventDeleteParser.cpp
new file mode 100644
index 0000000..03c7423
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubEventDeleteParser.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubEventDeleteParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+#include <Swiften/Parser/PayloadParsers/PubSubEventRedirectParser.h>
+
+using namespace Swift;
+
+PubSubEventDeleteParser::PubSubEventDeleteParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubEventDeleteParser::~PubSubEventDeleteParser() {
+}
+
+void PubSubEventDeleteParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) {
+			getPayloadInternal()->setNode(*attributeValue);
+		}
+	}
+
+	if (level == 1) {
+		if (element == "redirect" && ns == "http://jabber.org/protocol/pubsub#event") {
+			currentPayloadParser = boost::make_shared<PubSubEventRedirectParser>(parsers);
+		}
+	}
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubEventDeleteParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			if (element == "redirect" && ns == "http://jabber.org/protocol/pubsub#event") {
+				getPayloadInternal()->setRedirects(boost::dynamic_pointer_cast<PubSubEventRedirect>(currentPayloadParser->getPayload()));
+			}
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubEventDeleteParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubEventDeleteParser.h b/Swiften/Parser/PayloadParsers/PubSubEventDeleteParser.h
new file mode 100644
index 0000000..36f8e0b
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubEventDeleteParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubEventDelete.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubEventDeleteParser : public GenericPayloadParser<PubSubEventDelete> {
+		public:
+			PubSubEventDeleteParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubEventDeleteParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubEventDisassociateParser.cpp b/Swiften/Parser/PayloadParsers/PubSubEventDisassociateParser.cpp
new file mode 100644
index 0000000..287ac35
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubEventDisassociateParser.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubEventDisassociateParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+
+
+using namespace Swift;
+
+PubSubEventDisassociateParser::PubSubEventDisassociateParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubEventDisassociateParser::~PubSubEventDisassociateParser() {
+}
+
+void PubSubEventDisassociateParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) {
+			getPayloadInternal()->setNode(*attributeValue);
+		}
+	}
+
+	
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubEventDisassociateParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubEventDisassociateParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubEventDisassociateParser.h b/Swiften/Parser/PayloadParsers/PubSubEventDisassociateParser.h
new file mode 100644
index 0000000..9015100
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubEventDisassociateParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubEventDisassociate.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubEventDisassociateParser : public GenericPayloadParser<PubSubEventDisassociate> {
+		public:
+			PubSubEventDisassociateParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubEventDisassociateParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubEventItemParser.cpp b/Swiften/Parser/PayloadParsers/PubSubEventItemParser.cpp
new file mode 100644
index 0000000..8903545
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubEventItemParser.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubEventItemParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+
+
+using namespace Swift;
+
+PubSubEventItemParser::PubSubEventItemParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubEventItemParser::~PubSubEventItemParser() {
+}
+
+void PubSubEventItemParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) {
+			getPayloadInternal()->setNode(*attributeValue);
+		}
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("publisher")) {
+			getPayloadInternal()->setPublisher(*attributeValue);
+		}
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("id")) {
+			getPayloadInternal()->setID(*attributeValue);
+		}
+	}
+
+	if (level == 1) {
+		if (PayloadParserFactory* factory = parsers->getPayloadParserFactory(element, ns, attributes)) {
+			currentPayloadParser.reset(factory->createPayloadParser());
+		}
+	}
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubEventItemParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			getPayloadInternal()->addData(currentPayloadParser->getPayload());
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubEventItemParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubEventItemParser.h b/Swiften/Parser/PayloadParsers/PubSubEventItemParser.h
new file mode 100644
index 0000000..6c16043
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubEventItemParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubEventItem.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubEventItemParser : public GenericPayloadParser<PubSubEventItem> {
+		public:
+			PubSubEventItemParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubEventItemParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubEventItemsParser.cpp b/Swiften/Parser/PayloadParsers/PubSubEventItemsParser.cpp
new file mode 100644
index 0000000..fa155e9
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubEventItemsParser.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubEventItemsParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+#include <Swiften/Parser/PayloadParsers/PubSubEventRetractParser.h>
+#include <Swiften/Parser/PayloadParsers/PubSubEventItemParser.h>
+
+using namespace Swift;
+
+PubSubEventItemsParser::PubSubEventItemsParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubEventItemsParser::~PubSubEventItemsParser() {
+}
+
+void PubSubEventItemsParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) {
+			getPayloadInternal()->setNode(*attributeValue);
+		}
+	}
+
+	if (level == 1) {
+		if (element == "item" && ns == "http://jabber.org/protocol/pubsub#event") {
+			currentPayloadParser = boost::make_shared<PubSubEventItemParser>(parsers);
+		}
+		if (element == "retract" && ns == "http://jabber.org/protocol/pubsub#event") {
+			currentPayloadParser = boost::make_shared<PubSubEventRetractParser>(parsers);
+		}
+	}
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubEventItemsParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			if (element == "item" && ns == "http://jabber.org/protocol/pubsub#event") {
+				getPayloadInternal()->addItem(boost::dynamic_pointer_cast<PubSubEventItem>(currentPayloadParser->getPayload()));
+			}
+			if (element == "retract" && ns == "http://jabber.org/protocol/pubsub#event") {
+				getPayloadInternal()->addRetract(boost::dynamic_pointer_cast<PubSubEventRetract>(currentPayloadParser->getPayload()));
+			}
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubEventItemsParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubEventItemsParser.h b/Swiften/Parser/PayloadParsers/PubSubEventItemsParser.h
new file mode 100644
index 0000000..60ecb25
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubEventItemsParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubEventItems.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubEventItemsParser : public GenericPayloadParser<PubSubEventItems> {
+		public:
+			PubSubEventItemsParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubEventItemsParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubEventParser.cpp b/Swiften/Parser/PayloadParsers/PubSubEventParser.cpp
new file mode 100644
index 0000000..c4406a9
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubEventParser.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubEventParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+#include <Swiften/Parser/PayloadParsers/PubSubEventItemsParser.h>
+#include <Swiften/Parser/PayloadParsers/PubSubEventDeleteParser.h>
+#include <Swiften/Parser/PayloadParsers/PubSubEventSubscriptionParser.h>
+#include <Swiften/Parser/PayloadParsers/PubSubEventPurgeParser.h>
+#include <Swiften/Parser/PayloadParsers/PubSubEventCollectionParser.h>
+#include <Swiften/Parser/PayloadParsers/PubSubEventConfigurationParser.h>
+
+using namespace Swift;
+
+PubSubEventParser::PubSubEventParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubEventParser::~PubSubEventParser() {
+}
+
+void PubSubEventParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	
+
+	if (level == 1) {
+		if (element == "items" && ns == "http://jabber.org/protocol/pubsub#event") {
+			currentPayloadParser = boost::make_shared<PubSubEventItemsParser>(parsers);
+		}
+		if (element == "collection" && ns == "http://jabber.org/protocol/pubsub#event") {
+			currentPayloadParser = boost::make_shared<PubSubEventCollectionParser>(parsers);
+		}
+		if (element == "purge" && ns == "http://jabber.org/protocol/pubsub#event") {
+			currentPayloadParser = boost::make_shared<PubSubEventPurgeParser>(parsers);
+		}
+		if (element == "configuration" && ns == "http://jabber.org/protocol/pubsub#event") {
+			currentPayloadParser = boost::make_shared<PubSubEventConfigurationParser>(parsers);
+		}
+		if (element == "delete" && ns == "http://jabber.org/protocol/pubsub#event") {
+			currentPayloadParser = boost::make_shared<PubSubEventDeleteParser>(parsers);
+		}
+		if (element == "subscription" && ns == "http://jabber.org/protocol/pubsub#event") {
+			currentPayloadParser = boost::make_shared<PubSubEventSubscriptionParser>(parsers);
+		}
+	}
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubEventParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			if (currentPayloadParser) {
+				getPayloadInternal()->setPayload(boost::dynamic_pointer_cast<PubSubEventPayload>(currentPayloadParser->getPayload()));
+			}
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubEventParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubEventParser.h b/Swiften/Parser/PayloadParsers/PubSubEventParser.h
new file mode 100644
index 0000000..1042e75
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubEventParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubEvent.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubEventParser : public GenericPayloadParser<PubSubEvent> {
+		public:
+			PubSubEventParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubEventParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubEventPurgeParser.cpp b/Swiften/Parser/PayloadParsers/PubSubEventPurgeParser.cpp
new file mode 100644
index 0000000..14d1e96
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubEventPurgeParser.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubEventPurgeParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+
+
+using namespace Swift;
+
+PubSubEventPurgeParser::PubSubEventPurgeParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubEventPurgeParser::~PubSubEventPurgeParser() {
+}
+
+void PubSubEventPurgeParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) {
+			getPayloadInternal()->setNode(*attributeValue);
+		}
+	}
+
+	
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubEventPurgeParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubEventPurgeParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubEventPurgeParser.h b/Swiften/Parser/PayloadParsers/PubSubEventPurgeParser.h
new file mode 100644
index 0000000..740bff3
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubEventPurgeParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubEventPurge.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubEventPurgeParser : public GenericPayloadParser<PubSubEventPurge> {
+		public:
+			PubSubEventPurgeParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubEventPurgeParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubEventRedirectParser.cpp b/Swiften/Parser/PayloadParsers/PubSubEventRedirectParser.cpp
new file mode 100644
index 0000000..f053117
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubEventRedirectParser.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubEventRedirectParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+
+
+using namespace Swift;
+
+PubSubEventRedirectParser::PubSubEventRedirectParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubEventRedirectParser::~PubSubEventRedirectParser() {
+}
+
+void PubSubEventRedirectParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("uri")) {
+			getPayloadInternal()->setURI(*attributeValue);
+		}
+	}
+
+	
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubEventRedirectParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubEventRedirectParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubEventRedirectParser.h b/Swiften/Parser/PayloadParsers/PubSubEventRedirectParser.h
new file mode 100644
index 0000000..33880ed
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubEventRedirectParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubEventRedirect.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubEventRedirectParser : public GenericPayloadParser<PubSubEventRedirect> {
+		public:
+			PubSubEventRedirectParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubEventRedirectParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubEventRetractParser.cpp b/Swiften/Parser/PayloadParsers/PubSubEventRetractParser.cpp
new file mode 100644
index 0000000..da3dea3
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubEventRetractParser.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubEventRetractParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+
+
+using namespace Swift;
+
+PubSubEventRetractParser::PubSubEventRetractParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubEventRetractParser::~PubSubEventRetractParser() {
+}
+
+void PubSubEventRetractParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("id")) {
+			getPayloadInternal()->setID(*attributeValue);
+		}
+	}
+
+	
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubEventRetractParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubEventRetractParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubEventRetractParser.h b/Swiften/Parser/PayloadParsers/PubSubEventRetractParser.h
new file mode 100644
index 0000000..115bb7a
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubEventRetractParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubEventRetract.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubEventRetractParser : public GenericPayloadParser<PubSubEventRetract> {
+		public:
+			PubSubEventRetractParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubEventRetractParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubEventSubscriptionParser.cpp b/Swiften/Parser/PayloadParsers/PubSubEventSubscriptionParser.cpp
new file mode 100644
index 0000000..3367202
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubEventSubscriptionParser.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubEventSubscriptionParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+#include <Swiften/Base/DateTime.h>
+#include <Swiften/Parser/EnumParser.h>
+
+using namespace Swift;
+
+PubSubEventSubscriptionParser::PubSubEventSubscriptionParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubEventSubscriptionParser::~PubSubEventSubscriptionParser() {
+}
+
+void PubSubEventSubscriptionParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) {
+			getPayloadInternal()->setNode(*attributeValue);
+		}
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("jid")) {
+			if (boost::optional<JID> jid = JID::parse(*attributeValue)) {
+				getPayloadInternal()->setJID(*jid);
+			}
+		}
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("subscription")) {
+			if (boost::optional<PubSubEventSubscription::SubscriptionType> value = EnumParser<PubSubEventSubscription::SubscriptionType>()(PubSubEventSubscription::None, "none")(PubSubEventSubscription::Pending, "pending")(PubSubEventSubscription::Subscribed, "subscribed")(PubSubEventSubscription::Unconfigured, "unconfigured").parse(*attributeValue)) {
+				getPayloadInternal()->setSubscription(*value);
+			}
+		}
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("subid")) {
+			getPayloadInternal()->setSubscriptionID(*attributeValue);
+		}
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("expiry")) {
+				getPayloadInternal()->setExpiry(stringToDateTime(*attributeValue));
+		}
+	}
+
+	
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubEventSubscriptionParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubEventSubscriptionParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubEventSubscriptionParser.h b/Swiften/Parser/PayloadParsers/PubSubEventSubscriptionParser.h
new file mode 100644
index 0000000..1469920
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubEventSubscriptionParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubEventSubscription.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubEventSubscriptionParser : public GenericPayloadParser<PubSubEventSubscription> {
+		public:
+			PubSubEventSubscriptionParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubEventSubscriptionParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubItemParser.cpp b/Swiften/Parser/PayloadParsers/PubSubItemParser.cpp
new file mode 100644
index 0000000..2e7d01a
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubItemParser.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubItemParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+
+
+using namespace Swift;
+
+PubSubItemParser::PubSubItemParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubItemParser::~PubSubItemParser() {
+}
+
+void PubSubItemParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("id")) {
+			getPayloadInternal()->setID(*attributeValue);
+		}
+	}
+
+	if (level == 1) {
+		if (PayloadParserFactory* factory = parsers->getPayloadParserFactory(element, ns, attributes)) {
+			currentPayloadParser.reset(factory->createPayloadParser());
+		}
+	}
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubItemParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			getPayloadInternal()->addData(currentPayloadParser->getPayload());
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubItemParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubItemParser.h b/Swiften/Parser/PayloadParsers/PubSubItemParser.h
new file mode 100644
index 0000000..4f02211
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubItemParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubItem.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubItemParser : public GenericPayloadParser<PubSubItem> {
+		public:
+			PubSubItemParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubItemParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubItemsParser.cpp b/Swiften/Parser/PayloadParsers/PubSubItemsParser.cpp
new file mode 100644
index 0000000..615f05d
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubItemsParser.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubItemsParser.h>
+
+#include <boost/optional.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+#include <Swiften/Parser/PayloadParsers/PubSubItemParser.h>
+
+using namespace Swift;
+
+PubSubItemsParser::PubSubItemsParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubItemsParser::~PubSubItemsParser() {
+}
+
+void PubSubItemsParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) {
+			getPayloadInternal()->setNode(*attributeValue);
+		}
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("max_items")) {
+			try {
+				getPayloadInternal()->setMaximumItems(boost::lexical_cast<unsigned int>(*attributeValue));
+			}
+			catch (boost::bad_lexical_cast&) {
+			}
+		}
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("subid")) {
+			getPayloadInternal()->setSubscriptionID(*attributeValue);
+		}
+	}
+
+	if (level == 1) {
+		if (element == "item" && ns == "http://jabber.org/protocol/pubsub") {
+			currentPayloadParser = boost::make_shared<PubSubItemParser>(parsers);
+		}
+	}
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubItemsParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			if (element == "item" && ns == "http://jabber.org/protocol/pubsub") {
+				getPayloadInternal()->addItem(boost::dynamic_pointer_cast<PubSubItem>(currentPayloadParser->getPayload()));
+			}
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubItemsParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubItemsParser.h b/Swiften/Parser/PayloadParsers/PubSubItemsParser.h
new file mode 100644
index 0000000..895863f
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubItemsParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubItems.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubItemsParser : public GenericPayloadParser<PubSubItems> {
+		public:
+			PubSubItemsParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubItemsParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubOptionsParser.cpp b/Swiften/Parser/PayloadParsers/PubSubOptionsParser.cpp
new file mode 100644
index 0000000..3bf4998
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubOptionsParser.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubOptionsParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+#include <Swiften/Parser/PayloadParsers/FormParser.h>
+
+using namespace Swift;
+
+PubSubOptionsParser::PubSubOptionsParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubOptionsParser::~PubSubOptionsParser() {
+}
+
+void PubSubOptionsParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) {
+			getPayloadInternal()->setNode(*attributeValue);
+		}
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("jid")) {
+			if (boost::optional<JID> jid = JID::parse(*attributeValue)) {
+				getPayloadInternal()->setJID(*jid);
+			}
+		}
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("subid")) {
+			getPayloadInternal()->setSubscriptionID(*attributeValue);
+		}
+	}
+
+	if (level == 1) {
+		if (element == "x" && ns == "jabber:x:data") {
+			currentPayloadParser = boost::make_shared<FormParser>();
+		}
+	}
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubOptionsParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			if (element == "x" && ns == "jabber:x:data") {
+				getPayloadInternal()->setData(boost::dynamic_pointer_cast<Form>(currentPayloadParser->getPayload()));
+			}
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubOptionsParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubOptionsParser.h b/Swiften/Parser/PayloadParsers/PubSubOptionsParser.h
new file mode 100644
index 0000000..3c8754b
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubOptionsParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubOptions.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubOptionsParser : public GenericPayloadParser<PubSubOptions> {
+		public:
+			PubSubOptionsParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubOptionsParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationParser.cpp b/Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationParser.cpp
new file mode 100644
index 0000000..a648862
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationParser.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+#include <Swiften/Parser/EnumParser.h>
+
+using namespace Swift;
+
+PubSubOwnerAffiliationParser::PubSubOwnerAffiliationParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubOwnerAffiliationParser::~PubSubOwnerAffiliationParser() {
+}
+
+void PubSubOwnerAffiliationParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("jid")) {
+			if (boost::optional<JID> jid = JID::parse(*attributeValue)) {
+				getPayloadInternal()->setJID(*jid);
+			}
+		}
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("affiliation")) {
+			if (boost::optional<PubSubOwnerAffiliation::Type> value = EnumParser<PubSubOwnerAffiliation::Type>()(PubSubOwnerAffiliation::None, "none")(PubSubOwnerAffiliation::Member, "member")(PubSubOwnerAffiliation::Outcast, "outcast")(PubSubOwnerAffiliation::Owner, "owner")(PubSubOwnerAffiliation::Publisher, "publisher")(PubSubOwnerAffiliation::PublishOnly, "publish-only").parse(*attributeValue)) {
+				getPayloadInternal()->setType(*value);
+			}
+		}
+	}
+
+	
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubOwnerAffiliationParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubOwnerAffiliationParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationParser.h b/Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationParser.h
new file mode 100644
index 0000000..ae54b5f
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubOwnerAffiliation.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubOwnerAffiliationParser : public GenericPayloadParser<PubSubOwnerAffiliation> {
+		public:
+			PubSubOwnerAffiliationParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubOwnerAffiliationParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationsParser.cpp b/Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationsParser.cpp
new file mode 100644
index 0000000..b824279
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationsParser.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationsParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+#include <Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationParser.h>
+
+using namespace Swift;
+
+PubSubOwnerAffiliationsParser::PubSubOwnerAffiliationsParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubOwnerAffiliationsParser::~PubSubOwnerAffiliationsParser() {
+}
+
+void PubSubOwnerAffiliationsParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) {
+			getPayloadInternal()->setNode(*attributeValue);
+		}
+	}
+
+	if (level == 1) {
+		if (element == "affiliation" && ns == "http://jabber.org/protocol/pubsub#owner") {
+			currentPayloadParser = boost::make_shared<PubSubOwnerAffiliationParser>(parsers);
+		}
+	}
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubOwnerAffiliationsParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			if (element == "affiliation" && ns == "http://jabber.org/protocol/pubsub#owner") {
+				getPayloadInternal()->addAffiliation(boost::dynamic_pointer_cast<PubSubOwnerAffiliation>(currentPayloadParser->getPayload()));
+			}
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubOwnerAffiliationsParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationsParser.h b/Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationsParser.h
new file mode 100644
index 0000000..755d58c
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationsParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubOwnerAffiliations.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubOwnerAffiliationsParser : public GenericPayloadParser<PubSubOwnerAffiliations> {
+		public:
+			PubSubOwnerAffiliationsParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubOwnerAffiliationsParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerConfigureParser.cpp b/Swiften/Parser/PayloadParsers/PubSubOwnerConfigureParser.cpp
new file mode 100644
index 0000000..43d262f
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubOwnerConfigureParser.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubOwnerConfigureParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+#include <Swiften/Parser/PayloadParsers/FormParser.h>
+
+using namespace Swift;
+
+PubSubOwnerConfigureParser::PubSubOwnerConfigureParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubOwnerConfigureParser::~PubSubOwnerConfigureParser() {
+}
+
+void PubSubOwnerConfigureParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) {
+			getPayloadInternal()->setNode(*attributeValue);
+		}
+	}
+
+	if (level == 1) {
+		if (element == "x" && ns == "jabber:x:data") {
+			currentPayloadParser = boost::make_shared<FormParser>();
+		}
+	}
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubOwnerConfigureParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			if (element == "x" && ns == "jabber:x:data") {
+				getPayloadInternal()->setData(boost::dynamic_pointer_cast<Form>(currentPayloadParser->getPayload()));
+			}
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubOwnerConfigureParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerConfigureParser.h b/Swiften/Parser/PayloadParsers/PubSubOwnerConfigureParser.h
new file mode 100644
index 0000000..f9a8553
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubOwnerConfigureParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubOwnerConfigure.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubOwnerConfigureParser : public GenericPayloadParser<PubSubOwnerConfigure> {
+		public:
+			PubSubOwnerConfigureParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubOwnerConfigureParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerDefaultParser.cpp b/Swiften/Parser/PayloadParsers/PubSubOwnerDefaultParser.cpp
new file mode 100644
index 0000000..4c284bf
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubOwnerDefaultParser.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubOwnerDefaultParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+#include <Swiften/Parser/PayloadParsers/FormParser.h>
+
+using namespace Swift;
+
+PubSubOwnerDefaultParser::PubSubOwnerDefaultParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubOwnerDefaultParser::~PubSubOwnerDefaultParser() {
+}
+
+void PubSubOwnerDefaultParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	
+
+	if (level == 1) {
+		if (element == "x" && ns == "jabber:x:data") {
+			currentPayloadParser = boost::make_shared<FormParser>();
+		}
+	}
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubOwnerDefaultParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			if (element == "x" && ns == "jabber:x:data") {
+				getPayloadInternal()->setData(boost::dynamic_pointer_cast<Form>(currentPayloadParser->getPayload()));
+			}
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubOwnerDefaultParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerDefaultParser.h b/Swiften/Parser/PayloadParsers/PubSubOwnerDefaultParser.h
new file mode 100644
index 0000000..5207bc5
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubOwnerDefaultParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubOwnerDefault.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubOwnerDefaultParser : public GenericPayloadParser<PubSubOwnerDefault> {
+		public:
+			PubSubOwnerDefaultParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubOwnerDefaultParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerDeleteParser.cpp b/Swiften/Parser/PayloadParsers/PubSubOwnerDeleteParser.cpp
new file mode 100644
index 0000000..a2b7a9d
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubOwnerDeleteParser.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubOwnerDeleteParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+#include <Swiften/Parser/PayloadParsers/PubSubOwnerRedirectParser.h>
+
+using namespace Swift;
+
+PubSubOwnerDeleteParser::PubSubOwnerDeleteParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubOwnerDeleteParser::~PubSubOwnerDeleteParser() {
+}
+
+void PubSubOwnerDeleteParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) {
+			getPayloadInternal()->setNode(*attributeValue);
+		}
+	}
+
+	if (level == 1) {
+		if (element == "redirect" && ns == "http://jabber.org/protocol/pubsub#owner") {
+			currentPayloadParser = boost::make_shared<PubSubOwnerRedirectParser>(parsers);
+		}
+	}
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubOwnerDeleteParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			if (element == "redirect" && ns == "http://jabber.org/protocol/pubsub#owner") {
+				getPayloadInternal()->setRedirect(boost::dynamic_pointer_cast<PubSubOwnerRedirect>(currentPayloadParser->getPayload()));
+			}
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubOwnerDeleteParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerDeleteParser.h b/Swiften/Parser/PayloadParsers/PubSubOwnerDeleteParser.h
new file mode 100644
index 0000000..c171ab8
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubOwnerDeleteParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubOwnerDelete.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubOwnerDeleteParser : public GenericPayloadParser<PubSubOwnerDelete> {
+		public:
+			PubSubOwnerDeleteParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubOwnerDeleteParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerPubSubParser.cpp b/Swiften/Parser/PayloadParsers/PubSubOwnerPubSubParser.cpp
new file mode 100644
index 0000000..5262997
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubOwnerPubSubParser.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubOwnerPubSubParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+#include <Swiften/Parser/PayloadParsers/PubSubOwnerDefaultParser.h>
+#include <Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionsParser.h>
+#include <Swiften/Parser/PayloadParsers/PubSubOwnerDeleteParser.h>
+#include <Swiften/Parser/PayloadParsers/PubSubOwnerPurgeParser.h>
+#include <Swiften/Parser/PayloadParsers/PubSubOwnerConfigureParser.h>
+#include <Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationsParser.h>
+
+using namespace Swift;
+
+PubSubOwnerPubSubParser::PubSubOwnerPubSubParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubOwnerPubSubParser::~PubSubOwnerPubSubParser() {
+}
+
+void PubSubOwnerPubSubParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	
+
+	if (level == 1) {
+		if (element == "configure" && ns == "http://jabber.org/protocol/pubsub#owner") {
+			currentPayloadParser = boost::make_shared<PubSubOwnerConfigureParser>(parsers);
+		}
+		if (element == "subscriptions" && ns == "http://jabber.org/protocol/pubsub#owner") {
+			currentPayloadParser = boost::make_shared<PubSubOwnerSubscriptionsParser>(parsers);
+		}
+		if (element == "default" && ns == "http://jabber.org/protocol/pubsub#owner") {
+			currentPayloadParser = boost::make_shared<PubSubOwnerDefaultParser>(parsers);
+		}
+		if (element == "purge" && ns == "http://jabber.org/protocol/pubsub#owner") {
+			currentPayloadParser = boost::make_shared<PubSubOwnerPurgeParser>(parsers);
+		}
+		if (element == "affiliations" && ns == "http://jabber.org/protocol/pubsub#owner") {
+			currentPayloadParser = boost::make_shared<PubSubOwnerAffiliationsParser>(parsers);
+		}
+		if (element == "delete" && ns == "http://jabber.org/protocol/pubsub#owner") {
+			currentPayloadParser = boost::make_shared<PubSubOwnerDeleteParser>(parsers);
+		}
+	}
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubOwnerPubSubParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			if (currentPayloadParser) {
+				getPayloadInternal()->setPayload(boost::dynamic_pointer_cast<PubSubOwnerPayload>(currentPayloadParser->getPayload()));
+			}
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubOwnerPubSubParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerPubSubParser.h b/Swiften/Parser/PayloadParsers/PubSubOwnerPubSubParser.h
new file mode 100644
index 0000000..25fee8a
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubOwnerPubSubParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubOwnerPubSub.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubOwnerPubSubParser : public GenericPayloadParser<PubSubOwnerPubSub> {
+		public:
+			PubSubOwnerPubSubParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubOwnerPubSubParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerPurgeParser.cpp b/Swiften/Parser/PayloadParsers/PubSubOwnerPurgeParser.cpp
new file mode 100644
index 0000000..ebea0a7
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubOwnerPurgeParser.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubOwnerPurgeParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+
+
+using namespace Swift;
+
+PubSubOwnerPurgeParser::PubSubOwnerPurgeParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubOwnerPurgeParser::~PubSubOwnerPurgeParser() {
+}
+
+void PubSubOwnerPurgeParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) {
+			getPayloadInternal()->setNode(*attributeValue);
+		}
+	}
+
+	
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubOwnerPurgeParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubOwnerPurgeParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerPurgeParser.h b/Swiften/Parser/PayloadParsers/PubSubOwnerPurgeParser.h
new file mode 100644
index 0000000..0b85d3d
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubOwnerPurgeParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubOwnerPurge.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubOwnerPurgeParser : public GenericPayloadParser<PubSubOwnerPurge> {
+		public:
+			PubSubOwnerPurgeParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubOwnerPurgeParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerRedirectParser.cpp b/Swiften/Parser/PayloadParsers/PubSubOwnerRedirectParser.cpp
new file mode 100644
index 0000000..bc54e86
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubOwnerRedirectParser.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubOwnerRedirectParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+
+
+using namespace Swift;
+
+PubSubOwnerRedirectParser::PubSubOwnerRedirectParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubOwnerRedirectParser::~PubSubOwnerRedirectParser() {
+}
+
+void PubSubOwnerRedirectParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("uri")) {
+			getPayloadInternal()->setURI(*attributeValue);
+		}
+	}
+
+	
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubOwnerRedirectParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubOwnerRedirectParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerRedirectParser.h b/Swiften/Parser/PayloadParsers/PubSubOwnerRedirectParser.h
new file mode 100644
index 0000000..9a97d74
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubOwnerRedirectParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubOwnerRedirect.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubOwnerRedirectParser : public GenericPayloadParser<PubSubOwnerRedirect> {
+		public:
+			PubSubOwnerRedirectParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubOwnerRedirectParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionParser.cpp b/Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionParser.cpp
new file mode 100644
index 0000000..7c91526
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionParser.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+#include <Swiften/Parser/EnumParser.h>
+
+using namespace Swift;
+
+PubSubOwnerSubscriptionParser::PubSubOwnerSubscriptionParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubOwnerSubscriptionParser::~PubSubOwnerSubscriptionParser() {
+}
+
+void PubSubOwnerSubscriptionParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("jid")) {
+			if (boost::optional<JID> jid = JID::parse(*attributeValue)) {
+				getPayloadInternal()->setJID(*jid);
+			}
+		}
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("subscription")) {
+			if (boost::optional<PubSubOwnerSubscription::SubscriptionType> value = EnumParser<PubSubOwnerSubscription::SubscriptionType>()(PubSubOwnerSubscription::None, "none")(PubSubOwnerSubscription::Pending, "pending")(PubSubOwnerSubscription::Subscribed, "subscribed")(PubSubOwnerSubscription::Unconfigured, "unconfigured").parse(*attributeValue)) {
+				getPayloadInternal()->setSubscription(*value);
+			}
+		}
+	}
+
+	
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubOwnerSubscriptionParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubOwnerSubscriptionParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionParser.h b/Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionParser.h
new file mode 100644
index 0000000..8ef8d5b
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubOwnerSubscription.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubOwnerSubscriptionParser : public GenericPayloadParser<PubSubOwnerSubscription> {
+		public:
+			PubSubOwnerSubscriptionParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubOwnerSubscriptionParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionsParser.cpp b/Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionsParser.cpp
new file mode 100644
index 0000000..ebe90d8
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionsParser.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionsParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+#include <Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionParser.h>
+
+using namespace Swift;
+
+PubSubOwnerSubscriptionsParser::PubSubOwnerSubscriptionsParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubOwnerSubscriptionsParser::~PubSubOwnerSubscriptionsParser() {
+}
+
+void PubSubOwnerSubscriptionsParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) {
+			getPayloadInternal()->setNode(*attributeValue);
+		}
+	}
+
+	if (level == 1) {
+		if (element == "subscription" && ns == "http://jabber.org/protocol/pubsub#owner") {
+			currentPayloadParser = boost::make_shared<PubSubOwnerSubscriptionParser>(parsers);
+		}
+	}
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubOwnerSubscriptionsParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			if (element == "subscription" && ns == "http://jabber.org/protocol/pubsub#owner") {
+				getPayloadInternal()->addSubscription(boost::dynamic_pointer_cast<PubSubOwnerSubscription>(currentPayloadParser->getPayload()));
+			}
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubOwnerSubscriptionsParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionsParser.h b/Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionsParser.h
new file mode 100644
index 0000000..a5459a9
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionsParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubOwnerSubscriptions.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubOwnerSubscriptionsParser : public GenericPayloadParser<PubSubOwnerSubscriptions> {
+		public:
+			PubSubOwnerSubscriptionsParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubOwnerSubscriptionsParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubParser.cpp b/Swiften/Parser/PayloadParsers/PubSubParser.cpp
new file mode 100644
index 0000000..5b1462b
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubParser.cpp
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+#include <Swiften/Parser/PayloadParsers/PubSubSubscriptionParser.h>
+#include <Swiften/Parser/PayloadParsers/PubSubConfigureParser.h>
+#include <Swiften/Parser/PayloadParsers/PubSubDefaultParser.h>
+#include <Swiften/Parser/PayloadParsers/PubSubCreateParser.h>
+#include <Swiften/Parser/PayloadParsers/PubSubAffiliationsParser.h>
+#include <Swiften/Parser/PayloadParsers/PubSubOptionsParser.h>
+#include <Swiften/Parser/PayloadParsers/PubSubPublishParser.h>
+#include <Swiften/Parser/PayloadParsers/PubSubOptionsParser.h>
+#include <Swiften/Parser/PayloadParsers/PubSubSubscribeParser.h>
+#include <Swiften/Parser/PayloadParsers/PubSubUnsubscribeParser.h>
+#include <Swiften/Parser/PayloadParsers/PubSubItemsParser.h>
+#include <Swiften/Parser/PayloadParsers/PubSubRetractParser.h>
+#include <Swiften/Parser/PayloadParsers/PubSubSubscriptionsParser.h>
+
+using namespace Swift;
+
+PubSubParser::PubSubParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubParser::~PubSubParser() {
+}
+
+void PubSubParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 1) {
+		if (element == "items" && ns == "http://jabber.org/protocol/pubsub") {
+			currentPayloadParser = boost::make_shared<PubSubItemsParser>(parsers);
+		}
+		if (element == "create" && ns == "http://jabber.org/protocol/pubsub") {
+			currentPayloadParser = boost::make_shared<PubSubCreateParser>(parsers);
+		}
+		if (element == "publish" && ns == "http://jabber.org/protocol/pubsub") {
+			currentPayloadParser = boost::make_shared<PubSubPublishParser>(parsers);
+		}
+		if (element == "affiliations" && ns == "http://jabber.org/protocol/pubsub") {
+			currentPayloadParser = boost::make_shared<PubSubAffiliationsParser>(parsers);
+		}
+		if (element == "retract" && ns == "http://jabber.org/protocol/pubsub") {
+			currentPayloadParser = boost::make_shared<PubSubRetractParser>(parsers);
+		}
+		if (element == "options" && ns == "http://jabber.org/protocol/pubsub") {
+			currentPayloadParser = boost::make_shared<PubSubOptionsParser>(parsers);
+		}
+		if (element == "configure" && ns == "http://jabber.org/protocol/pubsub") {
+			currentPayloadParser = boost::make_shared<PubSubConfigureParser>(parsers);
+		}
+		if (element == "default" && ns == "http://jabber.org/protocol/pubsub") {
+			currentPayloadParser = boost::make_shared<PubSubDefaultParser>(parsers);
+		}
+		if (element == "subscriptions" && ns == "http://jabber.org/protocol/pubsub") {
+			currentPayloadParser = boost::make_shared<PubSubSubscriptionsParser>(parsers);
+		}
+		if (element == "subscribe" && ns == "http://jabber.org/protocol/pubsub") {
+			currentPayloadParser = boost::make_shared<PubSubSubscribeParser>(parsers);
+		}
+		if (element == "unsubscribe" && ns == "http://jabber.org/protocol/pubsub") {
+			currentPayloadParser = boost::make_shared<PubSubUnsubscribeParser>(parsers);
+		}
+		if (element == "subscription" && ns == "http://jabber.org/protocol/pubsub") {
+			currentPayloadParser = boost::make_shared<PubSubSubscriptionParser>(parsers);
+		}
+	}
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			if (currentPayloadParser) {
+				if (element == "options" && ns == "http://jabber.org/protocol/pubsub") {
+					optionsPayload = boost::dynamic_pointer_cast<PubSubOptions>(currentPayloadParser->getPayload());
+				}
+				else if (element == "configure" && ns == "http://jabber.org/protocol/pubsub") {
+					configurePayload = boost::dynamic_pointer_cast<PubSubConfigure>(currentPayloadParser->getPayload());
+				}
+				else {
+					getPayloadInternal()->setPayload(boost::dynamic_pointer_cast<PubSubPayload>(currentPayloadParser->getPayload()));
+				}
+			}
+			currentPayloadParser.reset();
+		}
+
+		if (level == 0) {
+			if (boost::shared_ptr<PubSubCreate> create = boost::dynamic_pointer_cast<PubSubCreate>(getPayloadInternal()->getPayload())) {
+				if (configurePayload) {
+					create->setConfigure(configurePayload);
+				}
+			}
+			if (boost::shared_ptr<PubSubSubscribe> subscribe = boost::dynamic_pointer_cast<PubSubSubscribe>(getPayloadInternal()->getPayload())) {
+				if (optionsPayload) {
+					subscribe->setOptions(optionsPayload);
+				}
+			}
+		}
+	}
+}
+
+void PubSubParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubParser.h b/Swiften/Parser/PayloadParsers/PubSubParser.h
new file mode 100644
index 0000000..0618361
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubParser.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSub.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+	class PubSubOptions;
+	class PubSubConfigure;
+
+	class SWIFTEN_API PubSubParser : public GenericPayloadParser<PubSub> {
+		public:
+			PubSubParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+			boost::shared_ptr<PubSubConfigure> configurePayload;
+			boost::shared_ptr<PubSubOptions> optionsPayload;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubPublishParser.cpp b/Swiften/Parser/PayloadParsers/PubSubPublishParser.cpp
new file mode 100644
index 0000000..ca358c3
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubPublishParser.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubPublishParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+#include <Swiften/Parser/PayloadParsers/PubSubItemParser.h>
+
+using namespace Swift;
+
+PubSubPublishParser::PubSubPublishParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubPublishParser::~PubSubPublishParser() {
+}
+
+void PubSubPublishParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) {
+			getPayloadInternal()->setNode(*attributeValue);
+		}
+	}
+
+	if (level == 1) {
+		if (element == "item" && ns == "http://jabber.org/protocol/pubsub") {
+			currentPayloadParser = boost::make_shared<PubSubItemParser>(parsers);
+		}
+	}
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubPublishParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			if (element == "item" && ns == "http://jabber.org/protocol/pubsub") {
+				getPayloadInternal()->addItem(boost::dynamic_pointer_cast<PubSubItem>(currentPayloadParser->getPayload()));
+			}
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubPublishParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubPublishParser.h b/Swiften/Parser/PayloadParsers/PubSubPublishParser.h
new file mode 100644
index 0000000..3d64e9d
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubPublishParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubPublish.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubPublishParser : public GenericPayloadParser<PubSubPublish> {
+		public:
+			PubSubPublishParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubPublishParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubRetractParser.cpp b/Swiften/Parser/PayloadParsers/PubSubRetractParser.cpp
new file mode 100644
index 0000000..f4a42d0
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubRetractParser.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubRetractParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+#include <Swiften/Parser/PayloadParsers/PubSubItemParser.h>
+
+using namespace Swift;
+
+PubSubRetractParser::PubSubRetractParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubRetractParser::~PubSubRetractParser() {
+}
+
+void PubSubRetractParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) {
+			getPayloadInternal()->setNode(*attributeValue);
+		}
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("notify")) {
+			getPayloadInternal()->setNotify(*attributeValue == "true" ? true : false);
+		}
+	}
+
+	if (level == 1) {
+		if (element == "item" && ns == "http://jabber.org/protocol/pubsub") {
+			currentPayloadParser = boost::make_shared<PubSubItemParser>(parsers);
+		}
+	}
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubRetractParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			if (element == "item" && ns == "http://jabber.org/protocol/pubsub") {
+				getPayloadInternal()->addItem(boost::dynamic_pointer_cast<PubSubItem>(currentPayloadParser->getPayload()));
+			}
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubRetractParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubRetractParser.h b/Swiften/Parser/PayloadParsers/PubSubRetractParser.h
new file mode 100644
index 0000000..2b5e633
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubRetractParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubRetract.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubRetractParser : public GenericPayloadParser<PubSubRetract> {
+		public:
+			PubSubRetractParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubRetractParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubSubscribeOptionsParser.cpp b/Swiften/Parser/PayloadParsers/PubSubSubscribeOptionsParser.cpp
new file mode 100644
index 0000000..caed681
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubSubscribeOptionsParser.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubSubscribeOptionsParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+
+
+using namespace Swift;
+
+PubSubSubscribeOptionsParser::PubSubSubscribeOptionsParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubSubscribeOptionsParser::~PubSubSubscribeOptionsParser() {
+}
+
+void PubSubSubscribeOptionsParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	
+
+	
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubSubscribeOptionsParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			if (element == "required") {
+				getPayloadInternal()->setRequired(true);
+			}
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubSubscribeOptionsParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubSubscribeOptionsParser.h b/Swiften/Parser/PayloadParsers/PubSubSubscribeOptionsParser.h
new file mode 100644
index 0000000..c9ac1ca
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubSubscribeOptionsParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubSubscribeOptions.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubSubscribeOptionsParser : public GenericPayloadParser<PubSubSubscribeOptions> {
+		public:
+			PubSubSubscribeOptionsParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubSubscribeOptionsParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubSubscribeParser.cpp b/Swiften/Parser/PayloadParsers/PubSubSubscribeParser.cpp
new file mode 100644
index 0000000..093c2c4
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubSubscribeParser.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubSubscribeParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+
+
+using namespace Swift;
+
+PubSubSubscribeParser::PubSubSubscribeParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubSubscribeParser::~PubSubSubscribeParser() {
+}
+
+void PubSubSubscribeParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) {
+			getPayloadInternal()->setNode(*attributeValue);
+		}
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("jid")) {
+			if (boost::optional<JID> jid = JID::parse(*attributeValue)) {
+				getPayloadInternal()->setJID(*jid);
+			}
+		}
+	}
+
+	
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubSubscribeParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubSubscribeParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubSubscribeParser.h b/Swiften/Parser/PayloadParsers/PubSubSubscribeParser.h
new file mode 100644
index 0000000..f0ad09d
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubSubscribeParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubSubscribe.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubSubscribeParser : public GenericPayloadParser<PubSubSubscribe> {
+		public:
+			PubSubSubscribeParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubSubscribeParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubSubscriptionParser.cpp b/Swiften/Parser/PayloadParsers/PubSubSubscriptionParser.cpp
new file mode 100644
index 0000000..be06ec8
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubSubscriptionParser.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubSubscriptionParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+#include <Swiften/Parser/EnumParser.h>
+#include <Swiften/Parser/PayloadParsers/PubSubSubscribeOptionsParser.h>
+
+using namespace Swift;
+
+PubSubSubscriptionParser::PubSubSubscriptionParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubSubscriptionParser::~PubSubSubscriptionParser() {
+}
+
+void PubSubSubscriptionParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) {
+			getPayloadInternal()->setNode(*attributeValue);
+		}
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("subid")) {
+			getPayloadInternal()->setSubscriptionID(*attributeValue);
+		}
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("jid")) {
+			if (boost::optional<JID> jid = JID::parse(*attributeValue)) {
+				getPayloadInternal()->setJID(*jid);
+			}
+		}
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("subscription")) {
+			if (boost::optional<PubSubSubscription::SubscriptionType> value = EnumParser<PubSubSubscription::SubscriptionType>()(PubSubSubscription::None, "none")(PubSubSubscription::Pending, "pending")(PubSubSubscription::Subscribed, "subscribed")(PubSubSubscription::Unconfigured, "unconfigured").parse(*attributeValue)) {
+				getPayloadInternal()->setSubscription(*value);
+			}
+		}
+	}
+
+	if (level == 1) {
+		if (element == "subscribe-options" && ns == "http://jabber.org/protocol/pubsub") {
+			currentPayloadParser = boost::make_shared<PubSubSubscribeOptionsParser>(parsers);
+		}
+	}
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubSubscriptionParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			if (element == "subscribe-options" && ns == "http://jabber.org/protocol/pubsub") {
+				getPayloadInternal()->setOptions(boost::dynamic_pointer_cast<PubSubSubscribeOptions>(currentPayloadParser->getPayload()));
+			}
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubSubscriptionParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubSubscriptionParser.h b/Swiften/Parser/PayloadParsers/PubSubSubscriptionParser.h
new file mode 100644
index 0000000..49290c2
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubSubscriptionParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubSubscription.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubSubscriptionParser : public GenericPayloadParser<PubSubSubscription> {
+		public:
+			PubSubSubscriptionParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubSubscriptionParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubSubscriptionsParser.cpp b/Swiften/Parser/PayloadParsers/PubSubSubscriptionsParser.cpp
new file mode 100644
index 0000000..3ac3ca0
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubSubscriptionsParser.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubSubscriptionsParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+#include <Swiften/Parser/PayloadParsers/PubSubSubscriptionParser.h>
+
+using namespace Swift;
+
+PubSubSubscriptionsParser::PubSubSubscriptionsParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubSubscriptionsParser::~PubSubSubscriptionsParser() {
+}
+
+void PubSubSubscriptionsParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) {
+			getPayloadInternal()->setNode(*attributeValue);
+		}
+	}
+
+	if (level == 1) {
+		if (element == "subscription" && ns == "http://jabber.org/protocol/pubsub") {
+			currentPayloadParser = boost::make_shared<PubSubSubscriptionParser>(parsers);
+		}
+	}
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubSubscriptionsParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			if (element == "subscription" && ns == "http://jabber.org/protocol/pubsub") {
+				getPayloadInternal()->addSubscription(boost::dynamic_pointer_cast<PubSubSubscription>(currentPayloadParser->getPayload()));
+			}
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubSubscriptionsParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubSubscriptionsParser.h b/Swiften/Parser/PayloadParsers/PubSubSubscriptionsParser.h
new file mode 100644
index 0000000..b08db93
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubSubscriptionsParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubSubscriptions.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubSubscriptionsParser : public GenericPayloadParser<PubSubSubscriptions> {
+		public:
+			PubSubSubscriptionsParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubSubscriptionsParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubUnsubscribeParser.cpp b/Swiften/Parser/PayloadParsers/PubSubUnsubscribeParser.cpp
new file mode 100644
index 0000000..53b4fae
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubUnsubscribeParser.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Parser/PayloadParsers/PubSubUnsubscribeParser.h>
+
+#include <boost/optional.hpp>
+
+
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+
+
+using namespace Swift;
+
+PubSubUnsubscribeParser::PubSubUnsubscribeParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) {
+}
+
+PubSubUnsubscribeParser::~PubSubUnsubscribeParser() {
+}
+
+void PubSubUnsubscribeParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
+	if (level == 0) {
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) {
+			getPayloadInternal()->setNode(*attributeValue);
+		}
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("jid")) {
+			if (boost::optional<JID> jid = JID::parse(*attributeValue)) {
+				getPayloadInternal()->setJID(*jid);
+			}
+		}
+		if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("subid")) {
+			getPayloadInternal()->setSubscriptionID(*attributeValue);
+		}
+	}
+
+	
+
+	if (level >= 1 && currentPayloadParser) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level;
+}
+
+void PubSubUnsubscribeParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level;
+	if (currentPayloadParser) {
+		if (level >= 1) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level == 1) {
+			
+			currentPayloadParser.reset();
+		}
+	}
+}
+
+void PubSubUnsubscribeParser::handleCharacterData(const std::string& data) {
+	if (level > 1 && currentPayloadParser) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+}
diff --git a/Swiften/Parser/PayloadParsers/PubSubUnsubscribeParser.h b/Swiften/Parser/PayloadParsers/PubSubUnsubscribeParser.h
new file mode 100644
index 0000000..a9e5ed0
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/PubSubUnsubscribeParser.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/PubSubUnsubscribe.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+	class PayloadParser;
+
+	class SWIFTEN_API PubSubUnsubscribeParser : public GenericPayloadParser<PubSubUnsubscribe> {
+		public:
+			PubSubUnsubscribeParser(PayloadParserFactoryCollection* parsers);
+			virtual ~PubSubUnsubscribeParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			PayloadParserFactoryCollection* parsers;
+			int level;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h b/Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h
index 213cd06..b328670 100644
--- a/Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h
+++ b/Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h
@@ -1,13 +1,11 @@
 /*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2013 Remko Tronçon
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
 
 #pragma once
 
-#include <cppunit/extensions/HelperMacros.h>
-
 #include <Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h>
 #include <Swiften/Parser/XMLParser.h>
 #include <Swiften/Parser/XMLParserClient.h>
@@ -32,9 +30,9 @@ namespace Swift {
 
 			virtual void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
 				if (level == 0) {
-					CPPUNIT_ASSERT(!payloadParser.get());
+					assert(!payloadParser.get());
 					PayloadParserFactory* payloadParserFactory = factories.getPayloadParserFactory(element, ns, attributes);
-					CPPUNIT_ASSERT(payloadParserFactory);
+					assert(payloadParserFactory);
 					payloadParser.reset(payloadParserFactory->createPayloadParser());
 				}
 				payloadParser->handleStartElement(element, ns, attributes);
diff --git a/Swiften/Parser/PayloadParsers/UserLocationParser.cpp b/Swiften/Parser/PayloadParsers/UserLocationParser.cpp
new file mode 100644
index 0000000..d3aac69
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/UserLocationParser.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Parser/PayloadParsers/UserLocationParser.h>
+
+#include <boost/lexical_cast.hpp>
+
+#include <Swiften/Base/DateTime.h>
+
+using namespace Swift;
+
+UserLocationParser::UserLocationParser() : level(0) {
+}
+
+UserLocationParser::~UserLocationParser() {
+}
+
+void UserLocationParser::handleStartElement(const std::string&, const std::string&, const AttributeMap&) {
+	if (level == 1) {
+		currentText = "";
+	}
+	++level;
+}
+
+void UserLocationParser::handleEndElement(const std::string& element, const std::string&) {
+	--level;
+	if (level == 1) {
+		try {
+			if (element == "accuracy") {
+				getPayloadInternal()->setAccuracy(boost::lexical_cast<float>(currentText));
+			}
+			else if (element == "alt") {
+				getPayloadInternal()->setAltitude(boost::lexical_cast<float>(currentText));
+			}
+			else if (element == "area") {
+				getPayloadInternal()->setArea(currentText);
+			}
+			else if (element == "bearing") {
+				getPayloadInternal()->setBearing(boost::lexical_cast<float>(currentText));
+			}
+			else if (element == "building") {
+				getPayloadInternal()->setBuilding(currentText);
+			}
+			else if (element == "country") {
+				getPayloadInternal()->setCountry(currentText);
+			}
+			else if (element == "countrycode") {
+				getPayloadInternal()->setCountryCode(currentText);
+			}
+			else if (element == "datum") {
+				getPayloadInternal()->setDatum(currentText);
+			}
+			else if (element == "description") {
+				getPayloadInternal()->setDescription(currentText);
+			}
+			else if (element == "error") {
+				getPayloadInternal()->setError(boost::lexical_cast<float>(currentText));
+			}
+			else if (element == "floor") {
+				getPayloadInternal()->setFloor(currentText);
+			}
+			else if (element == "lat") {
+				getPayloadInternal()->setLatitude(boost::lexical_cast<float>(currentText));
+			}
+			else if (element == "locality") {
+				getPayloadInternal()->setLocality(currentText);
+			}
+			else if (element == "lon") {
+				getPayloadInternal()->setLongitude(boost::lexical_cast<float>(currentText));
+			}
+			else if (element == "postalcode") {
+				getPayloadInternal()->setPostalCode(currentText);
+			}
+			else if (element == "region") {
+				getPayloadInternal()->setRegion(currentText);
+			}
+			else if (element == "room") {
+				getPayloadInternal()->setRoom(currentText);
+			}
+			else if (element == "speed") {
+				getPayloadInternal()->setSpeed(boost::lexical_cast<float>(currentText));
+			}
+			else if (element == "street") {
+				getPayloadInternal()->setStreet(currentText);
+			}
+			else if (element == "text") {
+				getPayloadInternal()->setText(currentText);
+			}
+			else if (element == "timestamp") {
+				getPayloadInternal()->setTimestamp(stringToDateTime(currentText));
+			}
+			else if (element == "uri") {
+				getPayloadInternal()->setURI(currentText);
+			}
+		}
+		catch (const boost::bad_lexical_cast&) {
+		}
+	}
+}
+
+void UserLocationParser::handleCharacterData(const std::string& data) {
+	currentText += data;
+}
diff --git a/Swiften/Parser/PayloadParsers/UserLocationParser.h b/Swiften/Parser/PayloadParsers/UserLocationParser.h
new file mode 100644
index 0000000..eb6e668
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/UserLocationParser.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+#include <string>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+#include <Swiften/Elements/UserLocation.h>
+
+namespace Swift {
+	class SWIFTEN_API UserLocationParser : public GenericPayloadParser<UserLocation> {
+		public:
+			UserLocationParser();
+			virtual ~UserLocationParser();
+
+			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE;
+			virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE;
+			virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE;
+
+		private:
+			int level;
+			std::string currentText;
+	};
+}
diff --git a/Swiften/Parser/SConscript b/Swiften/Parser/SConscript
index 068cbd7..0a6972e 100644
--- a/Swiften/Parser/SConscript
+++ b/Swiften/Parser/SConscript
@@ -73,7 +73,9 @@ sources = [
 		"PayloadParsers/S5BProxyRequestParser.cpp",
 		"PayloadParsers/DeliveryReceiptParser.cpp",
 		"PayloadParsers/DeliveryReceiptRequestParser.cpp",
+		"PayloadParsers/UserLocationParser.cpp",
 		"PayloadParsers/WhiteboardParser.cpp",
+		"PayloadParsers/PubSubErrorParserFactory.cpp",
 		"PlatformXMLParserFactory.cpp",
 		"PresenceParser.cpp",
 		"SerializingParser.cpp",
diff --git a/Swiften/PubSub/PubSubManager.cpp b/Swiften/PubSub/PubSubManager.cpp
new file mode 100644
index 0000000..8899b1e
--- /dev/null
+++ b/Swiften/PubSub/PubSubManager.cpp
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/PubSub/PubSubManager.h>
+
+using namespace Swift;
+
+PubSubManager::~PubSubManager() {
+}
diff --git a/Swiften/PubSub/PubSubManager.h b/Swiften/PubSub/PubSubManager.h
new file mode 100644
index 0000000..2f3c84d
--- /dev/null
+++ b/Swiften/PubSub/PubSubManager.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Base/boost_bsignals.h>
+#include <Swiften/Queries/PubSubRequest.h>
+#include <Swiften/PubSub/PubSubUtil.h>
+#include <Swiften/Elements/PubSub.h>
+#include <Swiften/Elements/PubSubOwnerPubSub.h>
+#include <Swiften/Elements/PubSubCreate.h>
+#include <Swiften/Elements/PubSubSubscribe.h>
+#include <Swiften/Elements/PubSubAffiliations.h>
+#include <Swiften/Elements/PubSubDefault.h>
+#include <Swiften/Elements/PubSubItems.h>
+#include <Swiften/Elements/PubSubPublish.h>
+#include <Swiften/Elements/PubSubRetract.h>
+#include <Swiften/Elements/PubSubSubscription.h>
+#include <Swiften/Elements/PubSubSubscriptions.h>
+#include <Swiften/Elements/PubSubUnsubscribe.h>
+#include <Swiften/Elements/PubSubOwnerAffiliations.h>
+#include <Swiften/Elements/PubSubOwnerConfigure.h>
+#include <Swiften/Elements/PubSubOwnerDefault.h>
+#include <Swiften/Elements/PubSubOwnerDelete.h>
+#include <Swiften/Elements/PubSubOwnerPurge.h>
+#include <Swiften/Elements/PubSubOwnerSubscriptions.h>
+#include <Swiften/Elements/IQ.h>
+#include <Swiften/Elements/PubSubEventPayload.h>
+
+#define SWIFTEN_PUBSUBMANAGER_DECLARE_CREATE_REQUEST(payload, container, response) \
+	virtual boost::shared_ptr< PubSubRequest<payload> >  \
+		createRequest(IQ::Type, const JID&, boost::shared_ptr<payload>) = 0;
+
+namespace Swift {
+	class JID;
+
+	class SWIFTEN_API PubSubManager {
+		public:
+			virtual ~PubSubManager();
+			
+			SWIFTEN_PUBSUB_FOREACH_PUBSUB_PAYLOAD_TYPE(
+					SWIFTEN_PUBSUBMANAGER_DECLARE_CREATE_REQUEST)
+
+			boost::signal<void (const JID&, const boost::shared_ptr<PubSubEventPayload>)> onEvent;
+	};
+}
diff --git a/Swiften/PubSub/PubSubManagerImpl.cpp b/Swiften/PubSub/PubSubManagerImpl.cpp
new file mode 100644
index 0000000..38b02aa
--- /dev/null
+++ b/Swiften/PubSub/PubSubManagerImpl.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/PubSub/PubSubManagerImpl.h>
+
+#include <boost/bind.hpp>
+
+#include <Swiften/Client/StanzaChannel.h>
+#include <Swiften/Elements/Message.h>
+#include <Swiften/Elements/PubSubEvent.h>
+
+using namespace Swift;
+
+PubSubManagerImpl::PubSubManagerImpl(StanzaChannel* stanzaChannel, IQRouter* router) : 
+		stanzaChannel(stanzaChannel),
+		router(router) {
+	stanzaChannel->onMessageReceived.connect(boost::bind(&PubSubManagerImpl::handleMessageRecevied, this, _1));
+}
+
+PubSubManagerImpl::~PubSubManagerImpl() {
+	stanzaChannel->onMessageReceived.disconnect(boost::bind(&PubSubManagerImpl::handleMessageRecevied, this, _1));
+}
+
+void PubSubManagerImpl::handleMessageRecevied(boost::shared_ptr<Message> message) {
+	if (boost::shared_ptr<PubSubEvent> event = message->getPayload<PubSubEvent>()) {
+		onEvent(message->getFrom(), event->getPayload());
+	}
+}
diff --git a/Swiften/PubSub/PubSubManagerImpl.h b/Swiften/PubSub/PubSubManagerImpl.h
new file mode 100644
index 0000000..65884c0
--- /dev/null
+++ b/Swiften/PubSub/PubSubManagerImpl.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/PubSub/PubSubManager.h>
+
+#define SWIFTEN_PUBSUBMANAGERIMPL_DECLARE_CREATE_REQUEST(payload, container, response) \
+	virtual boost::shared_ptr< PubSubRequest<payload> >  \
+			createRequest(IQ::Type type, const JID& receiver, boost::shared_ptr<payload> p) SWIFTEN_OVERRIDE { \
+		return boost::make_shared< PubSubRequest<payload> >(type, receiver, p, router); \
+	}
+
+namespace Swift {
+	class JID;
+	class StanzaChannel;
+	class Message;
+
+	class SWIFTEN_API PubSubManagerImpl : public PubSubManager {
+		public:
+			PubSubManagerImpl(StanzaChannel* stanzaChannel, IQRouter* router);
+			virtual ~PubSubManagerImpl();
+
+			SWIFTEN_PUBSUB_FOREACH_PUBSUB_PAYLOAD_TYPE(
+					SWIFTEN_PUBSUBMANAGERIMPL_DECLARE_CREATE_REQUEST)
+
+		private:
+			void handleMessageRecevied(boost::shared_ptr<Message>);
+
+		private:
+			StanzaChannel* stanzaChannel;
+			IQRouter* router;
+	};
+}
diff --git a/Swiften/PubSub/PubSubUtil.h b/Swiften/PubSub/PubSubUtil.h
new file mode 100644
index 0000000..3342659
--- /dev/null
+++ b/Swiften/PubSub/PubSubUtil.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#define SWIFTEN_PUBSUB_FOREACH_PUBSUB_PAYLOAD_TYPE(action) \
+	action(PubSubCreate, PubSub, PubSubCreate) \
+	action(PubSubAffiliations, PubSub, PubSubAffiliations) \
+	action(PubSubDefault, PubSub, PubSubDefault) \
+	action(PubSubItems, PubSub, PubSubItems) \
+	action(PubSubOptions, PubSub, PubSubOptions) \
+	action(PubSubPublish, PubSub, PubSubPublish) \
+	action(PubSubRetract, PubSub, PubSubRetract) \
+	action(PubSubSubscription, PubSub, PubSubSubscription) \
+	action(PubSubSubscriptions, PubSub, PubSubSubscriptions) \
+	action(PubSubSubscribe, PubSub, PubSubSubscription) \
+	action(PubSubUnsubscribe, PubSub, PubSubUnsubscribe) \
+	action(PubSubOwnerAffiliations, PubSubOwnerPubSub, PubSubOwnerAffiliations) \
+	action(PubSubOwnerConfigure, PubSubOwnerPubSub, PubSubOwnerConfigure) \
+	action(PubSubOwnerDefault, PubSubOwnerPubSub, PubSubOwnerDefault) \
+	action(PubSubOwnerDelete, PubSubOwnerPubSub, PubSubOwnerDelete) \
+	action(PubSubOwnerPurge, PubSubOwnerPubSub, PubSubOwnerPurge) \
+	action(PubSubOwnerSubscriptions, PubSubOwnerPubSub, PubSubOwnerSubscriptions)
+
diff --git a/Swiften/QA/ScriptedTests/MultipleClients.lua b/Swiften/QA/ScriptedTests/MultipleClients.lua
index ce51481..ddc7c44 100644
--- a/Swiften/QA/ScriptedTests/MultipleClients.lua
+++ b/Swiften/QA/ScriptedTests/MultipleClients.lua
@@ -1,5 +1,5 @@
 --
--- Copyright (c) 2010 Remko Tronçon
+-- Copyright (c) 2010-2013 Remko Tronçon
 -- Licensed under the GNU General Public License v3.
 -- See Documentation/Licenses/GPLv3.txt for more information.
 --
@@ -16,17 +16,17 @@ for i = 1, num_clients do
 	client = sluift.new_client(jid, os.getenv("SWIFT_CLIENTTEST_PASS"))
 	client:set_options({compress = false})
 	client:async_connect()
-	table.insert(clients, client)
+	clients[#clients+1] = client
 end
 
 print("Waiting for clients to be connected")
-for i, client in ipairs(clients) do
+for _, client in ipairs(clients) do
 	client:wait_connected()
 	client:send_presence("Hello")
 end
 
 print("Disconnecting clients")
-for i, client in ipairs(clients) do
+for _, client in ipairs(clients) do
 	client:disconnect()
 end
 
diff --git a/Swiften/QA/ScriptedTests/PubSub.lua b/Swiften/QA/ScriptedTests/PubSub.lua
new file mode 100644
index 0000000..a9c0fe8
--- /dev/null
+++ b/Swiften/QA/ScriptedTests/PubSub.lua
@@ -0,0 +1,288 @@
+ --[[
+	Copyright (c) 2013 Remko Tronçon
+	Licensed under the GNU General Public License.
+	See the COPYING file for more information.
+--]]
+
+require 'sluift'
+
+sluift.debug = os.getenv("SLUIFT_DEBUG")
+
+local publisher
+local publisher_jid = os.getenv("SLUIFT_JID")
+local pubsub_jid = os.getenv("SLUIFT_PUBSUB_SERVICE") or sluift.jid.to_bare(publisher_jid)
+local pubsub
+local node_id = os.getenv("SLUIFT_PUBSUB_NODE") or "http://swift.im/Swiften/QA/PubSub"
+local node
+
+local subscriber
+local subscriber_jid = os.getenv("SLUIFT_JID2")
+local subscriber_pubsub
+local subscriber_node
+
+local publish_item = {id = 'item_id', data = {{ _type = 'software_version', name = 'MyTest', os = 'Lua' }} }
+local publish_item2 = {id = 'item_id2', data = {{ _type = 'software_version', name = 'MyTest2', os = 'Lua' }} }
+
+--------------------------------------------------------------------------------
+-- Helper methods
+--------------------------------------------------------------------------------
+
+function purge_pubsub_events(client)
+	client:for_each_pubsub_event({timeout = 2000}, function() end)
+end
+
+--------------------------------------------------------------------------------
+-- 5. Entity use cases
+--------------------------------------------------------------------------------
+function test_entity_use_cases() 
+	node:delete()
+
+	-- 5.2 List nodes
+	assert(node:create())
+	local nodes = assert(pubsub:list_nodes()).items
+	local found_item = false
+	for _, node in ipairs(nodes) do
+		if node.node == node_id then found_item = true end
+	end
+	assert(found_item)
+	assert(node:delete())
+
+
+	-- 5.5 Discover items of node
+	assert(node:create())
+	assert(node:publish {items = {publish_item}})
+	local items = assert(node:list_items()).items
+	assert(#items == 1)
+	assert(items[1].name == 'item_id')
+	assert(node:delete())
+
+	-- 5.6 Subscriptions
+	assert(node:create())
+	assert(subscriber_node:subscribe({ jid = subscriber_jid }))
+	local service_subscriptions = assert(pubsub:get_subscriptions())
+	-- FIXME: Doesn't seem to return anything on M-Link. Test this later if this is supposed to work.
+	--print(service_subscriptions)
+	local node_subscriptions = assert(node:get_subscriptions())
+	--print(node_subscriptions)
+	assert(node:delete())
+
+	-- 5.7 Retrieve affiliations
+	--print(pubsub:get_affiliations()) -- Freezes Isode
+	--print(node:get_affiliations()) -- Freezes isode
+end
+
+--------------------------------------------------------------------------------
+-- 6. Subscriber use cases
+--------------------------------------------------------------------------------
+
+function test_subscriber_use_cases()
+	node:delete()
+
+	-- 6.1 Subscribe to a node
+	assert(node:create())
+	local subscription = assert(subscriber_node:subscribe({ jid = subscriber_jid }))
+	-- TODO: Test subscription id etc. Doesn't work with M-link atm
+	-- TODO: Test pending subscription
+	-- TODO: Test configuration required
+	assert(node:delete())
+
+	-- 6.2 Unsubscribe from a node
+	assert(node:create())
+	assert(subscriber_node:subscribe({ jid = subscriber_jid }))
+	assert(subscriber_node:unsubscribe({ jid = subscriber_jid }))
+	assert(node:delete())
+
+	-- 6.3 Configure subscription options
+	-- TODO: Not supported by M-Link? Finish it later
+	--assert(node:create())	
+	--assert(subscriber_node:subscribe({ jid = subscriber_jid }))
+	--local options = assert(subscriber_node:get_subscription_options({ jid = subscriber_jid }))
+	--print(options)
+	--assert(node:delete())
+
+	-- 6.4 Request default subscription configuration options
+	-- TODO: Not supported by M-Link? Finish it later
+	--local options = assert(subscriber_pubsub:get_default_subscription_options())
+	--print(options)
+	--local options = assert(subscriber_node:get_default_subscription_options())
+	--print(options)
+	
+	-- 6.5 Retrieve items of a node
+	assert(node:create())
+	assert(node:publish {item = publish_item})
+	local items = assert(subscriber_node:get_items())
+	assert(#items == 1)
+	assert(items[1].id == 'item_id')
+	assert(items[1].data[1].name == 'MyTest')
+	assert(node:delete())
+end
+
+--------------------------------------------------------------------------------
+-- 7. Publisher use cases
+--------------------------------------------------------------------------------
+
+function test_publisher_use_cases()
+	node:delete()
+
+	-- 7.1 Publish item to a node
+	assert(node:create())
+	assert(subscriber_node:subscribe({ jid = subscriber_jid }))
+	purge_pubsub_events(subscriber)
+	assert(node:publish {items = {publish_item}})
+	local event = assert(subscriber:get_next_event { type = 'pubsub' })
+	assert(event.from == publisher_jid)
+	assert(event._type == 'pubsub_event_items')
+	assert(event.items[1].id == publish_item.id)
+	assert(event.items[1].data[1].os == publish_item.data[1].os)
+	assert(event.item.os == publish_item.data[1].os)
+	assert(node:delete())
+
+	-- 7.2 Delete item from a node
+	assert(node:create())
+	assert(subscriber_node:subscribe({ jid = subscriber_jid }))
+	assert(node:publish {items = {publish_item}})
+	assert(node:retract { item = 'item_id', notify = true })
+	assert(node:delete())
+
+	-- 7.2.2.1 Delete and notify
+	assert(node:create())
+	assert(subscriber_node:subscribe({ jid = subscriber_jid }))
+	assert(node:publish {items = {publish_item}})
+	purge_pubsub_events(subscriber)
+	assert(node:retract { item = 'item_id', notify = true })
+	local event = assert(subscriber:get_next_event { type = 'pubsub' })
+	assert(event._type == 'pubsub_event_items')
+	assert(event.retracts[1].id == 'item_id')
+	assert(node:delete())
+
+	-- Publish an unknown element type
+	atom = [[
+		<entry xmlns='http://www.w3.org/2005/Atom'>
+			<title>Down the Rabbit Hole</title>
+			<summary>
+				Alice was beginning to get very tired of sitting by her sister on the
+				bank and of having nothing to do: once or twice she had peeped into the
+				book her sister was reading, but it had no pictures or conversations in
+				it, "and what is the use of a book," thought Alice, "without pictures
+				or conversations?'
+			</summary>
+			<link rel='alternate' type='text/html' 
+				href='http://www.gutenberg.org/files/11/11-h/11-h.htm#link2HCH0001'/>
+			<id>tag:gutenberg.org,2008:entry-1234</id>
+			<published>2008-06-25T18:30:02Z</published>
+			<updated>2008-06-25T18:30:02Z</updated>
+		</entry>
+	]]
+	assert(node:create())
+	assert(subscriber_node:subscribe({ jid = subscriber_jid }))
+	purge_pubsub_events(subscriber)
+	assert(node:publish { item = atom })
+	local event_item = assert(subscriber:get_next_event { type = 'pubsub' }).item
+	assert(event_item._type == 'dom')
+	assert(event_item.ns == 'http://www.w3.org/2005/Atom')
+	assert(event_item.tag == 'entry')
+	assert(node:delete())
+end
+
+--------------------------------------------------------------------------------
+-- 8 Owner Use Cases
+--------------------------------------------------------------------------------
+
+function test_owner_use_cases()
+	node:delete()
+
+	-- 8.1 Create a node
+	--   Create node with default config
+	assert(node:create())
+	configuration = assert(node:get_configuration())['data']
+	assert(node:delete())
+
+	--   Create node with custom config
+	print("Creating with configuration")
+	assert(node:create { configuration = { ['pubsub#access_model'] = 'whitelist' } })
+	configuration = assert(node:get_configuration())['data']
+	assert(configuration['pubsub#access_model']['value'] == 'whitelist')
+	assert(node:delete())
+
+	-- 8.2 Configure node
+	--   Set configuration
+	assert(node:create())
+	assert(node:set_configuration {configuration = {['pubsub#access_model'] = 'whitelist'}})
+	configuration = assert(node:get_configuration())['data']
+	assert(configuration['pubsub#access_model']['value'] == 'whitelist')
+	assert(node:delete())
+
+	-- Untested: 8.2.5.3 Success With Notifications
+	
+	-- 8.3 Request Default Node Configuration Options
+	configuration = assert(pubsub:get_default_configuration())['data']
+	assert(configuration['pubsub#access_model'] ~= nil)
+
+	-- 8.4 Delete node
+	--   Without redirection (see above)
+	--   With redirection
+	assert(node:create())
+	assert(subscriber_node:subscribe({ jid = subscriber_jid }))
+	purge_pubsub_events(subscriber)
+	assert(node:delete {redirect = 'foo@bar.com'})
+	-- FIXME: M-Link doesn't send out an event. Test this later.
+	--local event = assert(subscriber:get_next_event { type = 'pubsub' })
+	--print(event)
+	--assert(event._type == 'pubsub_event_items')
+	--assert(event.retracts[1].id == 'item_id')
+	
+	-- 8.5 Purge node items
+	assert(node:create())
+	assert(subscriber_node:subscribe({ jid = subscriber_jid }))
+	-- Publishing multiple items doesn't seem to work in M-Link
+	--assert(node:publish {items = { publish_item, publish_item2 }})
+	assert(node:publish {items = {publish_item} })
+	assert(node:publish {items = {publish_item2} })
+	purge_pubsub_events(subscriber)
+	if node:purge() then
+		-- Hasn't worked yet. Add more to this test later (including notifications)
+	else 
+		print("Warning: Purge not supported. Skipping test")
+	end
+	assert(node:delete())
+	
+	-- 8.6 Manage subscription requests
+	-- TODO	
+
+	-- 8.7 Process pending subscription requests
+	-- TODO
+	
+	-- ...
+end
+
+function run_tests() 
+	connect_options = {}
+
+	-- Set up publisher & subscriber
+	publisher = sluift.new_client(publisher_jid, os.getenv("SLUIFT_PASS"))
+	assert(publisher:connect(connect_options))
+	subscriber = sluift.new_client(subscriber_jid, os.getenv("SLUIFT_PASS2"))
+	assert(subscriber:connect(connect_options))
+
+	pubsub = publisher:pubsub(pubsub_jid)
+	node = pubsub:node(node_id)
+
+	subscriber_pubsub = subscriber:pubsub(pubsub_jid)
+	subscriber_node = subscriber_pubsub:node(node_id)
+
+	-- The tests
+	test_entity_use_cases()
+	test_subscriber_use_cases()
+	test_publisher_use_cases()
+	test_owner_use_cases()
+end
+
+success, err = pcall(run_tests)
+
+if subscriber then subscriber:disconnect() end
+if publisher then publisher:disconnect() end
+
+if not success then
+	print(err)
+	os.exit(-1)
+end
diff --git a/Swiften/QA/ScriptedTests/SendMessage.lua b/Swiften/QA/ScriptedTests/SendMessage.lua
index 8c54d00..9623ef4 100644
--- a/Swiften/QA/ScriptedTests/SendMessage.lua
+++ b/Swiften/QA/ScriptedTests/SendMessage.lua
@@ -1,5 +1,5 @@
 --
--- Copyright (c) 2010 Remko Tronçon
+-- Copyright (c) 2010-2013 Remko Tronçon
 -- Licensed under the GNU General Public License v3.
 -- See Documentation/Licenses/GPLv3.txt for more information.
 --
@@ -23,22 +23,22 @@ client2:send_presence("I'm here")
 
 print "Checking version of client 2 from client 1"
 client2:set_version({name = "Sluift Test", version = "1.0"})
-client2_version = client1:get_version(client2_jid)
+client2_version = client1:get_software_version {to=client2_jid}
 assert(client2_version["name"] == "Sluift Test")
 assert(client2_version["version"] == "1.0")
 
 print "Sending message from client 1 to client 2"
 client1:send_message(client2_jid, "Hello")
-received_message = client2:for_event(function(event) 
-		if event["type"] == "message" and event["from"] == client1_jid then
-			return event["body"]
-		end
-	end, 10000)
+received_message = client2:for_each_message({timeout = 1000}, function(message) 
+	if message["from"] == client1_jid then
+		return message["body"]
+	end
+end)
 assert(received_message == "Hello")
 
 print "Retrieving the roster"
 roster = client1:get_roster()
-tprint(roster)
+sluift.tprint(roster)
 
 client1:disconnect()
 client2:disconnect()
diff --git a/Swiften/Queries/PubSubRequest.h b/Swiften/Queries/PubSubRequest.h
new file mode 100644
index 0000000..aeee3bd
--- /dev/null
+++ b/Swiften/Queries/PubSubRequest.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2013 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/Queries/Request.h>
+#include <Swiften/Elements/ContainerPayload.h>
+#include <Swiften/PubSub/PubSubUtil.h>
+#include <Swiften/Elements/PubSub.h>
+#include <Swiften/Elements/PubSubOwnerPubSub.h>
+#include <Swiften/Elements/PubSubCreate.h>
+#include <Swiften/Elements/PubSubSubscribe.h>
+#include <Swiften/Elements/PubSubAffiliations.h>
+#include <Swiften/Elements/PubSubDefault.h>
+#include <Swiften/Elements/PubSubItems.h>
+#include <Swiften/Elements/PubSubPublish.h>
+#include <Swiften/Elements/PubSubRetract.h>
+#include <Swiften/Elements/PubSubSubscription.h>
+#include <Swiften/Elements/PubSubSubscriptions.h>
+#include <Swiften/Elements/PubSubUnsubscribe.h>
+#include <Swiften/Elements/PubSubOwnerAffiliations.h>
+#include <Swiften/Elements/PubSubOwnerConfigure.h>
+#include <Swiften/Elements/PubSubOwnerDefault.h>
+#include <Swiften/Elements/PubSubOwnerDelete.h>
+#include <Swiften/Elements/PubSubOwnerPurge.h>
+#include <Swiften/Elements/PubSubOwnerSubscriptions.h>
+
+namespace Swift {
+	namespace Detail {
+		template<typename T> 
+		struct PubSubPayloadTraits;
+
+#define SWIFTEN_PUBSUB_DECLARE_PAYLOAD_TRAITS(PAYLOAD, CONTAINER, RESPONSE) \
+		template<> struct PubSubPayloadTraits< PAYLOAD > { \
+			typedef CONTAINER ContainerType; \
+			typedef RESPONSE ResponseType; \
+		};
+
+		SWIFTEN_PUBSUB_FOREACH_PUBSUB_PAYLOAD_TYPE(
+				SWIFTEN_PUBSUB_DECLARE_PAYLOAD_TRAITS)
+	}
+
+	template<typename T>
+	class PubSubRequest : public Request {
+			typedef typename Detail::PubSubPayloadTraits<T>::ContainerType ContainerType;
+			typedef typename Detail::PubSubPayloadTraits<T>::ResponseType ResponseType;
+
+		public:
+			PubSubRequest(
+					IQ::Type type, 
+					const JID& receiver, 
+					boost::shared_ptr<T> payload, 
+					IQRouter* router) :
+						Request(type, receiver, router) {
+				boost::shared_ptr<ContainerType> wrapper = boost::make_shared<ContainerType>();
+				wrapper->setPayload(payload);
+				setPayload(wrapper);
+			}
+
+			PubSubRequest(
+					IQ::Type type,
+					const JID& sender,
+					const JID& receiver,
+					boost::shared_ptr<T> payload, 
+					IQRouter* router) :
+						Request(type, sender, receiver, router) {
+				boost::shared_ptr<ContainerType> wrapper = boost::make_shared<ContainerType>();
+				wrapper->setPayload(payload);
+				setPayload(wrapper);
+			}
+
+			virtual void handleResponse(
+					boost::shared_ptr<Payload> payload, ErrorPayload::ref error) {
+				boost::shared_ptr<ResponseType> result;
+				if (boost::shared_ptr<ContainerType> container = boost::dynamic_pointer_cast<ContainerType>(payload)) {
+					result = boost::dynamic_pointer_cast<ResponseType>(container->getPayload());
+				}
+				onResponse(result, error);
+			}
+
+		public:
+			boost::signal<void (boost::shared_ptr<ResponseType>, ErrorPayload::ref)> onResponse;
+	};
+}
diff --git a/Swiften/SConscript b/Swiften/SConscript
index 3edb463..0e7bb51 100644
--- a/Swiften/SConscript
+++ b/Swiften/SConscript
@@ -125,6 +125,9 @@ if env["SCONS_STAGE"] == "build" :
 			"Elements/Element.cpp",
 			"Elements/IQ.cpp",
 			"Elements/Payload.cpp",
+			"Elements/PubSubPayload.cpp",
+			"Elements/PubSubOwnerPayload.cpp",
+			"Elements/PubSubEventPayload.cpp",
 			"Elements/RosterItemExchangePayload.cpp",
 			"Elements/RosterPayload.cpp",
 			"Elements/Stanza.cpp",
@@ -133,6 +136,7 @@ if env["SCONS_STAGE"] == "build" :
 			"Elements/StreamManagementEnabled.cpp",
 			"Elements/StreamResume.cpp",
 			"Elements/StreamResumed.cpp",
+			"Elements/UserLocation.cpp",
 			"Elements/VCard.cpp",
 			"Elements/MUCOccupant.cpp",
 			"Entity/Entity.cpp",
@@ -141,6 +145,8 @@ if env["SCONS_STAGE"] == "build" :
 			"MUC/MUCManager.cpp",
 			"MUC/MUCRegistry.cpp",
 			"MUC/MUCBookmarkManager.cpp",
+			"PubSub/PubSubManager.cpp",
+			"PubSub/PubSubManagerImpl.cpp",
 			"Queries/IQChannel.cpp",
 			"Queries/IQHandler.cpp",
 			"Queries/IQRouter.cpp",
@@ -207,6 +213,7 @@ if env["SCONS_STAGE"] == "build" :
 			"Serializer/PayloadSerializers/StreamInitiationFileInfoSerializer.cpp",
 			"Serializer/PayloadSerializers/DeliveryReceiptSerializer.cpp",
 			"Serializer/PayloadSerializers/DeliveryReceiptRequestSerializer.cpp",
+			"Serializer/PayloadSerializers/UserLocationSerializer.cpp",
 			"Serializer/PayloadSerializers/WhiteboardSerializer.cpp",
 			"Serializer/PresenceSerializer.cpp",
 			"Serializer/StanzaSerializer.cpp",
@@ -232,6 +239,28 @@ if env["SCONS_STAGE"] == "build" :
 			"Elements/Whiteboard/WhiteboardColor.cpp",
 			"Whiteboard/WhiteboardTransformer.cpp",
 		]
+	
+	elements = [
+			"PubSub", "PubSubAffiliations", "PubSubAffiliation", "PubSubConfigure", "PubSubCreate", "PubSubDefault",
+			"PubSubItems", "PubSubItem", "PubSubOptions", "PubSubPublish", "PubSubRetract", "PubSubSubscribeOptions",
+			"PubSubSubscribe", "PubSubSubscriptions", "PubSubSubscription", "PubSubUnsubscribe",
+
+			"PubSubEvent", "PubSubEventAssociate", "PubSubEventCollection", "PubSubEventConfiguration", "PubSubEventDelete",
+			"PubSubEventDisassociate", "PubSubEventItem", "PubSubEventItems", "PubSubEventPurge", "PubSubEventRedirect",
+			"PubSubEventRetract", "PubSubEventSubscription",
+
+			"PubSubOwnerAffiliation", "PubSubOwnerAffiliations", "PubSubOwnerConfigure", "PubSubOwnerDefault",
+			"PubSubOwnerDelete", "PubSubOwnerPubSub", "PubSubOwnerPurge", "PubSubOwnerRedirect",
+			"PubSubOwnerSubscription", "PubSubOwnerSubscriptions",
+
+			"PubSubError",
+	]
+	for element in elements :
+		sources += [
+			"Elements/" + element + ".cpp", 
+			"Serializer/PayloadSerializers/" + element + "Serializer.cpp",
+			"Parser/PayloadParsers/" + element + "Parser.cpp",
+		]
 
 	SConscript(dirs = [
 			"Avatars",
diff --git a/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp b/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp
index 3f45a7c..a57a74e 100644
--- a/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp
+++ b/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2013 Remko Tronçon
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -51,7 +51,12 @@
 #include <Swiften/Serializer/PayloadSerializers/ReplaceSerializer.h>
 #include <Swiften/Serializer/PayloadSerializers/LastSerializer.h>
 #include <Swiften/Serializer/PayloadSerializers/WhiteboardSerializer.h>
+#include <Swiften/Serializer/PayloadSerializers/UserLocationSerializer.h>
 #include <Swiften/Serializer/PayloadSerializers/IdleSerializer.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubSerializer.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerPubSubSerializer.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubEventSerializer.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubErrorSerializer.h>
 
 #include <Swiften/Serializer/PayloadSerializers/StreamInitiationFileInfoSerializer.h>
 #include <Swiften/Serializer/PayloadSerializers/JingleContentPayloadSerializer.h>
@@ -111,6 +116,7 @@ FullPayloadSerializerCollection::FullPayloadSerializerCollection() {
 	serializers_.push_back(new ReplaceSerializer());
 	serializers_.push_back(new LastSerializer());
 	serializers_.push_back(new WhiteboardSerializer());
+	serializers_.push_back(new UserLocationSerializer());
 	serializers_.push_back(new IdleSerializer());
 	
 	serializers_.push_back(new StreamInitiationFileInfoSerializer());
@@ -124,6 +130,11 @@ FullPayloadSerializerCollection::FullPayloadSerializerCollection() {
 	serializers_.push_back(new S5BProxyRequestSerializer());
 	serializers_.push_back(new DeliveryReceiptSerializer());
 	serializers_.push_back(new DeliveryReceiptRequestSerializer());
+
+	serializers_.push_back(new PubSubSerializer(this));
+	serializers_.push_back(new PubSubEventSerializer(this));
+	serializers_.push_back(new PubSubOwnerPubSubSerializer(this));
+	serializers_.push_back(new PubSubErrorSerializer());
 	
 	foreach(PayloadSerializer* serializer, serializers_) {
 		addSerializer(serializer);
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubAffiliationSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubAffiliationSerializer.cpp
new file mode 100644
index 0000000..d5d5ead
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubAffiliationSerializer.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubAffiliationSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+
+
+using namespace Swift;
+
+PubSubAffiliationSerializer::PubSubAffiliationSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubAffiliationSerializer::~PubSubAffiliationSerializer() {
+}
+
+std::string PubSubAffiliationSerializer::serializePayload(boost::shared_ptr<PubSubAffiliation> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("affiliation", "http://jabber.org/protocol/pubsub");
+	element.setAttribute("node", payload->getNode());
+	element.setAttribute("affiliation", serializeType(payload->getType()));
+	return element.serialize();
+}
+
+std::string PubSubAffiliationSerializer::serializeType(PubSubAffiliation::Type value) {
+	switch (value) {
+		case PubSubAffiliation::None: return "none";
+		case PubSubAffiliation::Member: return "member";
+		case PubSubAffiliation::Outcast: return "outcast";
+		case PubSubAffiliation::Owner: return "owner";
+		case PubSubAffiliation::Publisher: return "publisher";
+		case PubSubAffiliation::PublishOnly: return "publish-only";
+	}
+	assert(false);
+	return "";
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubAffiliationSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubAffiliationSerializer.h
new file mode 100644
index 0000000..f6722c8
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubAffiliationSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubAffiliation.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubAffiliationSerializer : public GenericPayloadSerializer<PubSubAffiliation> {
+		public:
+			PubSubAffiliationSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubAffiliationSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubAffiliation>) const SWIFTEN_OVERRIDE;
+
+		private:
+			static std::string serializeType(PubSubAffiliation::Type);
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubAffiliationsSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubAffiliationsSerializer.cpp
new file mode 100644
index 0000000..25a0786
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubAffiliationsSerializer.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubAffiliationsSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+#include <Swiften/Base/foreach.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubAffiliationSerializer.h>
+#include <Swiften/Serializer/XML/XMLRawTextNode.h>
+
+using namespace Swift;
+
+PubSubAffiliationsSerializer::PubSubAffiliationsSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubAffiliationsSerializer::~PubSubAffiliationsSerializer() {
+}
+
+std::string PubSubAffiliationsSerializer::serializePayload(boost::shared_ptr<PubSubAffiliations> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("affiliations", "http://jabber.org/protocol/pubsub");
+	if (payload->getNode()) {
+		element.setAttribute("node", *payload->getNode());
+	}
+	foreach(boost::shared_ptr<PubSubAffiliation> item, payload->getAffiliations()) {
+		element.addNode(boost::make_shared<XMLRawTextNode>(PubSubAffiliationSerializer(serializers).serialize(item)));
+	}
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubAffiliationsSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubAffiliationsSerializer.h
new file mode 100644
index 0000000..ba3c591
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubAffiliationsSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubAffiliations.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubAffiliationsSerializer : public GenericPayloadSerializer<PubSubAffiliations> {
+		public:
+			PubSubAffiliationsSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubAffiliationsSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubAffiliations>) const SWIFTEN_OVERRIDE;
+
+		private:
+			
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubConfigureSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubConfigureSerializer.cpp
new file mode 100644
index 0000000..86a1ae8
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubConfigureSerializer.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubConfigureSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+#include <Swiften/Serializer/PayloadSerializers/FormSerializer.h>
+#include <Swiften/Serializer/XML/XMLRawTextNode.h>
+
+using namespace Swift;
+
+PubSubConfigureSerializer::PubSubConfigureSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubConfigureSerializer::~PubSubConfigureSerializer() {
+}
+
+std::string PubSubConfigureSerializer::serializePayload(boost::shared_ptr<PubSubConfigure> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("configure", "http://jabber.org/protocol/pubsub");
+	element.addNode(boost::make_shared<XMLRawTextNode>(FormSerializer().serialize(payload->getData())));
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubConfigureSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubConfigureSerializer.h
new file mode 100644
index 0000000..093fd35
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubConfigureSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubConfigure.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubConfigureSerializer : public GenericPayloadSerializer<PubSubConfigure> {
+		public:
+			PubSubConfigureSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubConfigureSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubConfigure>) const SWIFTEN_OVERRIDE;
+
+		private:
+			
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubCreateSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubCreateSerializer.cpp
new file mode 100644
index 0000000..73b2703
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubCreateSerializer.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubCreateSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+
+
+using namespace Swift;
+
+PubSubCreateSerializer::PubSubCreateSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubCreateSerializer::~PubSubCreateSerializer() {
+}
+
+std::string PubSubCreateSerializer::serializePayload(boost::shared_ptr<PubSubCreate> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("create", "http://jabber.org/protocol/pubsub");
+	element.setAttribute("node", payload->getNode());
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubCreateSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubCreateSerializer.h
new file mode 100644
index 0000000..29c2393
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubCreateSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubCreate.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubCreateSerializer : public GenericPayloadSerializer<PubSubCreate> {
+		public:
+			PubSubCreateSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubCreateSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubCreate>) const SWIFTEN_OVERRIDE;
+
+		private:
+			
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubDefaultSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubDefaultSerializer.cpp
new file mode 100644
index 0000000..d395c80
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubDefaultSerializer.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubDefaultSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+
+
+using namespace Swift;
+
+PubSubDefaultSerializer::PubSubDefaultSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubDefaultSerializer::~PubSubDefaultSerializer() {
+}
+
+std::string PubSubDefaultSerializer::serializePayload(boost::shared_ptr<PubSubDefault> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("default", "http://jabber.org/protocol/pubsub");
+	if (payload->getNode()) {
+		element.setAttribute("node", *payload->getNode());
+	}
+	element.setAttribute("type", serializeType(payload->getType()));
+	return element.serialize();
+}
+
+std::string PubSubDefaultSerializer::serializeType(PubSubDefault::Type value) {
+	switch (value) {
+		case PubSubDefault::None: return "none";
+		case PubSubDefault::Collection: return "collection";
+		case PubSubDefault::Leaf: return "leaf";
+	}
+	assert(false);
+	return "";
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubDefaultSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubDefaultSerializer.h
new file mode 100644
index 0000000..e7b8a6f
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubDefaultSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubDefault.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubDefaultSerializer : public GenericPayloadSerializer<PubSubDefault> {
+		public:
+			PubSubDefaultSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubDefaultSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubDefault>) const SWIFTEN_OVERRIDE;
+
+		private:
+			static std::string serializeType(PubSubDefault::Type);
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubErrorSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubErrorSerializer.cpp
new file mode 100644
index 0000000..a25b71e
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubErrorSerializer.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubErrorSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+
+using namespace Swift;
+
+PubSubErrorSerializer::PubSubErrorSerializer() {
+}
+
+PubSubErrorSerializer::~PubSubErrorSerializer() {
+}
+
+std::string PubSubErrorSerializer::serializePayload(boost::shared_ptr<PubSubError> payload) const {
+	if (payload->getType() == PubSubError::UnknownType) {
+		return "";
+	}
+	XMLElement element(serializeType(payload->getType()), "http://jabber.org/protocol/pubsub#errors");
+	if (payload->getType() == PubSubError::Unsupported) {
+		if (payload->getUnsupportedFeatureType() != PubSubError::UnknownUnsupportedFeatureType) {
+			element.setAttribute("feature", serializeUnsupportedFeatureType(payload->getUnsupportedFeatureType()));
+		}
+	}
+	return element.serialize();
+}
+
+std::string PubSubErrorSerializer::serializeType(PubSubError::Type value) {
+	switch (value) {
+		case PubSubError::UnknownType: assert(false); return "";
+		case PubSubError::ClosedNode: return "closed-node";
+		case PubSubError::ConfigurationRequired: return "configuration-required";
+		case PubSubError::InvalidJID: return "invalid-jid";
+		case PubSubError::InvalidOptions: return "invalid-options";
+		case PubSubError::InvalidPayload: return "invalid-payload";
+		case PubSubError::InvalidSubscriptionID: return "invalid-subid";
+		case PubSubError::ItemForbidden: return "item-forbidden";
+		case PubSubError::ItemRequired: return "item-required";
+		case PubSubError::JIDRequired: return "jid-required";
+		case PubSubError::MaximumItemsExceeded: return "max-items-exceeded";
+		case PubSubError::MaximumNodesExceeded: return "max-nodes-exceeded";
+		case PubSubError::NodeIDRequired: return "nodeid-required";
+		case PubSubError::NotInRosterGroup: return "not-in-roster-group";
+		case PubSubError::NotSubscribed: return "not-subscribed";
+		case PubSubError::PayloadTooBig: return "payload-too-big";
+		case PubSubError::PayloadRequired: return "payload-required";
+		case PubSubError::PendingSubscription: return "pending-subscription";
+		case PubSubError::PresenceSubscriptionRequired: return "presence-subscription-required";
+		case PubSubError::SubscriptionIDRequired: return "subid-required";
+		case PubSubError::TooManySubscriptions: return "too-many-subscriptions";
+		case PubSubError::Unsupported: return "unsupported";
+		case PubSubError::UnsupportedAccessModel: return "unsupported-access-model";
+	}
+	assert(false);
+	return "";
+}
+
+std::string PubSubErrorSerializer::serializeUnsupportedFeatureType(PubSubError::UnsupportedFeatureType value) {
+	switch (value) {
+		case PubSubError::UnknownUnsupportedFeatureType: assert(false); return "";
+		case PubSubError::AccessAuthorize: return "access-authorize";
+		case PubSubError::AccessOpen: return "access-open";
+		case PubSubError::AccessPresence: return "access-presence";
+		case PubSubError::AccessRoster: return "access-roster";
+		case PubSubError::AccessWhitelist: return "access-whitelist";
+		case PubSubError::AutoCreate: return "auto-create";
+		case PubSubError::AutoSubscribe: return "auto-subscribe";
+		case PubSubError::Collections: return "collections";
+		case PubSubError::ConfigNode: return "config-node";
+		case PubSubError::CreateAndConfigure: return "create-and-configure";
+		case PubSubError::CreateNodes: return "create-nodes";
+		case PubSubError::DeleteItems: return "delete-items";
+		case PubSubError::DeleteNodes: return "delete-nodes";
+		case PubSubError::FilteredNotifications: return "filtered-notifications";
+		case PubSubError::GetPending: return "get-pending";
+		case PubSubError::InstantNodes: return "instant-nodes";
+		case PubSubError::ItemIDs: return "item-ids";
+		case PubSubError::LastPublished: return "last-published";
+		case PubSubError::LeasedSubscription: return "leased-subscription";
+		case PubSubError::ManageSubscriptions: return "manage-subscriptions";
+		case PubSubError::MemberAffiliation: return "member-affiliation";
+		case PubSubError::MetaData: return "meta-data";
+		case PubSubError::ModifyAffiliations: return "modify-affiliations";
+		case PubSubError::MultiCollection: return "multi-collection";
+		case PubSubError::MultiSubscribe: return "multi-subscribe";
+		case PubSubError::OutcastAffiliation: return "outcast-affiliation";
+		case PubSubError::PersistentItems: return "persistent-items";
+		case PubSubError::PresenceNotifications: return "presence-notifications";
+		case PubSubError::PresenceSubscribe: return "presence-subscribe";
+		case PubSubError::Publish: return "publish";
+		case PubSubError::PublishOptions: return "publish-options";
+		case PubSubError::PublishOnlyAffiliation: return "publish-only-affiliation";
+		case PubSubError::PublisherAffiliation: return "publisher-affiliation";
+		case PubSubError::PurgeNodes: return "purge-nodes";
+		case PubSubError::RetractItems: return "retract-items";
+		case PubSubError::RetrieveAffiliations: return "retrieve-affiliations";
+		case PubSubError::RetrieveDefault: return "retrieve-default";
+		case PubSubError::RetrieveItems: return "retrieve-items";
+		case PubSubError::RetrieveSubscriptions: return "retrieve-subscriptions";
+		case PubSubError::Subscribe: return "subscribe";
+		case PubSubError::SubscriptionOptions: return "subscription-options";
+		case PubSubError::SubscriptionNotifications: return "subscription-notifications";
+	}
+	assert(false);
+	return "";
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubErrorSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubErrorSerializer.h
new file mode 100644
index 0000000..3ee09ce
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubErrorSerializer.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubError.h>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubErrorSerializer : public GenericPayloadSerializer<PubSubError> {
+		public:
+			PubSubErrorSerializer();
+			virtual ~PubSubErrorSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubError>) const SWIFTEN_OVERRIDE;
+
+		private:
+			static std::string serializeType(PubSubError::Type);
+			static std::string serializeUnsupportedFeatureType(PubSubError::UnsupportedFeatureType);
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventAssociateSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubEventAssociateSerializer.cpp
new file mode 100644
index 0000000..1baf7e4
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubEventAssociateSerializer.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubEventAssociateSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+
+
+using namespace Swift;
+
+PubSubEventAssociateSerializer::PubSubEventAssociateSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubEventAssociateSerializer::~PubSubEventAssociateSerializer() {
+}
+
+std::string PubSubEventAssociateSerializer::serializePayload(boost::shared_ptr<PubSubEventAssociate> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("associate", "http://jabber.org/protocol/pubsub#event");
+	element.setAttribute("node", payload->getNode());
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventAssociateSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubEventAssociateSerializer.h
new file mode 100644
index 0000000..60cf9c7
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubEventAssociateSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubEventAssociate.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubEventAssociateSerializer : public GenericPayloadSerializer<PubSubEventAssociate> {
+		public:
+			PubSubEventAssociateSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubEventAssociateSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubEventAssociate>) const SWIFTEN_OVERRIDE;
+
+		private:
+			
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventCollectionSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubEventCollectionSerializer.cpp
new file mode 100644
index 0000000..b44acaa
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubEventCollectionSerializer.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubEventCollectionSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubEventAssociateSerializer.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubEventDisassociateSerializer.h>
+#include <Swiften/Serializer/XML/XMLRawTextNode.h>
+
+using namespace Swift;
+
+PubSubEventCollectionSerializer::PubSubEventCollectionSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubEventCollectionSerializer::~PubSubEventCollectionSerializer() {
+}
+
+std::string PubSubEventCollectionSerializer::serializePayload(boost::shared_ptr<PubSubEventCollection> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("collection", "http://jabber.org/protocol/pubsub#event");
+	if (payload->getNode()) {
+		element.setAttribute("node", *payload->getNode());
+	}
+	element.addNode(boost::make_shared<XMLRawTextNode>(PubSubEventDisassociateSerializer(serializers).serialize(payload->getDisassociate())));
+	element.addNode(boost::make_shared<XMLRawTextNode>(PubSubEventAssociateSerializer(serializers).serialize(payload->getAssociate())));
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventCollectionSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubEventCollectionSerializer.h
new file mode 100644
index 0000000..ac5e7c4
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubEventCollectionSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubEventCollection.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubEventCollectionSerializer : public GenericPayloadSerializer<PubSubEventCollection> {
+		public:
+			PubSubEventCollectionSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubEventCollectionSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubEventCollection>) const SWIFTEN_OVERRIDE;
+
+		private:
+			
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventConfigurationSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubEventConfigurationSerializer.cpp
new file mode 100644
index 0000000..f478e4f
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubEventConfigurationSerializer.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubEventConfigurationSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+#include <Swiften/Serializer/PayloadSerializers/FormSerializer.h>
+#include <Swiften/Serializer/XML/XMLRawTextNode.h>
+
+using namespace Swift;
+
+PubSubEventConfigurationSerializer::PubSubEventConfigurationSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubEventConfigurationSerializer::~PubSubEventConfigurationSerializer() {
+}
+
+std::string PubSubEventConfigurationSerializer::serializePayload(boost::shared_ptr<PubSubEventConfiguration> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("configuration", "http://jabber.org/protocol/pubsub#event");
+	element.setAttribute("node", payload->getNode());
+	element.addNode(boost::make_shared<XMLRawTextNode>(FormSerializer().serialize(payload->getData())));
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventConfigurationSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubEventConfigurationSerializer.h
new file mode 100644
index 0000000..6a73496
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubEventConfigurationSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubEventConfiguration.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubEventConfigurationSerializer : public GenericPayloadSerializer<PubSubEventConfiguration> {
+		public:
+			PubSubEventConfigurationSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubEventConfigurationSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubEventConfiguration>) const SWIFTEN_OVERRIDE;
+
+		private:
+			
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventDeleteSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubEventDeleteSerializer.cpp
new file mode 100644
index 0000000..b45adb8
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubEventDeleteSerializer.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubEventDeleteSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubEventRedirectSerializer.h>
+#include <Swiften/Serializer/XML/XMLRawTextNode.h>
+
+using namespace Swift;
+
+PubSubEventDeleteSerializer::PubSubEventDeleteSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubEventDeleteSerializer::~PubSubEventDeleteSerializer() {
+}
+
+std::string PubSubEventDeleteSerializer::serializePayload(boost::shared_ptr<PubSubEventDelete> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("delete", "http://jabber.org/protocol/pubsub#event");
+	element.setAttribute("node", payload->getNode());
+	element.addNode(boost::make_shared<XMLRawTextNode>(PubSubEventRedirectSerializer(serializers).serialize(payload->getRedirects())));
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventDeleteSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubEventDeleteSerializer.h
new file mode 100644
index 0000000..10de3c3
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubEventDeleteSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubEventDelete.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubEventDeleteSerializer : public GenericPayloadSerializer<PubSubEventDelete> {
+		public:
+			PubSubEventDeleteSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubEventDeleteSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubEventDelete>) const SWIFTEN_OVERRIDE;
+
+		private:
+			
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventDisassociateSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubEventDisassociateSerializer.cpp
new file mode 100644
index 0000000..60cc562
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubEventDisassociateSerializer.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubEventDisassociateSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+
+
+using namespace Swift;
+
+PubSubEventDisassociateSerializer::PubSubEventDisassociateSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubEventDisassociateSerializer::~PubSubEventDisassociateSerializer() {
+}
+
+std::string PubSubEventDisassociateSerializer::serializePayload(boost::shared_ptr<PubSubEventDisassociate> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("disassociate", "http://jabber.org/protocol/pubsub#event");
+	element.setAttribute("node", payload->getNode());
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventDisassociateSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubEventDisassociateSerializer.h
new file mode 100644
index 0000000..c7187c7
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubEventDisassociateSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubEventDisassociate.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubEventDisassociateSerializer : public GenericPayloadSerializer<PubSubEventDisassociate> {
+		public:
+			PubSubEventDisassociateSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubEventDisassociateSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubEventDisassociate>) const SWIFTEN_OVERRIDE;
+
+		private:
+			
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventItemSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubEventItemSerializer.cpp
new file mode 100644
index 0000000..2b8b08e
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubEventItemSerializer.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubEventItemSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+#include <Swiften/Base/foreach.h>
+#include <Swiften/Serializer/XML/XMLRawTextNode.h>
+
+using namespace Swift;
+
+PubSubEventItemSerializer::PubSubEventItemSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubEventItemSerializer::~PubSubEventItemSerializer() {
+}
+
+std::string PubSubEventItemSerializer::serializePayload(boost::shared_ptr<PubSubEventItem> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("item", "http://jabber.org/protocol/pubsub#event");
+	if (payload->getNode()) {
+		element.setAttribute("node", *payload->getNode());
+	}
+	if (payload->getPublisher()) {
+		element.setAttribute("publisher", *payload->getPublisher());
+	}
+	foreach(boost::shared_ptr<Payload> item, payload->getData()) {
+		element.addNode(boost::make_shared<XMLRawTextNode>(serializers->getPayloadSerializer(item)->serialize(item)));
+	}
+	if (payload->getID()) {
+		element.setAttribute("id", *payload->getID());
+	}
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventItemSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubEventItemSerializer.h
new file mode 100644
index 0000000..93fa5b0
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubEventItemSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubEventItem.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubEventItemSerializer : public GenericPayloadSerializer<PubSubEventItem> {
+		public:
+			PubSubEventItemSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubEventItemSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubEventItem>) const SWIFTEN_OVERRIDE;
+
+		private:
+			
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventItemsSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubEventItemsSerializer.cpp
new file mode 100644
index 0000000..099aa4b
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubEventItemsSerializer.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubEventItemsSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+#include <Swiften/Base/foreach.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubEventRetractSerializer.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubEventItemSerializer.h>
+#include <Swiften/Serializer/XML/XMLRawTextNode.h>
+
+using namespace Swift;
+
+PubSubEventItemsSerializer::PubSubEventItemsSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubEventItemsSerializer::~PubSubEventItemsSerializer() {
+}
+
+std::string PubSubEventItemsSerializer::serializePayload(boost::shared_ptr<PubSubEventItems> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("items", "http://jabber.org/protocol/pubsub#event");
+	element.setAttribute("node", payload->getNode());
+	foreach(boost::shared_ptr<PubSubEventItem> item, payload->getItems()) {
+		element.addNode(boost::make_shared<XMLRawTextNode>(PubSubEventItemSerializer(serializers).serialize(item)));
+	}
+	foreach(boost::shared_ptr<PubSubEventRetract> item, payload->getRetracts()) {
+		element.addNode(boost::make_shared<XMLRawTextNode>(PubSubEventRetractSerializer(serializers).serialize(item)));
+	}
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventItemsSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubEventItemsSerializer.h
new file mode 100644
index 0000000..6e60ee4
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubEventItemsSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubEventItems.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubEventItemsSerializer : public GenericPayloadSerializer<PubSubEventItems> {
+		public:
+			PubSubEventItemsSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubEventItemsSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubEventItems>) const SWIFTEN_OVERRIDE;
+
+		private:
+			
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventPurgeSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubEventPurgeSerializer.cpp
new file mode 100644
index 0000000..1387848
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubEventPurgeSerializer.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubEventPurgeSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+
+
+using namespace Swift;
+
+PubSubEventPurgeSerializer::PubSubEventPurgeSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubEventPurgeSerializer::~PubSubEventPurgeSerializer() {
+}
+
+std::string PubSubEventPurgeSerializer::serializePayload(boost::shared_ptr<PubSubEventPurge> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("purge", "http://jabber.org/protocol/pubsub#event");
+	element.setAttribute("node", payload->getNode());
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventPurgeSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubEventPurgeSerializer.h
new file mode 100644
index 0000000..ab2d1d8
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubEventPurgeSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubEventPurge.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubEventPurgeSerializer : public GenericPayloadSerializer<PubSubEventPurge> {
+		public:
+			PubSubEventPurgeSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubEventPurgeSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubEventPurge>) const SWIFTEN_OVERRIDE;
+
+		private:
+			
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventRedirectSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubEventRedirectSerializer.cpp
new file mode 100644
index 0000000..7134e58
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubEventRedirectSerializer.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubEventRedirectSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+
+
+using namespace Swift;
+
+PubSubEventRedirectSerializer::PubSubEventRedirectSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubEventRedirectSerializer::~PubSubEventRedirectSerializer() {
+}
+
+std::string PubSubEventRedirectSerializer::serializePayload(boost::shared_ptr<PubSubEventRedirect> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("redirect", "http://jabber.org/protocol/pubsub#event");
+	element.setAttribute("uri", payload->getURI());
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventRedirectSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubEventRedirectSerializer.h
new file mode 100644
index 0000000..751ff19
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubEventRedirectSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubEventRedirect.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubEventRedirectSerializer : public GenericPayloadSerializer<PubSubEventRedirect> {
+		public:
+			PubSubEventRedirectSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubEventRedirectSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubEventRedirect>) const SWIFTEN_OVERRIDE;
+
+		private:
+			
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventRetractSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubEventRetractSerializer.cpp
new file mode 100644
index 0000000..17d1a0f
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubEventRetractSerializer.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubEventRetractSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+
+
+using namespace Swift;
+
+PubSubEventRetractSerializer::PubSubEventRetractSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubEventRetractSerializer::~PubSubEventRetractSerializer() {
+}
+
+std::string PubSubEventRetractSerializer::serializePayload(boost::shared_ptr<PubSubEventRetract> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("retract", "http://jabber.org/protocol/pubsub#event");
+	element.setAttribute("id", payload->getID());
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventRetractSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubEventRetractSerializer.h
new file mode 100644
index 0000000..0d73ec8
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubEventRetractSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubEventRetract.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubEventRetractSerializer : public GenericPayloadSerializer<PubSubEventRetract> {
+		public:
+			PubSubEventRetractSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubEventRetractSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubEventRetract>) const SWIFTEN_OVERRIDE;
+
+		private:
+			
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubEventSerializer.cpp
new file mode 100644
index 0000000..da813cd
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubEventSerializer.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubEventSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubEventConfigurationSerializer.h>
+#include <Swiften/Serializer/XML/XMLRawTextNode.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubEventSubscriptionSerializer.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubEventPurgeSerializer.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubEventCollectionSerializer.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubEventDeleteSerializer.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubEventItemsSerializer.h>
+#include <Swiften/Base/foreach.h>
+
+using namespace Swift;
+
+PubSubEventSerializer::PubSubEventSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+	pubsubSerializers.push_back(boost::make_shared<PubSubEventSubscriptionSerializer>(serializers));
+	pubsubSerializers.push_back(boost::make_shared<PubSubEventPurgeSerializer>(serializers));
+	pubsubSerializers.push_back(boost::make_shared<PubSubEventCollectionSerializer>(serializers));
+	pubsubSerializers.push_back(boost::make_shared<PubSubEventDeleteSerializer>(serializers));
+	pubsubSerializers.push_back(boost::make_shared<PubSubEventItemsSerializer>(serializers));
+	pubsubSerializers.push_back(boost::make_shared<PubSubEventConfigurationSerializer>(serializers));
+}
+
+PubSubEventSerializer::~PubSubEventSerializer() {
+}
+
+std::string PubSubEventSerializer::serializePayload(boost::shared_ptr<PubSubEvent> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("event", "http://jabber.org/protocol/pubsub#event");
+	boost::shared_ptr<PubSubEventPayload> p = payload->getPayload();
+	foreach(boost::shared_ptr<PayloadSerializer> serializer, pubsubSerializers) {
+		if (serializer->canSerialize(p)) {
+			element.addNode(boost::make_shared<XMLRawTextNode>(serializer->serialize(p)));
+		}
+	}
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubEventSerializer.h
new file mode 100644
index 0000000..85b5b90
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubEventSerializer.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubEvent.h>
+#include <boost/shared_ptr.hpp>
+#include <vector>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubEventSerializer : public GenericPayloadSerializer<PubSubEvent> {
+		public:
+			PubSubEventSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubEventSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubEvent>) const SWIFTEN_OVERRIDE;
+
+		private:
+			
+
+		private:
+			PayloadSerializerCollection* serializers;
+			std::vector< boost::shared_ptr<PayloadSerializer> > pubsubSerializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventSubscriptionSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubEventSubscriptionSerializer.cpp
new file mode 100644
index 0000000..9b0a334
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubEventSubscriptionSerializer.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubEventSubscriptionSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+#include <Swiften/Base/DateTime.h>
+
+using namespace Swift;
+
+PubSubEventSubscriptionSerializer::PubSubEventSubscriptionSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubEventSubscriptionSerializer::~PubSubEventSubscriptionSerializer() {
+}
+
+std::string PubSubEventSubscriptionSerializer::serializePayload(boost::shared_ptr<PubSubEventSubscription> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("subscription", "http://jabber.org/protocol/pubsub#event");
+	element.setAttribute("node", payload->getNode());
+	element.setAttribute("jid", payload->getJID());
+	element.setAttribute("subscription", serializeSubscriptionType(payload->getSubscription()));
+	if (payload->getSubscriptionID()) {
+		element.setAttribute("subid", *payload->getSubscriptionID());
+	}
+	element.setAttribute("expiry", dateTimeToString(payload->getExpiry()));
+	return element.serialize();
+}
+
+std::string PubSubEventSubscriptionSerializer::serializeSubscriptionType(PubSubEventSubscription::SubscriptionType value) {
+	switch (value) {
+		case PubSubEventSubscription::None: return "none";
+		case PubSubEventSubscription::Pending: return "pending";
+		case PubSubEventSubscription::Subscribed: return "subscribed";
+		case PubSubEventSubscription::Unconfigured: return "unconfigured";
+	}
+	assert(false);
+	return "";
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventSubscriptionSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubEventSubscriptionSerializer.h
new file mode 100644
index 0000000..3b613bd
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubEventSubscriptionSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubEventSubscription.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubEventSubscriptionSerializer : public GenericPayloadSerializer<PubSubEventSubscription> {
+		public:
+			PubSubEventSubscriptionSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubEventSubscriptionSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubEventSubscription>) const SWIFTEN_OVERRIDE;
+
+		private:
+			static std::string serializeSubscriptionType(PubSubEventSubscription::SubscriptionType);
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.cpp
new file mode 100644
index 0000000..5a82b42
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+#include <Swiften/Base/foreach.h>
+#include <Swiften/Serializer/XML/XMLRawTextNode.h>
+
+using namespace Swift;
+
+PubSubItemSerializer::PubSubItemSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubItemSerializer::~PubSubItemSerializer() {
+}
+
+std::string PubSubItemSerializer::serializePayload(boost::shared_ptr<PubSubItem> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("item", "http://jabber.org/protocol/pubsub");
+	foreach(boost::shared_ptr<Payload> item, payload->getData()) {
+		element.addNode(boost::make_shared<XMLRawTextNode>(serializers->getPayloadSerializer(item)->serialize(item)));
+	}
+	element.setAttribute("id", payload->getID());
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.h
new file mode 100644
index 0000000..56f186d
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubItem.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubItemSerializer : public GenericPayloadSerializer<PubSubItem> {
+		public:
+			PubSubItemSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubItemSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubItem>) const SWIFTEN_OVERRIDE;
+
+		private:
+			
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubItemsSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubItemsSerializer.cpp
new file mode 100644
index 0000000..6bffa6a
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubItemsSerializer.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubItemsSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+#include <boost/lexical_cast.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+#include <Swiften/Base/foreach.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.h>
+#include <Swiften/Serializer/XML/XMLRawTextNode.h>
+
+using namespace Swift;
+
+PubSubItemsSerializer::PubSubItemsSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubItemsSerializer::~PubSubItemsSerializer() {
+}
+
+std::string PubSubItemsSerializer::serializePayload(boost::shared_ptr<PubSubItems> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("items", "http://jabber.org/protocol/pubsub");
+	element.setAttribute("node", payload->getNode());
+	foreach(boost::shared_ptr<PubSubItem> item, payload->getItems()) {
+		element.addNode(boost::make_shared<XMLRawTextNode>(PubSubItemSerializer(serializers).serialize(item)));
+	}
+	if (payload->getMaximumItems()) {
+		element.setAttribute("max_items", boost::lexical_cast<std::string>(*payload->getMaximumItems()));
+	}
+	if (payload->getSubscriptionID()) {
+		element.setAttribute("subid", *payload->getSubscriptionID());
+	}
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubItemsSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubItemsSerializer.h
new file mode 100644
index 0000000..050e156
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubItemsSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubItems.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubItemsSerializer : public GenericPayloadSerializer<PubSubItems> {
+		public:
+			PubSubItemsSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubItemsSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubItems>) const SWIFTEN_OVERRIDE;
+
+		private:
+			
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOptionsSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubOptionsSerializer.cpp
new file mode 100644
index 0000000..db983b9
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubOptionsSerializer.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubOptionsSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+#include <Swiften/Serializer/PayloadSerializers/FormSerializer.h>
+#include <Swiften/Serializer/XML/XMLRawTextNode.h>
+
+using namespace Swift;
+
+PubSubOptionsSerializer::PubSubOptionsSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubOptionsSerializer::~PubSubOptionsSerializer() {
+}
+
+std::string PubSubOptionsSerializer::serializePayload(boost::shared_ptr<PubSubOptions> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("options", "http://jabber.org/protocol/pubsub");
+	element.setAttribute("node", payload->getNode());
+	element.setAttribute("jid", payload->getJID());
+	element.addNode(boost::make_shared<XMLRawTextNode>(FormSerializer().serialize(payload->getData())));
+	if (payload->getSubscriptionID()) {
+		element.setAttribute("subid", *payload->getSubscriptionID());
+	}
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOptionsSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubOptionsSerializer.h
new file mode 100644
index 0000000..258f1f2
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubOptionsSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubOptions.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubOptionsSerializer : public GenericPayloadSerializer<PubSubOptions> {
+		public:
+			PubSubOptionsSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubOptionsSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubOptions>) const SWIFTEN_OVERRIDE;
+
+		private:
+			
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationSerializer.cpp
new file mode 100644
index 0000000..3699b8e
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationSerializer.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+
+
+using namespace Swift;
+
+PubSubOwnerAffiliationSerializer::PubSubOwnerAffiliationSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubOwnerAffiliationSerializer::~PubSubOwnerAffiliationSerializer() {
+}
+
+std::string PubSubOwnerAffiliationSerializer::serializePayload(boost::shared_ptr<PubSubOwnerAffiliation> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("affiliation", "http://jabber.org/protocol/pubsub#owner");
+	element.setAttribute("jid", payload->getJID());
+	element.setAttribute("affiliation", serializeType(payload->getType()));
+	return element.serialize();
+}
+
+std::string PubSubOwnerAffiliationSerializer::serializeType(PubSubOwnerAffiliation::Type value) {
+	switch (value) {
+		case PubSubOwnerAffiliation::None: return "none";
+		case PubSubOwnerAffiliation::Member: return "member";
+		case PubSubOwnerAffiliation::Outcast: return "outcast";
+		case PubSubOwnerAffiliation::Owner: return "owner";
+		case PubSubOwnerAffiliation::Publisher: return "publisher";
+		case PubSubOwnerAffiliation::PublishOnly: return "publish-only";
+	}
+	assert(false);
+	return "";
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationSerializer.h
new file mode 100644
index 0000000..acea723
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubOwnerAffiliation.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubOwnerAffiliationSerializer : public GenericPayloadSerializer<PubSubOwnerAffiliation> {
+		public:
+			PubSubOwnerAffiliationSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubOwnerAffiliationSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubOwnerAffiliation>) const SWIFTEN_OVERRIDE;
+
+		private:
+			static std::string serializeType(PubSubOwnerAffiliation::Type);
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationsSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationsSerializer.cpp
new file mode 100644
index 0000000..c393bfb
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationsSerializer.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationsSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+#include <Swiften/Base/foreach.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationSerializer.h>
+#include <Swiften/Serializer/XML/XMLRawTextNode.h>
+
+using namespace Swift;
+
+PubSubOwnerAffiliationsSerializer::PubSubOwnerAffiliationsSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubOwnerAffiliationsSerializer::~PubSubOwnerAffiliationsSerializer() {
+}
+
+std::string PubSubOwnerAffiliationsSerializer::serializePayload(boost::shared_ptr<PubSubOwnerAffiliations> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("affiliations", "http://jabber.org/protocol/pubsub#owner");
+	element.setAttribute("node", payload->getNode());
+	foreach(boost::shared_ptr<PubSubOwnerAffiliation> item, payload->getAffiliations()) {
+		element.addNode(boost::make_shared<XMLRawTextNode>(PubSubOwnerAffiliationSerializer(serializers).serialize(item)));
+	}
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationsSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationsSerializer.h
new file mode 100644
index 0000000..3d20042
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationsSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubOwnerAffiliations.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubOwnerAffiliationsSerializer : public GenericPayloadSerializer<PubSubOwnerAffiliations> {
+		public:
+			PubSubOwnerAffiliationsSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubOwnerAffiliationsSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubOwnerAffiliations>) const SWIFTEN_OVERRIDE;
+
+		private:
+			
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerConfigureSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubOwnerConfigureSerializer.cpp
new file mode 100644
index 0000000..154a370
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerConfigureSerializer.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerConfigureSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+#include <Swiften/Serializer/PayloadSerializers/FormSerializer.h>
+#include <Swiften/Serializer/XML/XMLRawTextNode.h>
+
+using namespace Swift;
+
+PubSubOwnerConfigureSerializer::PubSubOwnerConfigureSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubOwnerConfigureSerializer::~PubSubOwnerConfigureSerializer() {
+}
+
+std::string PubSubOwnerConfigureSerializer::serializePayload(boost::shared_ptr<PubSubOwnerConfigure> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("configure", "http://jabber.org/protocol/pubsub#owner");
+	if (payload->getNode()) {
+		element.setAttribute("node", *payload->getNode());
+	}
+	element.addNode(boost::make_shared<XMLRawTextNode>(FormSerializer().serialize(payload->getData())));
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerConfigureSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubOwnerConfigureSerializer.h
new file mode 100644
index 0000000..41f2a9d
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerConfigureSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubOwnerConfigure.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubOwnerConfigureSerializer : public GenericPayloadSerializer<PubSubOwnerConfigure> {
+		public:
+			PubSubOwnerConfigureSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubOwnerConfigureSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubOwnerConfigure>) const SWIFTEN_OVERRIDE;
+
+		private:
+			
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerDefaultSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubOwnerDefaultSerializer.cpp
new file mode 100644
index 0000000..7ce2e71
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerDefaultSerializer.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerDefaultSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+#include <Swiften/Serializer/PayloadSerializers/FormSerializer.h>
+#include <Swiften/Serializer/XML/XMLRawTextNode.h>
+
+using namespace Swift;
+
+PubSubOwnerDefaultSerializer::PubSubOwnerDefaultSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubOwnerDefaultSerializer::~PubSubOwnerDefaultSerializer() {
+}
+
+std::string PubSubOwnerDefaultSerializer::serializePayload(boost::shared_ptr<PubSubOwnerDefault> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("default", "http://jabber.org/protocol/pubsub#owner");
+	element.addNode(boost::make_shared<XMLRawTextNode>(FormSerializer().serialize(payload->getData())));
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerDefaultSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubOwnerDefaultSerializer.h
new file mode 100644
index 0000000..02aefe8
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerDefaultSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubOwnerDefault.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubOwnerDefaultSerializer : public GenericPayloadSerializer<PubSubOwnerDefault> {
+		public:
+			PubSubOwnerDefaultSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubOwnerDefaultSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubOwnerDefault>) const SWIFTEN_OVERRIDE;
+
+		private:
+			
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerDeleteSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubOwnerDeleteSerializer.cpp
new file mode 100644
index 0000000..010645c
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerDeleteSerializer.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerDeleteSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerRedirectSerializer.h>
+#include <Swiften/Serializer/XML/XMLRawTextNode.h>
+
+using namespace Swift;
+
+PubSubOwnerDeleteSerializer::PubSubOwnerDeleteSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubOwnerDeleteSerializer::~PubSubOwnerDeleteSerializer() {
+}
+
+std::string PubSubOwnerDeleteSerializer::serializePayload(boost::shared_ptr<PubSubOwnerDelete> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("delete", "http://jabber.org/protocol/pubsub#owner");
+	element.setAttribute("node", payload->getNode());
+	element.addNode(boost::make_shared<XMLRawTextNode>(PubSubOwnerRedirectSerializer(serializers).serialize(payload->getRedirect())));
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerDeleteSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubOwnerDeleteSerializer.h
new file mode 100644
index 0000000..d537a4f
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerDeleteSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubOwnerDelete.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubOwnerDeleteSerializer : public GenericPayloadSerializer<PubSubOwnerDelete> {
+		public:
+			PubSubOwnerDeleteSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubOwnerDeleteSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubOwnerDelete>) const SWIFTEN_OVERRIDE;
+
+		private:
+			
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerPubSubSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubOwnerPubSubSerializer.cpp
new file mode 100644
index 0000000..de7d5a5
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerPubSubSerializer.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerPubSubSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerDeleteSerializer.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionsSerializer.h>
+#include <Swiften/Serializer/XML/XMLRawTextNode.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerDefaultSerializer.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerPurgeSerializer.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationsSerializer.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerConfigureSerializer.h>
+#include <Swiften/Base/foreach.h>
+
+using namespace Swift;
+
+PubSubOwnerPubSubSerializer::PubSubOwnerPubSubSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+	pubsubSerializers.push_back(boost::make_shared<PubSubOwnerConfigureSerializer>(serializers));
+	pubsubSerializers.push_back(boost::make_shared<PubSubOwnerSubscriptionsSerializer>(serializers));
+	pubsubSerializers.push_back(boost::make_shared<PubSubOwnerDefaultSerializer>(serializers));
+	pubsubSerializers.push_back(boost::make_shared<PubSubOwnerPurgeSerializer>(serializers));
+	pubsubSerializers.push_back(boost::make_shared<PubSubOwnerAffiliationsSerializer>(serializers));
+	pubsubSerializers.push_back(boost::make_shared<PubSubOwnerDeleteSerializer>(serializers));
+}
+
+PubSubOwnerPubSubSerializer::~PubSubOwnerPubSubSerializer() {
+}
+
+std::string PubSubOwnerPubSubSerializer::serializePayload(boost::shared_ptr<PubSubOwnerPubSub> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("pubsub", "http://jabber.org/protocol/pubsub#owner");
+	boost::shared_ptr<PubSubOwnerPayload> p = payload->getPayload();
+	foreach(boost::shared_ptr<PayloadSerializer> serializer, pubsubSerializers) {
+		if (serializer->canSerialize(p)) {
+			element.addNode(boost::make_shared<XMLRawTextNode>(serializer->serialize(p)));
+		}
+	}
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerPubSubSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubOwnerPubSubSerializer.h
new file mode 100644
index 0000000..9f5732b
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerPubSubSerializer.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubOwnerPubSub.h>
+#include <boost/shared_ptr.hpp>
+#include <vector>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubOwnerPubSubSerializer : public GenericPayloadSerializer<PubSubOwnerPubSub> {
+		public:
+			PubSubOwnerPubSubSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubOwnerPubSubSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubOwnerPubSub>) const SWIFTEN_OVERRIDE;
+
+		private:
+			
+
+		private:
+			PayloadSerializerCollection* serializers;
+			std::vector< boost::shared_ptr<PayloadSerializer> > pubsubSerializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerPurgeSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubOwnerPurgeSerializer.cpp
new file mode 100644
index 0000000..591cdf9
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerPurgeSerializer.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerPurgeSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+
+
+using namespace Swift;
+
+PubSubOwnerPurgeSerializer::PubSubOwnerPurgeSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubOwnerPurgeSerializer::~PubSubOwnerPurgeSerializer() {
+}
+
+std::string PubSubOwnerPurgeSerializer::serializePayload(boost::shared_ptr<PubSubOwnerPurge> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("purge", "http://jabber.org/protocol/pubsub#owner");
+	element.setAttribute("node", payload->getNode());
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerPurgeSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubOwnerPurgeSerializer.h
new file mode 100644
index 0000000..51a086f
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerPurgeSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubOwnerPurge.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubOwnerPurgeSerializer : public GenericPayloadSerializer<PubSubOwnerPurge> {
+		public:
+			PubSubOwnerPurgeSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubOwnerPurgeSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubOwnerPurge>) const SWIFTEN_OVERRIDE;
+
+		private:
+			
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerRedirectSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubOwnerRedirectSerializer.cpp
new file mode 100644
index 0000000..ea7d721
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerRedirectSerializer.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerRedirectSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+
+
+using namespace Swift;
+
+PubSubOwnerRedirectSerializer::PubSubOwnerRedirectSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubOwnerRedirectSerializer::~PubSubOwnerRedirectSerializer() {
+}
+
+std::string PubSubOwnerRedirectSerializer::serializePayload(boost::shared_ptr<PubSubOwnerRedirect> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("redirect", "http://jabber.org/protocol/pubsub#owner");
+	element.setAttribute("uri", payload->getURI());
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerRedirectSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubOwnerRedirectSerializer.h
new file mode 100644
index 0000000..e5d5af5
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerRedirectSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubOwnerRedirect.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubOwnerRedirectSerializer : public GenericPayloadSerializer<PubSubOwnerRedirect> {
+		public:
+			PubSubOwnerRedirectSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubOwnerRedirectSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubOwnerRedirect>) const SWIFTEN_OVERRIDE;
+
+		private:
+			
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionSerializer.cpp
new file mode 100644
index 0000000..91bc00b
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionSerializer.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+
+
+using namespace Swift;
+
+PubSubOwnerSubscriptionSerializer::PubSubOwnerSubscriptionSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubOwnerSubscriptionSerializer::~PubSubOwnerSubscriptionSerializer() {
+}
+
+std::string PubSubOwnerSubscriptionSerializer::serializePayload(boost::shared_ptr<PubSubOwnerSubscription> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("subscription", "http://jabber.org/protocol/pubsub#owner");
+	element.setAttribute("jid", payload->getJID());
+	element.setAttribute("subscription", serializeSubscriptionType(payload->getSubscription()));
+	return element.serialize();
+}
+
+std::string PubSubOwnerSubscriptionSerializer::serializeSubscriptionType(PubSubOwnerSubscription::SubscriptionType value) {
+	switch (value) {
+		case PubSubOwnerSubscription::None: return "none";
+		case PubSubOwnerSubscription::Pending: return "pending";
+		case PubSubOwnerSubscription::Subscribed: return "subscribed";
+		case PubSubOwnerSubscription::Unconfigured: return "unconfigured";
+	}
+	assert(false);
+	return "";
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionSerializer.h
new file mode 100644
index 0000000..4cecca7
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubOwnerSubscription.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubOwnerSubscriptionSerializer : public GenericPayloadSerializer<PubSubOwnerSubscription> {
+		public:
+			PubSubOwnerSubscriptionSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubOwnerSubscriptionSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubOwnerSubscription>) const SWIFTEN_OVERRIDE;
+
+		private:
+			static std::string serializeSubscriptionType(PubSubOwnerSubscription::SubscriptionType);
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionsSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionsSerializer.cpp
new file mode 100644
index 0000000..c265662
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionsSerializer.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionsSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionSerializer.h>
+#include <Swiften/Base/foreach.h>
+#include <Swiften/Serializer/XML/XMLRawTextNode.h>
+
+using namespace Swift;
+
+PubSubOwnerSubscriptionsSerializer::PubSubOwnerSubscriptionsSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubOwnerSubscriptionsSerializer::~PubSubOwnerSubscriptionsSerializer() {
+}
+
+std::string PubSubOwnerSubscriptionsSerializer::serializePayload(boost::shared_ptr<PubSubOwnerSubscriptions> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("subscriptions", "http://jabber.org/protocol/pubsub#owner");
+	element.setAttribute("node", payload->getNode());
+	foreach(boost::shared_ptr<PubSubOwnerSubscription> item, payload->getSubscriptions()) {
+		element.addNode(boost::make_shared<XMLRawTextNode>(PubSubOwnerSubscriptionSerializer(serializers).serialize(item)));
+	}
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionsSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionsSerializer.h
new file mode 100644
index 0000000..d77bc99
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionsSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubOwnerSubscriptions.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubOwnerSubscriptionsSerializer : public GenericPayloadSerializer<PubSubOwnerSubscriptions> {
+		public:
+			PubSubOwnerSubscriptionsSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubOwnerSubscriptionsSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubOwnerSubscriptions>) const SWIFTEN_OVERRIDE;
+
+		private:
+			
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubPublishSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubPublishSerializer.cpp
new file mode 100644
index 0000000..5a150e0
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubPublishSerializer.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubPublishSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+#include <Swiften/Base/foreach.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.h>
+#include <Swiften/Serializer/XML/XMLRawTextNode.h>
+
+using namespace Swift;
+
+PubSubPublishSerializer::PubSubPublishSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubPublishSerializer::~PubSubPublishSerializer() {
+}
+
+std::string PubSubPublishSerializer::serializePayload(boost::shared_ptr<PubSubPublish> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("publish", "http://jabber.org/protocol/pubsub");
+	element.setAttribute("node", payload->getNode());
+	foreach(boost::shared_ptr<PubSubItem> item, payload->getItems()) {
+		element.addNode(boost::make_shared<XMLRawTextNode>(PubSubItemSerializer(serializers).serialize(item)));
+	}
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubPublishSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubPublishSerializer.h
new file mode 100644
index 0000000..9d53141
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubPublishSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubPublish.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubPublishSerializer : public GenericPayloadSerializer<PubSubPublish> {
+		public:
+			PubSubPublishSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubPublishSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubPublish>) const SWIFTEN_OVERRIDE;
+
+		private:
+			
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubRetractSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubRetractSerializer.cpp
new file mode 100644
index 0000000..3f1434b
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubRetractSerializer.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubRetractSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+#include <Swiften/Base/foreach.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.h>
+#include <Swiften/Serializer/XML/XMLRawTextNode.h>
+
+using namespace Swift;
+
+PubSubRetractSerializer::PubSubRetractSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubRetractSerializer::~PubSubRetractSerializer() {
+}
+
+std::string PubSubRetractSerializer::serializePayload(boost::shared_ptr<PubSubRetract> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("retract", "http://jabber.org/protocol/pubsub");
+	element.setAttribute("node", payload->getNode());
+	foreach(boost::shared_ptr<PubSubItem> item, payload->getItems()) {
+		element.addNode(boost::make_shared<XMLRawTextNode>(PubSubItemSerializer(serializers).serialize(item)));
+	}
+	element.setAttribute("notify", payload->isNotify() ? "true" : "false");
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubRetractSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubRetractSerializer.h
new file mode 100644
index 0000000..47a01af
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubRetractSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubRetract.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubRetractSerializer : public GenericPayloadSerializer<PubSubRetract> {
+		public:
+			PubSubRetractSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubRetractSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubRetract>) const SWIFTEN_OVERRIDE;
+
+		private:
+			
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubSerializer.cpp
new file mode 100644
index 0000000..0e61331
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubSerializer.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubConfigureSerializer.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubAffiliationsSerializer.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubCreateSerializer.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubDefaultSerializer.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubItemsSerializer.h>
+#include <Swiften/Serializer/XML/XMLRawTextNode.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubSubscriptionSerializer.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubUnsubscribeSerializer.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubPublishSerializer.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubOptionsSerializer.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubSubscribeSerializer.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubRetractSerializer.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubSubscriptionsSerializer.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubOptionsSerializer.h>
+#include <Swiften/Base/foreach.h>
+
+using namespace Swift;
+
+PubSubSerializer::PubSubSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+	pubsubSerializers.push_back(boost::make_shared<PubSubItemsSerializer>(serializers));
+	pubsubSerializers.push_back(boost::make_shared<PubSubCreateSerializer>(serializers));
+	pubsubSerializers.push_back(boost::make_shared<PubSubPublishSerializer>(serializers));
+	pubsubSerializers.push_back(boost::make_shared<PubSubOptionsSerializer>(serializers));
+	pubsubSerializers.push_back(boost::make_shared<PubSubAffiliationsSerializer>(serializers));
+	pubsubSerializers.push_back(boost::make_shared<PubSubRetractSerializer>(serializers));
+	pubsubSerializers.push_back(boost::make_shared<PubSubDefaultSerializer>(serializers));
+	pubsubSerializers.push_back(boost::make_shared<PubSubSubscriptionsSerializer>(serializers));
+	pubsubSerializers.push_back(boost::make_shared<PubSubSubscribeSerializer>(serializers));
+	pubsubSerializers.push_back(boost::make_shared<PubSubUnsubscribeSerializer>(serializers));
+	pubsubSerializers.push_back(boost::make_shared<PubSubSubscriptionSerializer>(serializers));
+}
+
+PubSubSerializer::~PubSubSerializer() {
+}
+
+std::string PubSubSerializer::serializePayload(boost::shared_ptr<PubSub> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("pubsub", "http://jabber.org/protocol/pubsub");
+	boost::shared_ptr<PubSubPayload> p = payload->getPayload();
+	foreach(boost::shared_ptr<PayloadSerializer> serializer, pubsubSerializers) {
+		if (serializer->canSerialize(p)) {
+			element.addNode(boost::make_shared<XMLRawTextNode>(serializer->serialize(p)));
+			if (boost::shared_ptr<PubSubCreate> create = boost::dynamic_pointer_cast<PubSubCreate>(p)) {
+				element.addNode(boost::make_shared<XMLRawTextNode>(boost::make_shared<PubSubConfigureSerializer>(serializers)->serialize(create->getConfigure())));
+			}
+			if (boost::shared_ptr<PubSubSubscribe> subscribe = boost::dynamic_pointer_cast<PubSubSubscribe>(p)) {
+				element.addNode(boost::make_shared<XMLRawTextNode>(boost::make_shared<PubSubConfigureSerializer>(serializers)->serialize(subscribe->getOptions())));
+			}
+		}
+	}
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubSerializer.h
new file mode 100644
index 0000000..7665800
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubSerializer.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSub.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubSerializer : public GenericPayloadSerializer<PubSub> {
+		public:
+			PubSubSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSub>) const SWIFTEN_OVERRIDE;
+
+		private:
+			std::vector< boost::shared_ptr<PayloadSerializer> > pubsubSerializers;
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubSubscribeOptionsSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubSubscribeOptionsSerializer.cpp
new file mode 100644
index 0000000..7a55228
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubSubscribeOptionsSerializer.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubSubscribeOptionsSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+#include <Swiften/Serializer/XML/XMLRawTextNode.h>
+
+using namespace Swift;
+
+PubSubSubscribeOptionsSerializer::PubSubSubscribeOptionsSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubSubscribeOptionsSerializer::~PubSubSubscribeOptionsSerializer() {
+}
+
+std::string PubSubSubscribeOptionsSerializer::serializePayload(boost::shared_ptr<PubSubSubscribeOptions> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("subscribe-options", "http://jabber.org/protocol/pubsub");
+	element.addNode(payload->isRequired() ? boost::make_shared<XMLElement>("required", "") : boost::shared_ptr<XMLElement>());
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubSubscribeOptionsSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubSubscribeOptionsSerializer.h
new file mode 100644
index 0000000..6ffaac7
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubSubscribeOptionsSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubSubscribeOptions.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubSubscribeOptionsSerializer : public GenericPayloadSerializer<PubSubSubscribeOptions> {
+		public:
+			PubSubSubscribeOptionsSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubSubscribeOptionsSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubSubscribeOptions>) const SWIFTEN_OVERRIDE;
+
+		private:
+			
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubSubscribeSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubSubscribeSerializer.cpp
new file mode 100644
index 0000000..83a73af
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubSubscribeSerializer.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubSubscribeSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+
+
+using namespace Swift;
+
+PubSubSubscribeSerializer::PubSubSubscribeSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubSubscribeSerializer::~PubSubSubscribeSerializer() {
+}
+
+std::string PubSubSubscribeSerializer::serializePayload(boost::shared_ptr<PubSubSubscribe> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("subscribe", "http://jabber.org/protocol/pubsub");
+	if (payload->getNode()) {
+		element.setAttribute("node", *payload->getNode());
+	}
+	element.setAttribute("jid", payload->getJID());
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubSubscribeSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubSubscribeSerializer.h
new file mode 100644
index 0000000..b730a4d
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubSubscribeSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubSubscribe.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubSubscribeSerializer : public GenericPayloadSerializer<PubSubSubscribe> {
+		public:
+			PubSubSubscribeSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubSubscribeSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubSubscribe>) const SWIFTEN_OVERRIDE;
+
+		private:
+			
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionSerializer.cpp
new file mode 100644
index 0000000..8a54afa
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionSerializer.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubSubscriptionSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubSubscribeOptionsSerializer.h>
+#include <Swiften/Serializer/XML/XMLRawTextNode.h>
+
+using namespace Swift;
+
+PubSubSubscriptionSerializer::PubSubSubscriptionSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubSubscriptionSerializer::~PubSubSubscriptionSerializer() {
+}
+
+std::string PubSubSubscriptionSerializer::serializePayload(boost::shared_ptr<PubSubSubscription> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("subscription", "http://jabber.org/protocol/pubsub");
+	if (payload->getNode()) {
+		element.setAttribute("node", *payload->getNode());
+	}
+	if (payload->getSubscriptionID()) {
+		element.setAttribute("subid", *payload->getSubscriptionID());
+	}
+	element.setAttribute("jid", payload->getJID());
+	element.addNode(boost::make_shared<XMLRawTextNode>(PubSubSubscribeOptionsSerializer(serializers).serialize(payload->getOptions())));
+	element.setAttribute("subscription", serializeSubscriptionType(payload->getSubscription()));
+	return element.serialize();
+}
+
+std::string PubSubSubscriptionSerializer::serializeSubscriptionType(PubSubSubscription::SubscriptionType value) {
+	switch (value) {
+		case PubSubSubscription::None: return "none";
+		case PubSubSubscription::Pending: return "pending";
+		case PubSubSubscription::Subscribed: return "subscribed";
+		case PubSubSubscription::Unconfigured: return "unconfigured";
+	}
+	assert(false);
+	return "";
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionSerializer.h
new file mode 100644
index 0000000..d03bb69
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubSubscription.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubSubscriptionSerializer : public GenericPayloadSerializer<PubSubSubscription> {
+		public:
+			PubSubSubscriptionSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubSubscriptionSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubSubscription>) const SWIFTEN_OVERRIDE;
+
+		private:
+			static std::string serializeSubscriptionType(PubSubSubscription::SubscriptionType);
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionsSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionsSerializer.cpp
new file mode 100644
index 0000000..74f1123
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionsSerializer.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubSubscriptionsSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+#include <Swiften/Serializer/PayloadSerializers/PubSubSubscriptionSerializer.h>
+#include <Swiften/Base/foreach.h>
+#include <Swiften/Serializer/XML/XMLRawTextNode.h>
+
+using namespace Swift;
+
+PubSubSubscriptionsSerializer::PubSubSubscriptionsSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubSubscriptionsSerializer::~PubSubSubscriptionsSerializer() {
+}
+
+std::string PubSubSubscriptionsSerializer::serializePayload(boost::shared_ptr<PubSubSubscriptions> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("subscriptions", "http://jabber.org/protocol/pubsub");
+	if (payload->getNode()) {
+		element.setAttribute("node", *payload->getNode());
+	}
+	foreach(boost::shared_ptr<PubSubSubscription> item, payload->getSubscriptions()) {
+		element.addNode(boost::make_shared<XMLRawTextNode>(PubSubSubscriptionSerializer(serializers).serialize(item)));
+	}
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionsSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionsSerializer.h
new file mode 100644
index 0000000..2b5d8fa
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionsSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubSubscriptions.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubSubscriptionsSerializer : public GenericPayloadSerializer<PubSubSubscriptions> {
+		public:
+			PubSubSubscriptionsSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubSubscriptionsSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubSubscriptions>) const SWIFTEN_OVERRIDE;
+
+		private:
+			
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubUnsubscribeSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubUnsubscribeSerializer.cpp
new file mode 100644
index 0000000..e0d6cd3
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubUnsubscribeSerializer.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+#include <Swiften/Serializer/PayloadSerializers/PubSubUnsubscribeSerializer.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+
+
+#include <Swiften/Serializer/PayloadSerializerCollection.h>
+
+
+using namespace Swift;
+
+PubSubUnsubscribeSerializer::PubSubUnsubscribeSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) {
+}
+
+PubSubUnsubscribeSerializer::~PubSubUnsubscribeSerializer() {
+}
+
+std::string PubSubUnsubscribeSerializer::serializePayload(boost::shared_ptr<PubSubUnsubscribe> payload) const {
+	if (!payload) {
+		return "";
+	}
+	XMLElement element("unsubscribe", "http://jabber.org/protocol/pubsub");
+	if (payload->getNode()) {
+		element.setAttribute("node", *payload->getNode());
+	}
+	element.setAttribute("jid", payload->getJID());
+	if (payload->getSubscriptionID()) {
+		element.setAttribute("subid", *payload->getSubscriptionID());
+	}
+	return element.serialize();
+}
+
+
diff --git a/Swiften/Serializer/PayloadSerializers/PubSubUnsubscribeSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubUnsubscribeSerializer.h
new file mode 100644
index 0000000..b4f6f62
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/PubSubUnsubscribeSerializer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+#include <Swiften/Base/API.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/PubSubUnsubscribe.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class PayloadSerializerCollection;
+
+	class SWIFTEN_API PubSubUnsubscribeSerializer : public GenericPayloadSerializer<PubSubUnsubscribe> {
+		public:
+			PubSubUnsubscribeSerializer(PayloadSerializerCollection* serializers);
+			virtual ~PubSubUnsubscribeSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<PubSubUnsubscribe>) const SWIFTEN_OVERRIDE;
+
+		private:
+			
+
+		private:
+			PayloadSerializerCollection* serializers;
+	};
+}
diff --git a/Swiften/Serializer/PayloadSerializers/UserLocationSerializer.cpp b/Swiften/Serializer/PayloadSerializers/UserLocationSerializer.cpp
new file mode 100644
index 0000000..373276b
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/UserLocationSerializer.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/Serializer/PayloadSerializers/UserLocationSerializer.h>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include <Swiften/Base/foreach.h>
+#include <Swiften/Base/DateTime.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+
+namespace Swift {
+
+UserLocationSerializer::UserLocationSerializer() {
+}
+
+std::string UserLocationSerializer::serializePayload(
+		boost::shared_ptr<UserLocation> payload) const {
+	XMLElement result("geoloc", "http://jabber.org/protocol/geoloc");
+	if (boost::optional<std::string> value = payload->getArea()) {
+		result.addNode(boost::make_shared<XMLElement>("area", "", *value));
+	}
+	else if (boost::optional<float> value = payload->getAltitude()) {
+		result.addNode(boost::make_shared<XMLElement>("alt", "", boost::lexical_cast<std::string>(*value)));
+	}
+	else if (boost::optional<std::string> value = payload->getLocality()) {
+		result.addNode(boost::make_shared<XMLElement>("locality", "", *value));
+	}
+	else if (boost::optional<float> value = payload->getLatitude()) {
+		result.addNode(boost::make_shared<XMLElement>("lat", "", boost::lexical_cast<std::string>(*value)));
+	}
+	else if (boost::optional<float> value = payload->getAccuracy()) {
+		result.addNode(boost::make_shared<XMLElement>("lon", "", boost::lexical_cast<std::string>(*value)));
+	}
+	else if (boost::optional<std::string> value = payload->getDescription()) {
+		result.addNode(boost::make_shared<XMLElement>("description", "", *value));
+	}
+	else if (boost::optional<std::string> value = payload->getCountryCode()) {
+		result.addNode(boost::make_shared<XMLElement>("countrycode", "", *value));
+	}
+	else if (boost::optional<boost::posix_time::ptime> value = payload->getTimestamp()) {
+		result.addNode(boost::make_shared<XMLElement>("timestamp", "", dateTimeToString(*value)));
+	}
+	else if (boost::optional<std::string> value = payload->getFloor()) {
+		result.addNode(boost::make_shared<XMLElement>("floor", "", *value));
+	}
+	else if (boost::optional<std::string> value = payload->getBuilding()) {
+		result.addNode(boost::make_shared<XMLElement>("building", "", *value));
+	}
+	else if (boost::optional<std::string> value = payload->getRoom()) {
+		result.addNode(boost::make_shared<XMLElement>("room", "", *value));
+	}
+	else if (boost::optional<std::string> value = payload->getCountry()) {
+		result.addNode(boost::make_shared<XMLElement>("country", "", *value));
+	}
+	else if (boost::optional<std::string> value = payload->getRegion()) {
+		result.addNode(boost::make_shared<XMLElement>("region", "", *value));
+	}
+	else if (boost::optional<std::string> value = payload->getURI()) {
+		result.addNode(boost::make_shared<XMLElement>("uri", "", *value));
+	}
+	else if (boost::optional<float> value = payload->getLongitude()) {
+		result.addNode(boost::make_shared<XMLElement>("lon", "", boost::lexical_cast<std::string>(*value)));
+	}
+	else if (boost::optional<float> value = payload->getError()) {
+		result.addNode(boost::make_shared<XMLElement>("error", "", boost::lexical_cast<std::string>(*value)));
+	}
+	else if (boost::optional<std::string> value = payload->getPostalCode()) {
+		result.addNode(boost::make_shared<XMLElement>("postalcode", "", *value));
+	}
+	else if (boost::optional<float> value = payload->getBearing()) {
+		result.addNode(boost::make_shared<XMLElement>("bearing", "", boost::lexical_cast<std::string>(*value)));
+	}
+	else if (boost::optional<std::string> value = payload->getText()) {
+		result.addNode(boost::make_shared<XMLElement>("text", "", *value));
+	}
+	else if (boost::optional<std::string> value = payload->getDatum()) {
+		result.addNode(boost::make_shared<XMLElement>("datum", "", *value));
+	}
+	else if (boost::optional<std::string> value = payload->getStreet()) {
+		result.addNode(boost::make_shared<XMLElement>("street", "", *value));
+	}
+	else if (boost::optional<float> value = payload->getSpeed()) {
+		result.addNode(boost::make_shared<XMLElement>("speed", "", boost::lexical_cast<std::string>(*value)));
+	}
+	return result.serialize();
+}
+
+}
diff --git a/Swiften/Serializer/PayloadSerializers/UserLocationSerializer.h b/Swiften/Serializer/PayloadSerializers/UserLocationSerializer.h
new file mode 100644
index 0000000..28a5fe8
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/UserLocationSerializer.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+#include <Swiften/Elements/UserLocation.h>
+
+namespace Swift {
+	class UserLocationSerializer : public GenericPayloadSerializer<UserLocation> {
+		public:
+			UserLocationSerializer();
+
+			virtual std::string serializePayload(boost::shared_ptr<UserLocation>)  const;
+	};
+}
diff --git a/Swiften/Serializer/XML/XMLElement.cpp b/Swiften/Serializer/XML/XMLElement.cpp
index d39ec39..42b602a 100644
--- a/Swiften/Serializer/XML/XMLElement.cpp
+++ b/Swiften/Serializer/XML/XMLElement.cpp
@@ -52,7 +52,9 @@ void XMLElement::setAttribute(const std::string& attribute, const std::string& v
 }
 
 void XMLElement::addNode(boost::shared_ptr<XMLNode> node) {
-	childNodes_.push_back(node);
+	if (node) {
+		childNodes_.push_back(node);
+	}
 }
 
 }
-- 
cgit v0.10.2-6-g49f6