From 37bfeaf6f2e0145731c32f79291ff3d48ae0e1b1 Mon Sep 17 00:00:00 2001
From: Kevin Smith <git@kismith.co.uk>
Date: Fri, 4 Mar 2011 10:56:07 +0000
Subject: Upgrade XEP-0258 support to match 0.6.

Resolves: #183
Release-Notes: Security labels (XEP-0258) support has been updated to match the latest version of the specification.

diff --git a/Swift/Controllers/Chat/ChatController.cpp b/Swift/Controllers/Chat/ChatController.cpp
index 6e7825f..722d68c 100644
--- a/Swift/Controllers/Chat/ChatController.cpp
+++ b/Swift/Controllers/Chat/ChatController.cpp
@@ -112,7 +112,7 @@ void ChatController::preSendMessageRequest(boost::shared_ptr<Message> message) {
 }
 
 void ChatController::postSendMessage(const std::string& body, boost::shared_ptr<Stanza> sentStanza) {
-	std::string id = addMessage(body, QT_TRANSLATE_NOOP("", "me"), true, labelsEnabled_ ? chatWindow_->getSelectedSecurityLabel() : boost::optional<SecurityLabel>(), std::string(avatarManager_->getAvatarPath(selfJID_).string()), boost::posix_time::microsec_clock::universal_time());
+	std::string id = addMessage(body, QT_TRANSLATE_NOOP("", "me"), true, labelsEnabled_ ? chatWindow_->getSelectedSecurityLabel().getLabel() : boost::shared_ptr<SecurityLabel>(), std::string(avatarManager_->getAvatarPath(selfJID_).string()), boost::posix_time::microsec_clock::universal_time());
 	if (stanzaChannel_->getStreamManagementEnabled()) {
 		chatWindow_->setAckState(id, ChatWindow::Pending);
 		unackedStanzas_[sentStanza] = id;
diff --git a/Swift/Controllers/Chat/ChatControllerBase.cpp b/Swift/Controllers/Chat/ChatControllerBase.cpp
index a970d88..b819835 100644
--- a/Swift/Controllers/Chat/ChatControllerBase.cpp
+++ b/Swift/Controllers/Chat/ChatControllerBase.cpp
@@ -67,7 +67,7 @@ void ChatControllerBase::setOnline(bool online) {
 }
 
 void ChatControllerBase::setAvailableServerFeatures(boost::shared_ptr<DiscoInfo> info) {
-	if (iqRouter_->isAvailable() && info->hasFeature(DiscoInfo::SecurityLabels)) {
+	if (iqRouter_->isAvailable() && info->hasFeature(DiscoInfo::SecurityLabelsCatalogueFeature)) {
 		//chatWindow_->setSecurityLabelsEnabled(true);
 		//chatWindow_->setSecurityLabelsError();
 		GetSecurityLabelsCatalogRequest::ref request = GetSecurityLabelsCatalogRequest::create(JID(toJID_.toBare()), iqRouter_);
@@ -96,10 +96,8 @@ void ChatControllerBase::handleSendMessageRequest(const std::string &body) {
 	message->setTo(toJID_);
 	message->setType(Swift::Message::Chat);
 	message->setBody(body);
-	boost::optional<SecurityLabel> label;
 	if (labelsEnabled_) {
-		message->addPayload(boost::shared_ptr<SecurityLabel>(new SecurityLabel(chatWindow_->getSelectedSecurityLabel())));
-		label = boost::optional<SecurityLabel>(chatWindow_->getSelectedSecurityLabel());
+		message->addPayload(chatWindow_->getSelectedSecurityLabel().getLabel());
 	}
 	preSendMessageRequest(message);
 	if (useDelayForLatency_) {
@@ -112,12 +110,12 @@ void ChatControllerBase::handleSendMessageRequest(const std::string &body) {
 
 void ChatControllerBase::handleSecurityLabelsCatalogResponse(boost::shared_ptr<SecurityLabelsCatalog> catalog, ErrorPayload::ref error) {
 	if (!error) {
-		if (catalog->getLabels().size() == 0) {
+		if (catalog->getItems().size() == 0) {
 			chatWindow_->setSecurityLabelsEnabled(false);
 			labelsEnabled_ = false;
 		} else {
 			labelsEnabled_ = true;
-			chatWindow_->setAvailableSecurityLabels(catalog->getLabels());
+			chatWindow_->setAvailableSecurityLabels(catalog->getItems());
 			chatWindow_->setSecurityLabelsEnabled(true);
 		}
 	} else {
@@ -134,7 +132,7 @@ void ChatControllerBase::activateChatWindow() {
 	chatWindow_->activate();
 }
 
-std::string ChatControllerBase::addMessage(const std::string& message, const std::string& senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const std::string& avatarPath, const boost::posix_time::ptime& time) {
+std::string ChatControllerBase::addMessage(const std::string& message, const std::string& senderName, bool senderIsSelf, const boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time) {
 	if (boost::starts_with(message, "/me ")) {
 		return chatWindow_->addAction(String::getSplittedAtFirst(message, ' ').second, senderName, senderIsSelf, label, avatarPath, time);
 	} else {
@@ -174,7 +172,6 @@ void ChatControllerBase::handleIncomingMessage(boost::shared_ptr<MessageEvent> m
 			chatWindow_->addSystemMessage(std::string(s.str()));
 		}
 		boost::shared_ptr<SecurityLabel> label = message->getPayload<SecurityLabel>();
-		boost::optional<SecurityLabel> maybeLabel = label ? boost::optional<SecurityLabel>(*label) : boost::optional<SecurityLabel>();
 
 		// Determine the timestamp
 		boost::posix_time::ptime timeStamp = boost::posix_time::microsec_clock::universal_time();
@@ -183,7 +180,7 @@ void ChatControllerBase::handleIncomingMessage(boost::shared_ptr<MessageEvent> m
 			timeStamp = *messageTimeStamp;
 		}
 
-		addMessage(body, senderDisplayNameFromMessage(from), isIncomingMessageFromMe(message), maybeLabel, std::string(avatarManager_->getAvatarPath(from).string()), timeStamp);
+		addMessage(body, senderDisplayNameFromMessage(from), isIncomingMessageFromMe(message), label, std::string(avatarManager_->getAvatarPath(from).string()), timeStamp);
 	}
 	chatWindow_->show();
 	chatWindow_->setUnreadMessageCount(unreadMessages_.size());
diff --git a/Swift/Controllers/Chat/ChatControllerBase.h b/Swift/Controllers/Chat/ChatControllerBase.h
index 4a1f8e0..6a92429 100644
--- a/Swift/Controllers/Chat/ChatControllerBase.h
+++ b/Swift/Controllers/Chat/ChatControllerBase.h
@@ -43,7 +43,7 @@ namespace Swift {
 			void activateChatWindow();
 			void setAvailableServerFeatures(boost::shared_ptr<DiscoInfo> info);
 			void handleIncomingMessage(boost::shared_ptr<MessageEvent> message);
-			std::string addMessage(const std::string& message, const std::string& senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const std::string& avatarPath, const boost::posix_time::ptime& time);
+			std::string addMessage(const std::string& message, const std::string& senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time);
 			virtual void setOnline(bool online);
 			virtual void setEnabled(bool enabled);
 			virtual void setToJID(const JID& jid) {toJID_ = jid;};
diff --git a/Swift/Controllers/UIInterfaces/ChatWindow.h b/Swift/Controllers/UIInterfaces/ChatWindow.h
index b90ae46..c7bcf1e 100644
--- a/Swift/Controllers/UIInterfaces/ChatWindow.h
+++ b/Swift/Controllers/UIInterfaces/ChatWindow.h
@@ -14,7 +14,7 @@
 #include <vector>
 
 #include <string>
-#include "Swiften/Elements/SecurityLabel.h"
+#include "Swiften/Elements/SecurityLabelsCatalog.h"
 #include "Swiften/Elements/ChatState.h"
 
 namespace Swift {
@@ -32,11 +32,11 @@ namespace Swift {
 			/** Add message to window.
 			 * @return id of added message (for acks).
 			 */
-			virtual std::string addMessage(const std::string& message, const std::string& senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const std::string& avatarPath, const boost::posix_time::ptime& time) = 0;
+			virtual std::string addMessage(const std::string& message, const std::string& senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time) = 0;
 			/** Adds action to window.
 			 * @return id of added message (for acks);
 			 */
-			virtual std::string addAction(const std::string& message, const std::string& senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const std::string& avatarPath, const boost::posix_time::ptime& time) = 0;
+			virtual std::string addAction(const std::string& message, const std::string& senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time) = 0;
 			virtual void addSystemMessage(const std::string& message) = 0;
 			virtual void addPresenceMessage(const std::string& message) = 0;
 			virtual void addErrorMessage(const std::string& message) = 0;
@@ -45,13 +45,13 @@ namespace Swift {
 			virtual void setName(const std::string& name) = 0;
 			virtual void show() = 0;
 			virtual void activate() = 0;
-			virtual void setAvailableSecurityLabels(const std::vector<SecurityLabel>& labels) = 0;
+			virtual void setAvailableSecurityLabels(const std::vector<SecurityLabelsCatalog::Item>& labels) = 0;
 			virtual void setSecurityLabelsEnabled(bool enabled) = 0;
 			virtual void setUnreadMessageCount(int count) = 0;
 			virtual void convertToMUC() = 0;
 //			virtual TreeWidget *getTreeWidget() = 0;
 			virtual void setSecurityLabelsError() = 0;
-			virtual SecurityLabel getSelectedSecurityLabel() = 0;
+			virtual SecurityLabelsCatalog::Item getSelectedSecurityLabel() = 0;
 			virtual void setInputEnabled(bool enabled) = 0;
 			virtual void setRosterModel(Roster* model) = 0;
 			virtual void setTabComplete(TabComplete* completer) = 0;
diff --git a/Swift/Controllers/UnitTest/MockChatWindow.h b/Swift/Controllers/UnitTest/MockChatWindow.h
index 27b9c9e..53a90a7 100644
--- a/Swift/Controllers/UnitTest/MockChatWindow.h
+++ b/Swift/Controllers/UnitTest/MockChatWindow.h
@@ -14,8 +14,8 @@ namespace Swift {
 			MockChatWindow() {};
 			virtual ~MockChatWindow();
 
-			virtual std::string addMessage(const std::string& message, const std::string& /*senderName*/, bool /*senderIsSelf*/, const boost::optional<SecurityLabel>& /*label*/, const std::string& /*avatarPath*/, const boost::posix_time::ptime&) {lastMessageBody_ = message; return "";};
-			virtual std::string addAction(const std::string& message, const std::string& /*senderName*/, bool /*senderIsSelf*/, const boost::optional<SecurityLabel>& /*label*/, const std::string& /*avatarPath*/, const boost::posix_time::ptime&) {lastMessageBody_ = message; return "";};
+			virtual std::string addMessage(const std::string& message, const std::string& /*senderName*/, bool /*senderIsSelf*/, boost::shared_ptr<SecurityLabel> /*label*/, const std::string& /*avatarPath*/, const boost::posix_time::ptime&) {lastMessageBody_ = message; return "";};
+			virtual std::string addAction(const std::string& message, const std::string& /*senderName*/, bool /*senderIsSelf*/, boost::shared_ptr<SecurityLabel> /*label*/, const std::string& /*avatarPath*/, const boost::posix_time::ptime&) {lastMessageBody_ = message; return "";};
 			virtual void addSystemMessage(const std::string& /*message*/) {};
 			virtual void addErrorMessage(const std::string& /*message*/) {};
 			virtual void addPresenceMessage(const std::string& /*message*/) {};
@@ -24,12 +24,12 @@ namespace Swift {
 			virtual void setName(const std::string& name) {name_ = name;};
 			virtual void show() {};
 			virtual void activate() {};
-			virtual void setAvailableSecurityLabels(const std::vector<SecurityLabel>& labels) {labels_ = labels;};
+			virtual void setAvailableSecurityLabels(const std::vector<SecurityLabelsCatalog::Item>& labels) {labels_ = labels;};
 			virtual void setSecurityLabelsEnabled(bool enabled) {labelsEnabled_ = enabled;};
 			virtual void setUnreadMessageCount(int /*count*/) {};
 			virtual void convertToMUC() {};
 			virtual void setSecurityLabelsError() {};
-			virtual SecurityLabel getSelectedSecurityLabel() {return SecurityLabel();};
+			virtual SecurityLabelsCatalog::Item getSelectedSecurityLabel() {return SecurityLabelsCatalog::Item();};
 			virtual void setInputEnabled(bool /*enabled*/) {};
 			virtual void setRosterModel(Roster* /*roster*/) {};
 			virtual void setTabComplete(TabComplete*) {};
@@ -43,7 +43,7 @@ namespace Swift {
 
 			std::string name_;
 			std::string lastMessageBody_;
-			std::vector<SecurityLabel> labels_;
+			std::vector<SecurityLabelsCatalog::Item> labels_;
 			bool labelsEnabled_;
 	};
 }
diff --git a/Swift/QtUI/QtChatWindow.cpp b/Swift/QtUI/QtChatWindow.cpp
index f056a1d..998912a 100644
--- a/Swift/QtUI/QtChatWindow.cpp
+++ b/Swift/QtUI/QtChatWindow.cpp
@@ -151,15 +151,22 @@ void QtChatWindow::setRosterModel(Roster* roster) {
 	treeWidget_->setRosterModel(roster);	
 }
 
-void QtChatWindow::setAvailableSecurityLabels(const std::vector<SecurityLabel>& labels) {
+void QtChatWindow::setAvailableSecurityLabels(const std::vector<SecurityLabelsCatalog::Item>& labels) {
 	availableLabels_ = labels;
 	labelsWidget_->clear();
 	int i = 0;
-	foreach (SecurityLabel label, labels) {
-		QString labelName = P2QSTRING(label.getDisplayMarking());
+	int defaultIndex = 0;
+	foreach (SecurityLabelsCatalog::Item label, labels) {
+		std::string selector = label.getSelector();
+		std::string displayMarking = label.getLabel() ? label.getLabel()->getDisplayMarking() : "";
+		QString labelName = selector.empty() ? displayMarking.c_str() : selector.c_str();
 		labelsWidget_->addItem(labelName, QVariant(i));
+		if (label.getIsDefault()) {
+			defaultIndex = i;
+		}
 		i++;
 	}
+	labelsWidget_->setCurrentIndex(defaultIndex);
 }
 
 
@@ -176,7 +183,7 @@ void QtChatWindow::setSecurityLabelsEnabled(bool enabled) {
 	}
 }
 
-SecurityLabel QtChatWindow::getSelectedSecurityLabel() {
+SecurityLabelsCatalog::Item QtChatWindow::getSelectedSecurityLabel() {
 	assert(labelsWidget_->isEnabled());
 	return availableLabels_[labelsWidget_->currentIndex()];
 }
@@ -248,11 +255,11 @@ void QtChatWindow::updateTitleWithUnreadCount() {
 	emit titleUpdated();
 }
 
-std::string QtChatWindow::addMessage(const std::string &message, const std::string &senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const std::string& avatarPath, const boost::posix_time::ptime& time) {
+std::string QtChatWindow::addMessage(const std::string &message, const std::string &senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time) {
 	return addMessage(message, senderName, senderIsSelf, label, avatarPath, "", time);
 }
 
-std::string QtChatWindow::addMessage(const std::string &message, const std::string &senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const std::string& avatarPath, const QString& style, const boost::posix_time::ptime& time) {
+std::string QtChatWindow::addMessage(const std::string &message, const std::string &senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const QString& style, const boost::posix_time::ptime& time) {
 	if (isWidgetSelected()) {
 		onAllMessagesRead();
 	}
@@ -299,7 +306,7 @@ int QtChatWindow::getCount() {
 	return unreadCount_;
 }
 
-std::string QtChatWindow::addAction(const std::string &message, const std::string &senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const std::string& avatarPath, const boost::posix_time::ptime& time) {
+std::string QtChatWindow::addAction(const std::string &message, const std::string &senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time) {
 	return addMessage(" *" + message + "*", senderName, senderIsSelf, label, avatarPath, "font-style:italic ", time);
 }
 
diff --git a/Swift/QtUI/QtChatWindow.h b/Swift/QtUI/QtChatWindow.h
index dbcfe9c..910019b 100644
--- a/Swift/QtUI/QtChatWindow.h
+++ b/Swift/QtUI/QtChatWindow.h
@@ -30,8 +30,8 @@ namespace Swift {
 		public:
 			QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventStream* eventStream);
 			~QtChatWindow();
-			std::string addMessage(const std::string &message, const std::string &senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const std::string& avatarPath, const boost::posix_time::ptime& time);
-			std::string addAction(const std::string &message, const std::string &senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const std::string& avatarPath, const boost::posix_time::ptime& time);
+			std::string addMessage(const std::string &message, const std::string &senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time);
+			std::string addAction(const std::string &message, const std::string &senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time);
 			void addSystemMessage(const std::string& message);
 			void addPresenceMessage(const std::string& message);
 			void addErrorMessage(const std::string& errorMessage);
@@ -40,10 +40,10 @@ namespace Swift {
 			void setUnreadMessageCount(int count);
 			void convertToMUC();
 //			TreeWidget *getTreeWidget();
-			void setAvailableSecurityLabels(const std::vector<SecurityLabel>& labels);
+			void setAvailableSecurityLabels(const std::vector<SecurityLabelsCatalog::Item>& labels);
 			void setSecurityLabelsEnabled(bool enabled);
 			void setSecurityLabelsError();
-			SecurityLabel getSelectedSecurityLabel();
+			SecurityLabelsCatalog::Item getSelectedSecurityLabel();
 			void setName(const std::string& name);
 			void setInputEnabled(bool enabled);
 			QtTabbable::AlertType getWidgetAlertState();
@@ -75,7 +75,7 @@ namespace Swift {
 		private:
 			void updateTitleWithUnreadCount();
 			void tabComplete();
-			std::string addMessage(const std::string &message, const std::string &senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const std::string& avatarPath, const QString& style, const boost::posix_time::ptime& time);
+			std::string addMessage(const std::string &message, const std::string &senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const QString& style, const boost::posix_time::ptime& time);
 
 			int unreadCount_;
 			bool contactIsTyping_;
@@ -86,7 +86,7 @@ namespace Swift {
 			QComboBox* labelsWidget_;
 			QtTreeWidget* treeWidget_;
 			TabComplete* completer_;
-			std::vector<SecurityLabel> availableLabels_;
+			std::vector<SecurityLabelsCatalog::Item> availableLabels_;
 			bool previousMessageWasSelf_;
 			bool previousMessageWasSystem_;
 			bool previousMessageWasPresence_;
diff --git a/Swiften/Elements/DiscoInfo.cpp b/Swiften/Elements/DiscoInfo.cpp
index 9c43ef4..7ed8e88 100644
--- a/Swiften/Elements/DiscoInfo.cpp
+++ b/Swiften/Elements/DiscoInfo.cpp
@@ -10,6 +10,7 @@ namespace Swift {
 
 const std::string DiscoInfo::ChatStatesFeature = std::string("http://jabber.org/protocol/chatstates");
 const std::string DiscoInfo::SecurityLabelsFeature = std::string("urn:xmpp:sec-label:0");
+const std::string DiscoInfo::SecurityLabelsCatalogueFeature = std::string("urn:xmpp:sec-label:catalog:2");
 const std::string DiscoInfo::JabberSearchFeature = std::string("jabber:iq:search");
 
 
@@ -32,5 +33,4 @@ bool DiscoInfo::Identity::operator<(const Identity& other) const {
 	}
 }
 
-const std::string DiscoInfo::SecurityLabels = "urn:xmpp:sec-label:0";
 }
diff --git a/Swiften/Elements/DiscoInfo.h b/Swiften/Elements/DiscoInfo.h
index 5101884..e433b26 100644
--- a/Swiften/Elements/DiscoInfo.h
+++ b/Swiften/Elements/DiscoInfo.h
@@ -21,9 +21,9 @@ namespace Swift {
 
 			static const std::string ChatStatesFeature;
 			static const std::string SecurityLabelsFeature;
+			static const std::string SecurityLabelsCatalogueFeature;
 			static const std::string JabberSearchFeature;
 
-			const static std::string SecurityLabels;
 			class Identity {
 				public:
 					Identity(const std::string& name, const std::string& category = "client", const std::string& type = "pc", const std::string& lang = "") : name_(name), category_(category), type_(type), lang_(lang) {
diff --git a/Swiften/Elements/SecurityLabelsCatalog.h b/Swiften/Elements/SecurityLabelsCatalog.h
index 1c13fdf..10ef459 100644
--- a/Swiften/Elements/SecurityLabelsCatalog.h
+++ b/Swiften/Elements/SecurityLabelsCatalog.h
@@ -17,14 +17,41 @@
 namespace Swift {
 	class SecurityLabelsCatalog : public Payload {
 		public:
+			class Item {
+				public:
+					Item() : default_(false) {}
+					const boost::shared_ptr<SecurityLabel> getLabel() const {
+						return label_;
+					}
+
+					void setLabel(boost::shared_ptr<SecurityLabel> label) {
+						label_ = label;
+					}
+
+					const std::string& getSelector() const { return selector_; }
+
+					void setSelector(const std::string& selector) {
+						selector_ = selector;
+					}
+
+					bool getIsDefault() const { return default_; }
+
+					void setIsDefault(bool isDefault) {
+						default_ = isDefault;
+					}
+				private:
+					boost::shared_ptr<SecurityLabel> label_;
+					std::string selector_;
+					bool default_;
+			};
 			SecurityLabelsCatalog(const JID& to = JID()) : to_(to) {}
 
-			const std::vector<SecurityLabel>& getLabels() const {
-				return labels_;
+			const std::vector<Item>& getItems() const {
+				return items_;
 			}
 
-			void addLabel(const SecurityLabel& label) {
-				labels_.push_back(label);
+			void addItem(const Item& item) {
+				items_.push_back(item);
 			}
 
 			const JID& getTo() const {
@@ -55,7 +82,7 @@ namespace Swift {
 			JID to_;
 			std::string name_;
 			std::string description_;
-			std::vector<SecurityLabel> labels_;
+			std::vector<Item> items_;
 	};
 }
 
diff --git a/Swiften/Parser/PayloadParsers/SecurityLabelParser.cpp b/Swiften/Parser/PayloadParsers/SecurityLabelParser.cpp
index bf134d7..b769a47 100644
--- a/Swiften/Parser/PayloadParsers/SecurityLabelParser.cpp
+++ b/Swiften/Parser/PayloadParsers/SecurityLabelParser.cpp
@@ -62,4 +62,8 @@ void SecurityLabelParser::handleCharacterData(const std::string& data) {
 	}
 }
 
+boost::shared_ptr<SecurityLabel> SecurityLabelParser::getLabelPayload() {
+	return getPayloadInternal();
+}
+
 }
diff --git a/Swiften/Parser/PayloadParsers/SecurityLabelParser.h b/Swiften/Parser/PayloadParsers/SecurityLabelParser.h
index bd80921..b54c3be 100644
--- a/Swiften/Parser/PayloadParsers/SecurityLabelParser.h
+++ b/Swiften/Parser/PayloadParsers/SecurityLabelParser.h
@@ -20,7 +20,7 @@ namespace Swift {
 			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes);
 			virtual void handleEndElement(const std::string& element, const std::string&);
 			virtual void handleCharacterData(const std::string& data);
-
+			boost::shared_ptr<SecurityLabel> getLabelPayload();
 		private:
 			enum Level { 
 				TopLevel = 0, 
diff --git a/Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParser.cpp b/Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParser.cpp
index 1f2a6bc..a08cd11 100644
--- a/Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParser.cpp
+++ b/Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParser.cpp
@@ -15,6 +15,7 @@ SecurityLabelsCatalogParser::SecurityLabelsCatalogParser() : level_(TopLevel), l
 }
 
 SecurityLabelsCatalogParser::~SecurityLabelsCatalogParser() {
+	//delete currentLabel_;
 	delete labelParserFactory_;
 }
 
@@ -25,6 +26,11 @@ void SecurityLabelsCatalogParser::handleStartElement(const std::string& element,
 		getPayloadInternal()->setName(attributes.getAttribute("name"));
 		getPayloadInternal()->setDescription(attributes.getAttribute("desc"));
 	}
+	else if (level_ == ItemLevel && element == "item" && ns == "urn:xmpp:sec-label:catalog:2") {
+		currentItem_ = boost::shared_ptr<SecurityLabelsCatalog::Item>(new SecurityLabelsCatalog::Item());
+		currentItem_->setSelector(attributes.getAttribute("selector"));
+		currentItem_->setIsDefault(attributes.getBoolAttribute("default", false));
+	}
 	else if (level_ == LabelLevel) {
 		assert(!labelParser_);
 		if (labelParserFactory_->canParse(element, ns, attributes)) {
@@ -42,13 +48,19 @@ void SecurityLabelsCatalogParser::handleEndElement(const std::string& element, c
 	if (labelParser_) {
 		labelParser_->handleEndElement(element, ns);
 	}
-	if (level_ == LabelLevel && labelParser_) {
-		SecurityLabel* label = dynamic_cast<SecurityLabel*>(labelParser_->getPayload().get());
-		assert(label);
-		getPayloadInternal()->addLabel(SecurityLabel(*label));
+	if (level_ == LabelLevel && labelParser_ && currentItem_) {
+		boost::shared_ptr<SecurityLabel> currentLabel = labelParser_->getLabelPayload();
+		assert(currentLabel);
+		currentItem_->setLabel(currentLabel);
 		delete labelParser_;
 		labelParser_ = 0;
 	}
+	else if (level_ == ItemLevel && element == "item" && ns == "urn:xmpp:sec-label:catalog:2") {
+		if (currentItem_) {
+			getPayloadInternal()->addItem(SecurityLabelsCatalog::Item(*currentItem_));
+			currentItem_.reset();
+		}
+	}
 	--level_;
 }
 
diff --git a/Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParser.h b/Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParser.h
index 2222117..ca422d1 100644
--- a/Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParser.h
+++ b/Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParser.h
@@ -27,11 +27,13 @@ namespace Swift {
 			enum Level { 
 				TopLevel = 0, 
 				PayloadLevel = 1,
-				LabelLevel = 2
+				ItemLevel = 2,
+				LabelLevel = 3
 			};
 			int level_;
 			SecurityLabelParserFactory* labelParserFactory_;
 			SecurityLabelParser* labelParser_;
+			boost::shared_ptr<SecurityLabelsCatalog::Item> currentItem_;
 	};
 }
 
diff --git a/Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParserFactory.h b/Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParserFactory.h
index bb1da3a..a148d81 100644
--- a/Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParserFactory.h
+++ b/Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParserFactory.h
@@ -13,7 +13,7 @@
 namespace Swift {
 	class SecurityLabelsCatalogParserFactory : public GenericPayloadParserFactory<SecurityLabelsCatalogParser> {
 		public:
-			SecurityLabelsCatalogParserFactory() : GenericPayloadParserFactory<SecurityLabelsCatalogParser>("catalog", "urn:xmpp:sec-label:catalog:0") {}
+			SecurityLabelsCatalogParserFactory() : GenericPayloadParserFactory<SecurityLabelsCatalogParser>("catalog", "urn:xmpp:sec-label:catalog:2") {}
 	};
 }
 
diff --git a/Swiften/Parser/PayloadParsers/UnitTest/SecurityLabelsCatalogParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/SecurityLabelsCatalogParserTest.cpp
index 9925e34..e1e8594 100644
--- a/Swiften/Parser/PayloadParsers/UnitTest/SecurityLabelsCatalogParserTest.cpp
+++ b/Swiften/Parser/PayloadParsers/UnitTest/SecurityLabelsCatalogParserTest.cpp
@@ -25,26 +25,38 @@ class SecurityLabelsCatalogParserTest : public CppUnit::TestFixture
 			PayloadsParserTester parser;
 
 			CPPUNIT_ASSERT(parser.parse(
-				"<catalog desc=\"an example set of labels\" name=\"Default\" to=\"example.com\" xmlns=\"urn:xmpp:sec-label:catalog:0\">"
+				"<catalog desc=\"an example set of labels\" name=\"Default\" to=\"example.com\" xmlns=\"urn:xmpp:sec-label:catalog:2\">"
+				 "<item selector='Classified|SECRET'>"
 					"<securitylabel xmlns=\"urn:xmpp:sec-label:0\">"
 						"<displaymarking bgcolor=\"red\" fgcolor=\"black\">SECRET</displaymarking>"
 						"<label><esssecuritylabel xmlns=\"urn:xmpp:sec-label:ess:0\">MQYCAQQGASk=</esssecuritylabel></label>"
 					"</securitylabel>"
+				 "</item>"
+				 "<item selector='Classified|CONFIDENTIAL' default='true'>"
 					"<securitylabel xmlns=\"urn:xmpp:sec-label:0\">"
 						"<displaymarking bgcolor=\"navy\" fgcolor=\"black\">CONFIDENTIAL</displaymarking>"
 						"<label><esssecuritylabel xmlns=\"urn:xmpp:sec-label:ess:0\">MQMGASk=</esssecuritylabel></label>"
 					"</securitylabel>"
+				 "</item>"
+				 "<item selector='Unclassified|UNCLASSIFIED'/>"
 				"</catalog>"));
 
 			SecurityLabelsCatalog* payload = dynamic_cast<SecurityLabelsCatalog*>(parser.getPayload().get());
 			CPPUNIT_ASSERT_EQUAL(std::string("Default"), payload->getName());
 			CPPUNIT_ASSERT_EQUAL(std::string("an example set of labels"), payload->getDescription());
 			CPPUNIT_ASSERT_EQUAL(JID("example.com"), payload->getTo());
-			CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(payload->getLabels().size()));
-			CPPUNIT_ASSERT_EQUAL(std::string("SECRET"), payload->getLabels()[0].getDisplayMarking());
-			CPPUNIT_ASSERT_EQUAL(std::string("<esssecuritylabel xmlns=\"urn:xmpp:sec-label:ess:0\">MQYCAQQGASk=</esssecuritylabel>"), payload->getLabels()[0].getLabel());
-			CPPUNIT_ASSERT_EQUAL(std::string("CONFIDENTIAL"), payload->getLabels()[1].getDisplayMarking());
-			CPPUNIT_ASSERT_EQUAL(std::string("<esssecuritylabel xmlns=\"urn:xmpp:sec-label:ess:0\">MQMGASk=</esssecuritylabel>"), payload->getLabels()[1].getLabel());
+			CPPUNIT_ASSERT_EQUAL(3, static_cast<int>(payload->getItems().size()));
+			CPPUNIT_ASSERT_EQUAL(std::string("SECRET"), payload->getItems()[0].getLabel()->getDisplayMarking());
+			CPPUNIT_ASSERT_EQUAL(std::string("<esssecuritylabel xmlns=\"urn:xmpp:sec-label:ess:0\">MQYCAQQGASk=</esssecuritylabel>"), payload->getItems()[0].getLabel()->getLabel());
+			CPPUNIT_ASSERT_EQUAL(false, payload->getItems()[0].getIsDefault());
+			CPPUNIT_ASSERT_EQUAL(std::string("Classified|SECRET"), payload->getItems()[0].getSelector());
+			CPPUNIT_ASSERT_EQUAL(std::string("CONFIDENTIAL"), payload->getItems()[1].getLabel()->getDisplayMarking());
+			CPPUNIT_ASSERT_EQUAL(std::string("<esssecuritylabel xmlns=\"urn:xmpp:sec-label:ess:0\">MQMGASk=</esssecuritylabel>"), payload->getItems()[1].getLabel()->getLabel());
+			CPPUNIT_ASSERT_EQUAL(true, payload->getItems()[1].getIsDefault());
+			CPPUNIT_ASSERT_EQUAL(std::string("Classified|CONFIDENTIAL"), payload->getItems()[1].getSelector());
+			CPPUNIT_ASSERT_EQUAL(false, payload->getItems()[2].getIsDefault());
+			CPPUNIT_ASSERT_EQUAL(std::string("Unclassified|UNCLASSIFIED"), payload->getItems()[2].getSelector());
+			CPPUNIT_ASSERT(!payload->getItems()[2].getLabel());
 		}
 };
 
diff --git a/Swiften/Serializer/PayloadSerializers/SecurityLabelsCatalogSerializer.cpp b/Swiften/Serializer/PayloadSerializers/SecurityLabelsCatalogSerializer.cpp
index 5e4d8e4..7424c98 100644
--- a/Swiften/Serializer/PayloadSerializers/SecurityLabelsCatalogSerializer.cpp
+++ b/Swiften/Serializer/PayloadSerializers/SecurityLabelsCatalogSerializer.cpp
@@ -16,7 +16,7 @@ SecurityLabelsCatalogSerializer::SecurityLabelsCatalogSerializer() : GenericPayl
 }
 
 std::string SecurityLabelsCatalogSerializer::serializePayload(boost::shared_ptr<SecurityLabelsCatalog> catalog)  const {
-	XMLElement element("catalog", "urn:xmpp:sec-label:catalog:0");
+	XMLElement element("catalog", "urn:xmpp:sec-label:catalog:2");
 	if (!catalog->getName().empty()) {
 		element.setAttribute("name", catalog->getName());
 	}
@@ -26,9 +26,17 @@ std::string SecurityLabelsCatalogSerializer::serializePayload(boost::shared_ptr<
 	if (!catalog->getDescription().empty()) {
 		element.setAttribute("desc", catalog->getDescription());
 	}
-	foreach (const SecurityLabel& label, catalog->getLabels()) {
-		std::string serializedLabel = SecurityLabelSerializer().serialize(boost::shared_ptr<SecurityLabel>(new SecurityLabel(label)));
-		element.addNode(boost::shared_ptr<XMLRawTextNode>(new XMLRawTextNode(serializedLabel)));
+	foreach (const SecurityLabelsCatalog::Item& item, catalog->getItems()) {
+		boost::shared_ptr<XMLElement> itemElement(new XMLElement("item"));
+		itemElement->setAttribute("selector", item.getSelector());
+		if (item.getIsDefault()) {
+			itemElement->setAttribute("default", "true");
+		}
+		if (item.getLabel()) {
+			std::string serializedLabel = SecurityLabelSerializer().serialize(item.getLabel());
+			itemElement->addNode(boost::shared_ptr<XMLRawTextNode>(new XMLRawTextNode(serializedLabel)));
+		}
+		element.addNode(itemElement);
 	}
 	return element.serialize();
 }
diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/SecurityLabelsCatalogSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/SecurityLabelsCatalogSerializerTest.cpp
index 928f209..a7bf1b9 100644
--- a/Swiften/Serializer/PayloadSerializers/UnitTest/SecurityLabelsCatalogSerializerTest.cpp
+++ b/Swiften/Serializer/PayloadSerializers/UnitTest/SecurityLabelsCatalogSerializerTest.cpp
@@ -27,30 +27,47 @@ class SecurityLabelsCatalogSerializerTest : public CppUnit::TestFixture
 			catalog->setName("Default");
 			catalog->setDescription("an example set of labels");
 
-			SecurityLabel securityLabel1;
-			securityLabel1.setDisplayMarking("SECRET");
-			securityLabel1.setForegroundColor("black");
-			securityLabel1.setBackgroundColor("red");
-			securityLabel1.setLabel("<esssecuritylabel xmlns=\"urn:xmpp:sec-label:ess:0\">MQYCAQQGASk=</esssecuritylabel>");
-			catalog->addLabel(securityLabel1);
-
-			SecurityLabel securityLabel2;
-			securityLabel2.setDisplayMarking("CONFIDENTIAL");
-			securityLabel2.setForegroundColor("black");
-			securityLabel2.setBackgroundColor("navy");
-			securityLabel2.setLabel("<esssecuritylabel xmlns=\"urn:xmpp:sec-label:ess:0\">MQMGASk=</esssecuritylabel>");
-			catalog->addLabel(securityLabel2);
+			SecurityLabelsCatalog::Item item1;
+			boost::shared_ptr<SecurityLabel> securityLabel1(new SecurityLabel());
+			item1.setLabel(securityLabel1);
+			securityLabel1->setDisplayMarking("SECRET");
+			securityLabel1->setForegroundColor("black");
+			securityLabel1->setBackgroundColor("red");
+			item1.setIsDefault(false);
+			item1.setSelector("Classified|SECRET");
+			securityLabel1->setLabel("<esssecuritylabel xmlns=\"urn:xmpp:sec-label:ess:0\">MQYCAQQGASk=</esssecuritylabel>");
+			catalog->addItem(item1);
+
+			SecurityLabelsCatalog::Item item2;
+			boost::shared_ptr<SecurityLabel> securityLabel2(new SecurityLabel());
+			item2.setLabel(securityLabel2);
+			securityLabel2->setDisplayMarking("CONFIDENTIAL");
+			securityLabel2->setForegroundColor("black");
+			securityLabel2->setBackgroundColor("navy");
+			item2.setIsDefault(true);
+			item2.setSelector("Classified|CONFIDENTIAL");
+			securityLabel2->setLabel("<esssecuritylabel xmlns=\"urn:xmpp:sec-label:ess:0\">MQMGASk=</esssecuritylabel>");
+			catalog->addItem(item2);
+
+			SecurityLabelsCatalog::Item item3;
+			item3.setSelector("Unclassified|UNCLASSIFIED");
+			catalog->addItem(item3);
 
 			CPPUNIT_ASSERT_EQUAL(std::string(
-				"<catalog desc=\"an example set of labels\" name=\"Default\" to=\"example.com\" xmlns=\"urn:xmpp:sec-label:catalog:0\">"
+				"<catalog desc=\"an example set of labels\" name=\"Default\" to=\"example.com\" xmlns=\"urn:xmpp:sec-label:catalog:2\">"
+				 "<item selector=\"Classified|SECRET\">"
 					"<securitylabel xmlns=\"urn:xmpp:sec-label:0\">"
 						"<displaymarking bgcolor=\"red\" fgcolor=\"black\">SECRET</displaymarking>"
 						"<label><esssecuritylabel xmlns=\"urn:xmpp:sec-label:ess:0\">MQYCAQQGASk=</esssecuritylabel></label>"
 					"</securitylabel>"
+				 "</item>"
+				 "<item default=\"true\" selector=\"Classified|CONFIDENTIAL\">"
 					"<securitylabel xmlns=\"urn:xmpp:sec-label:0\">"
 						"<displaymarking bgcolor=\"navy\" fgcolor=\"black\">CONFIDENTIAL</displaymarking>"
 						"<label><esssecuritylabel xmlns=\"urn:xmpp:sec-label:ess:0\">MQMGASk=</esssecuritylabel></label>"
 					"</securitylabel>"
+				 "</item>"
+				 "<item selector=\"Unclassified|UNCLASSIFIED\"/>"
 				"</catalog>"), testling.serialize(catalog));
 		}
 };
-- 
cgit v0.10.2-6-g49f6