From 85a144fe80d0fe89b5fed852013b6986b44978d4 Mon Sep 17 00:00:00 2001
From: Peter Burgess <pete.burgess@isode.com>
Date: Fri, 19 Jan 2018 14:01:53 +0000
Subject: Request and display security markings for MUC chat windows

Disco#info requested and handled by MUCController on rejoin().
UI display of disco#info implemented for QtChatWindow.

Test-Information:
Tests written for new MUCController features, and all tests passed.
Swift runs with changes and security markings show as and when
expected in local isode MUC windows.

Change-Id: Ibef4a31f6f8c4cff5f518a66106266a7f961d103

diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp
index ff8efa2..9e12a66 100644
--- a/Swift/Controllers/Chat/MUCController.cpp
+++ b/Swift/Controllers/Chat/MUCController.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2017 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
  * All rights reserved.
  * See the COPYING file for more information.
  */
@@ -23,6 +23,7 @@
 #include <Swiften/Client/ClientBlockListManager.h>
 #include <Swiften/Client/StanzaChannel.h>
 #include <Swiften/Disco/EntityCapsProvider.h>
+#include <Swiften/Disco/GetDiscoInfoRequest.h>
 #include <Swiften/Elements/Delay.h>
 #include <Swiften/Elements/Thread.h>
 #include <Swiften/MUC/MUC.h>
@@ -273,6 +274,9 @@ void MUCController::rejoin() {
             lastActivity_ = historyController_->getLastTimeStampFromMUC(selfJID_, toJID_);
         }
 #endif
+
+        requestSecurityMarking();
+
         if (lastActivity_ == boost::posix_time::not_a_date_time) {
             muc_->joinAs(nick_);
         }
@@ -1243,4 +1247,53 @@ void MUCController::setChatWindowTitle(const std::string& title) {
     chatWindow_->setName(chatWindowTitle_);
 }
 
+void MUCController::requestSecurityMarking() {
+    auto discoInfoRequest = GetDiscoInfoRequest::create(muc_->getJID(), iqRouter_);
+    discoInfoRequest->onResponse.connect(
+        [this](std::shared_ptr<DiscoInfo> discoInfoRef, ErrorPayload::ref errorPayloadRef) {
+            if (!discoInfoRef || errorPayloadRef) {
+                return;
+            }
+            const std::vector<Form::ref>& extensionsList = discoInfoRef->getExtensions();
+            if (extensionsList.empty()) {
+                return;
+            }
+            // Get the correct form if it exists
+            Form::ref roomInfoForm;
+            for (const auto& form : extensionsList) {
+                if (form->getFormType() == "http://jabber.org/protocol/muc#roominfo") {
+                    roomInfoForm = form;
+                    break;
+                }
+            }
+            if (!roomInfoForm) {
+                return;
+            }
+            // It exists, now examine the security marking data
+            auto marking = roomInfoForm->getField("x-isode#roominfo_marking");
+            if (!marking) {
+                return;
+            }
+            // Now we know the marking is valid
+            auto markingValue = marking->getTextSingleValue();
+            if (markingValue == "") {
+                chatWindow_->removeChatSecurityMarking();
+                return;
+            }
+            auto markingForegroundColor = roomInfoForm->getField("x-isode#roominfo_marking_fg_color");
+            auto markingBackgroundColor = roomInfoForm->getField("x-isode#roominfo_marking_bg_color");
+            std::string markingForegroundColorValue = "Black";
+            std::string markingBackgroundColorValue = "White";
+            if (markingForegroundColor) {
+                markingForegroundColorValue = markingForegroundColor->getTextSingleValue();
+            }
+            if (markingBackgroundColor) {
+                markingBackgroundColorValue = markingBackgroundColor->getTextSingleValue();
+            }
+            chatWindow_->setChatSecurityMarking(markingValue, markingForegroundColorValue, markingBackgroundColorValue);
+        }
+    );
+    discoInfoRequest->send();
+}
+
 }
diff --git a/Swift/Controllers/Chat/MUCController.h b/Swift/Controllers/Chat/MUCController.h
index 4b39f54..949f530 100644
--- a/Swift/Controllers/Chat/MUCController.h
+++ b/Swift/Controllers/Chat/MUCController.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2017 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
  * All rights reserved.
  * See the COPYING file for more information.
  */
@@ -148,6 +148,8 @@ namespace Swift {
             void displaySubjectIfChanged(const std::string& sucject);
             void addChatSystemMessage();
 
+            void requestSecurityMarking();
+
         private:
             MUC::ref muc_;
             std::string nick_;
diff --git a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
index 8f6c3a8..e06a3c7 100644
--- a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
+++ b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
@@ -776,7 +776,7 @@ public:
         // send message to participantA
         auto messageBody = std::string("message body to send");
         window->onSendMessageRequest(messageBody, false);
-        auto sendMessageStanza = stanzaChannel_->getStanzaAtIndex<Message>(2);
+        auto sendMessageStanza = stanzaChannel_->getStanzaAtIndex<Message>(3);
         CPPUNIT_ASSERT_EQUAL(messageBody, *sendMessageStanza->getBody());
 
         // receive reply with error
@@ -1537,7 +1537,11 @@ public:
         uiEventStream_->send(std::make_shared<CreateImpromptuMUCUIEvent>(jids, mucJID, ""));
         CPPUNIT_ASSERT_EQUAL(std::string("bar@test.com, foo@test.com"), manager_->getRecentChats()[0].getTitle());
 
-        auto mucJoinPresence = std::dynamic_pointer_cast<Presence>(stanzaChannel_->sentStanzas[2]);
+        // Check the MUC security marking request
+        auto mucInfoRequest = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[2]);
+        CPPUNIT_ASSERT(mucInfoRequest);
+
+        auto mucJoinPresence = std::dynamic_pointer_cast<Presence>(stanzaChannel_->sentStanzas[3]);
         CPPUNIT_ASSERT(mucJoinPresence);
 
         // MUC presence reply
diff --git a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
index 1f69f4f..06486d3 100644
--- a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
+++ b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
@@ -68,6 +68,14 @@ class MUCControllerTest : public CppUnit::TestFixture {
 
     CPPUNIT_TEST(testNonImpromptuMUCWindowTitle);
 
+    CPPUNIT_TEST(testSecurityMarkingRequestCompleteMarking);
+    CPPUNIT_TEST(testSecurityMarkingRequestCompleteMarkingWithExtraForm);
+    CPPUNIT_TEST(testSecurityMarkingRequestEmptyMarking);
+    CPPUNIT_TEST(testSecurityMarkingRequestWithMarkingNoFormType);
+    CPPUNIT_TEST(testSecurityMarkingRequestNoMarking);
+    CPPUNIT_TEST(testSecurityMarkingRequestNoForm);
+    CPPUNIT_TEST(testSecurityMarkingRequestError);
+
     CPPUNIT_TEST_SUITE_END();
 
 public:
@@ -593,6 +601,168 @@ public:
         CPPUNIT_ASSERT_EQUAL(muc_->getJID().getNode(), window_->name_);
     }
 
+    void testSecurityMarkingRequestCompleteMarking() {
+        auto formTypeField = std::make_shared<FormField>(FormField::Type::HiddenType, "http://jabber.org/protocol/muc#roominfo");
+        auto markingField = std::make_shared<FormField>(FormField::Type::TextSingleType, "Test | Highest Possible Security");
+        auto markingForegroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, "Black");
+        auto markingBackgroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, "Red");
+        formTypeField->setName("FORM_TYPE");
+        markingField->setName("x-isode#roominfo_marking");
+        markingForegroundColorField->setName("x-isode#roominfo_marking_fg_color");
+        markingBackgroundColorField->setName("x-isode#roominfo_marking_bg_color");
+
+        auto form = std::make_shared<Form>(Form::Type::ResultType);
+        form->addField(formTypeField);
+        form->addField(markingField);
+        form->addField(markingForegroundColorField);
+        form->addField(markingBackgroundColorField);
+
+        auto discoInfoRef = std::make_shared<DiscoInfo>();
+        discoInfoRef->addExtension(form);
+
+        auto infoResponse = IQ::createResult(self_, mucJID_, "test-id", discoInfoRef);
+        iqChannel_->onIQReceived(infoResponse);
+        CPPUNIT_ASSERT_EQUAL(std::string("Test | Highest Possible Security"), window_->markingValue_);
+        CPPUNIT_ASSERT_EQUAL(std::string("Black"), window_->markingForegroundColorValue_);
+        CPPUNIT_ASSERT_EQUAL(std::string("Red"), window_->markingBackgroundColorValue_);
+    }
+
+    void testSecurityMarkingRequestCompleteMarkingWithExtraForm() {
+        auto formTypeField = std::make_shared<FormField>(FormField::Type::HiddenType, "http://jabber.org/protocol/muc#roominfo");
+        auto markingField = std::make_shared<FormField>(FormField::Type::TextSingleType, "Test | Highest Possible Security");
+        auto markingForegroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, "Black");
+        auto markingBackgroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, "Red");
+        formTypeField->setName("FORM_TYPE");
+        markingField->setName("x-isode#roominfo_marking");
+        markingForegroundColorField->setName("x-isode#roominfo_marking_fg_color");
+        markingBackgroundColorField->setName("x-isode#roominfo_marking_bg_color");
+
+        auto extraForm = std::make_shared<Form>(Form::Type::ResultType);
+        auto form = std::make_shared<Form>(Form::Type::ResultType);
+        form->addField(formTypeField);
+        form->addField(markingField);
+        form->addField(markingForegroundColorField);
+        form->addField(markingBackgroundColorField);
+
+        auto discoInfoRef = std::make_shared<DiscoInfo>();
+        discoInfoRef->addExtension(extraForm);
+        discoInfoRef->addExtension(form);
+
+        auto infoResponse = IQ::createResult(self_, mucJID_, "test-id", discoInfoRef);
+        iqChannel_->onIQReceived(infoResponse);
+        CPPUNIT_ASSERT_EQUAL(std::string("Test | Highest Possible Security"), window_->markingValue_);
+        CPPUNIT_ASSERT_EQUAL(std::string("Black"), window_->markingForegroundColorValue_);
+        CPPUNIT_ASSERT_EQUAL(std::string("Red"), window_->markingBackgroundColorValue_);
+    }
+
+    void testSecurityMarkingRequestNoColorsInMarking() {
+        auto formTypeField = std::make_shared<FormField>(FormField::Type::HiddenType, "http://jabber.org/protocol/muc#roominfo");
+        auto markingField = std::make_shared<FormField>(FormField::Type::TextSingleType, "Test | Highest Possible Security");
+        auto markingForegroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, "");
+        auto markingBackgroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, "");
+        formTypeField->setName("FORM_TYPE");
+        markingField->setName("x-isode#roominfo_marking");
+        markingForegroundColorField->setName("x-isode#roominfo_marking_fg_color");
+        markingBackgroundColorField->setName("x-isode#roominfo_marking_bg_color");
+
+        auto form = std::make_shared<Form>(Form::Type::ResultType);
+        form->addField(formTypeField);
+        form->addField(markingField);
+        form->addField(markingForegroundColorField);
+        form->addField(markingBackgroundColorField);
+
+        auto discoInfoRef = std::make_shared<DiscoInfo>();
+        discoInfoRef->addExtension(form);
+
+        auto infoResponse = IQ::createResult(self_, mucJID_, "test-id", discoInfoRef);
+        iqChannel_->onIQReceived(infoResponse);
+        CPPUNIT_ASSERT_EQUAL(std::string("Test | Highest Possible Security"), window_->markingValue_);
+        CPPUNIT_ASSERT_EQUAL(std::string("Black"), window_->markingForegroundColorValue_);
+        CPPUNIT_ASSERT_EQUAL(std::string("White"), window_->markingBackgroundColorValue_);
+    }
+
+    void testSecurityMarkingRequestEmptyMarking() {
+        auto formTypeField = std::make_shared<FormField>(FormField::Type::HiddenType, "http://jabber.org/protocol/muc#roominfo");
+        auto markingField = std::make_shared<FormField>(FormField::Type::TextSingleType, "");
+        auto markingForegroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, "");
+        auto markingBackgroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, "");
+        formTypeField->setName("FORM_TYPE");
+        markingField->setName("x-isode#roominfo_marking");
+        markingForegroundColorField->setName("x-isode#roominfo_marking_fg_color");
+        markingBackgroundColorField->setName("x-isode#roominfo_marking_bg_color");
+
+        auto form = std::make_shared<Form>(Form::Type::ResultType);
+        form->addField(formTypeField);
+        form->addField(markingField);
+        form->addField(markingForegroundColorField);
+        form->addField(markingBackgroundColorField);
+
+        auto discoInfoRef = std::make_shared<DiscoInfo>();
+        discoInfoRef->addExtension(form);
+
+        auto infoResponse = IQ::createResult(self_, mucJID_, "test-id", discoInfoRef);
+        iqChannel_->onIQReceived(infoResponse);
+        CPPUNIT_ASSERT_EQUAL(std::string(""), window_->markingValue_);
+        CPPUNIT_ASSERT_EQUAL(std::string(""), window_->markingForegroundColorValue_);
+        CPPUNIT_ASSERT_EQUAL(std::string(""), window_->markingBackgroundColorValue_);
+    }
+
+    void testSecurityMarkingRequestWithMarkingNoFormType() {
+        auto markingField = std::make_shared<FormField>(FormField::Type::TextSingleType, "Test | Highest Possible Security");
+        auto markingForegroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, "Black");
+        auto markingBackgroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, "Red");
+        markingField->setName("x-isode#roominfo_marking");
+        markingForegroundColorField->setName("x-isode#roominfo_marking_fg_color");
+        markingBackgroundColorField->setName("x-isode#roominfo_marking_bg_color");
+
+        auto form = std::make_shared<Form>(Form::Type::ResultType);
+        form->addField(markingField);
+        form->addField(markingForegroundColorField);
+        form->addField(markingBackgroundColorField);
+
+        auto discoInfoRef = std::make_shared<DiscoInfo>();
+        discoInfoRef->addExtension(form);
+
+        auto infoResponse = IQ::createResult(self_, mucJID_, "test-id", discoInfoRef);
+        iqChannel_->onIQReceived(infoResponse);
+        CPPUNIT_ASSERT_EQUAL(std::string(""), window_->markingValue_);
+        CPPUNIT_ASSERT_EQUAL(std::string(""), window_->markingForegroundColorValue_);
+        CPPUNIT_ASSERT_EQUAL(std::string(""), window_->markingBackgroundColorValue_);
+    }
+
+    void testSecurityMarkingRequestNoMarking() {
+        auto form = std::make_shared<Form>(Form::Type::ResultType);
+
+        auto discoInfoRef = std::make_shared<DiscoInfo>();
+        discoInfoRef->addExtension(form);
+
+        auto infoResponse = IQ::createResult(self_, mucJID_, "test-id", discoInfoRef);
+        iqChannel_->onIQReceived(infoResponse);
+        CPPUNIT_ASSERT_EQUAL(std::string(""), window_->markingValue_);
+        CPPUNIT_ASSERT_EQUAL(std::string(""), window_->markingForegroundColorValue_);
+        CPPUNIT_ASSERT_EQUAL(std::string(""), window_->markingBackgroundColorValue_);
+    }
+
+    void testSecurityMarkingRequestNoForm() {
+        auto discoInfoRef = std::make_shared<DiscoInfo>();
+
+        auto infoResponse = IQ::createResult( self_, mucJID_, "test-id", discoInfoRef);
+        iqChannel_->onIQReceived(infoResponse);
+        CPPUNIT_ASSERT_EQUAL(std::string(""), window_->markingValue_);
+        CPPUNIT_ASSERT_EQUAL(std::string(""), window_->markingForegroundColorValue_);
+        CPPUNIT_ASSERT_EQUAL(std::string(""), window_->markingBackgroundColorValue_);
+    }
+
+    void testSecurityMarkingRequestError() {
+        auto errorPayload = std::make_shared<ErrorPayload>(ErrorPayload::Condition::NotAuthorized, ErrorPayload::Type::Auth);
+
+        auto infoResponse = IQ::createResult( self_, mucJID_, "test-id", errorPayload);
+        iqChannel_->onIQReceived(infoResponse);
+        CPPUNIT_ASSERT_EQUAL(std::string(""), window_->markingValue_);
+        CPPUNIT_ASSERT_EQUAL(std::string(""), window_->markingForegroundColorValue_);
+        CPPUNIT_ASSERT_EQUAL(std::string(""), window_->markingBackgroundColorValue_);
+    }
+
 private:
     JID self_;
     JID mucJID_;
diff --git a/Swift/Controllers/UIInterfaces/ChatWindow.h b/Swift/Controllers/UIInterfaces/ChatWindow.h
index 8273802..13cbb7d 100644
--- a/Swift/Controllers/UIInterfaces/ChatWindow.h
+++ b/Swift/Controllers/UIInterfaces/ChatWindow.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2017 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
  * All rights reserved.
  * See the COPYING file for more information.
  */
@@ -33,6 +33,8 @@ namespace Swift {
     class ContactRosterItem;
     class FileTransferController;
     class UserSearchWindow;
+    class DiscoInfo;
+    class ErrorPayload;
 
 
     class ChatWindow {
@@ -219,6 +221,9 @@ namespace Swift {
             virtual void showBookmarkWindow(const MUCBookmark& bookmark) = 0;
             virtual void setBookmarkState(RoomBookmarkState bookmarkState) = 0;
 
+            virtual void setChatSecurityMarking(const std::string& markingValue, const std::string& markingForegroundColorValue, const std::string& markingBackgroundColorValue) = 0;
+            virtual void removeChatSecurityMarking() = 0;
+
             /**
              * A handle that uniquely identities an alert message.
              */
@@ -282,4 +287,3 @@ namespace Swift {
             boost::signals2::signal<void ()> onUnblockUserRequest;
     };
 }
-
diff --git a/Swift/Controllers/UnitTest/MockChatWindow.h b/Swift/Controllers/UnitTest/MockChatWindow.h
index 7682781..56f118d 100644
--- a/Swift/Controllers/UnitTest/MockChatWindow.h
+++ b/Swift/Controllers/UnitTest/MockChatWindow.h
@@ -133,6 +133,14 @@ namespace Swift {
                 lastAddedMessageSenderIsSelf_ = lastAddedActionSenderIsSelf_ = false;
             }
 
+            void setChatSecurityMarking(const std::string& markingValue, const std::string& markingForegroundColorValue, const std::string& markingBackgroundColorValue) {
+                markingValue_ = markingValue;
+                markingForegroundColorValue_ = markingForegroundColorValue;
+                markingBackgroundColorValue_ = markingBackgroundColorValue;
+            }
+
+            void removeChatSecurityMarking() {}
+
             std::string name_;
             ChatMessage lastAddedMessage_;
             std::string lastAddedMessageSenderName_;
@@ -154,6 +162,9 @@ namespace Swift {
             Roster* roster_ = nullptr;
             std::vector<std::pair<std::string, ReceiptState>> receiptChanges_;
             boost::optional<MUCType> mucType_;
+            std::string markingValue_;
+            std::string markingForegroundColorValue_;
+            std::string markingBackgroundColorValue_;
     };
 }
 
diff --git a/Swift/QtUI/QtChatWindow.cpp b/Swift/QtUI/QtChatWindow.cpp
index e750caa..17e3328 100644
--- a/Swift/QtUI/QtChatWindow.cpp
+++ b/Swift/QtUI/QtChatWindow.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2017 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
  * All rights reserved.
  * See the COPYING file for more information.
  */
@@ -984,4 +984,46 @@ void QtChatWindow::setBookmarkState(RoomBookmarkState bookmarkState) {
     roomBookmarkState_ = bookmarkState;
 }
 
+void QtChatWindow::setChatSecurityMarking(const std::string& markingValue, const std::string& markingForegroundColorValue, const std::string& markingBackgroundColorValue) {
+    auto layout = static_cast<QBoxLayout*>(this->layout());
+
+    if (securityMarkingLayout_) {
+        layout->removeItem(securityMarkingLayout_);
+        securityMarkingLayout_->removeWidget(securityMarkingDisplay_);
+        delete securityMarkingLayout_;
+    }
+    delete securityMarkingDisplay_;
+
+    securityMarkingLayout_ = new QHBoxLayout();
+    securityMarkingDisplay_ = new QLabel(P2QSTRING(markingValue));
+
+    securityMarkingLayout_->addWidget(securityMarkingDisplay_);
+    layout->insertLayout(1, securityMarkingLayout_);
+
+    auto palette = securityMarkingDisplay_->palette();
+    palette.setColor(securityMarkingDisplay_->foregroundRole(), P2QSTRING(markingForegroundColorValue));
+    palette.setColor(securityMarkingDisplay_->backgroundRole(), P2QSTRING(markingBackgroundColorValue));
+
+    securityMarkingDisplay_->setPalette(palette);
+    securityMarkingDisplay_->setContentsMargins(4,4,4,4);
+    securityMarkingDisplay_->setAutoFillBackground(true);
+    securityMarkingDisplay_->setAlignment(Qt::AlignCenter);
+}
+
+void QtChatWindow::removeChatSecurityMarking() {
+    if (!securityMarkingLayout_) {
+        return;
+    }
+
+    auto layout = static_cast<QBoxLayout*>(this->layout());
+
+    layout->removeItem(securityMarkingLayout_);
+    securityMarkingLayout_->removeWidget(securityMarkingDisplay_);
+
+    delete securityMarkingDisplay_;
+    delete securityMarkingLayout_;
+    securityMarkingDisplay_ = nullptr;
+    securityMarkingLayout_ = nullptr;
+}
+
 }
diff --git a/Swift/QtUI/QtChatWindow.h b/Swift/QtUI/QtChatWindow.h
index 361d7c6..4e10053 100644
--- a/Swift/QtUI/QtChatWindow.h
+++ b/Swift/QtUI/QtChatWindow.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2017 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
  * All rights reserved.
  * See the COPYING file for more information.
  */
@@ -194,6 +194,9 @@ namespace Swift {
 
             void resetDayChangeTimer();
 
+            void setChatSecurityMarking(const std::string& markingValue, const std::string& markingForegroundColorValue, const std::string& markingBackgroundColorValue);
+            void removeChatSecurityMarking();
+
         private:
             int unreadCount_;
             bool contactIsTyping_;
@@ -241,5 +244,7 @@ namespace Swift {
             QPointer<QtEmojisSelector> emojisGrid_;
             std::map<std::string, std::string> emoticonsMap_;
             QTimer* dayChangeTimer = nullptr;
+            QHBoxLayout* securityMarkingLayout_ = nullptr;
+            QLabel* securityMarkingDisplay_ = nullptr;
     };
 }
diff --git a/Swiften/Elements/Form.h b/Swiften/Elements/Form.h
index 899fb93..827e497 100644
--- a/Swiften/Elements/Form.h
+++ b/Swiften/Elements/Form.h
@@ -89,6 +89,9 @@ namespace Swift {
                 return instructions_;
             }
 
+            /** Returns the Form::Type enum (ie. ResultType, CancelType etc.).
+             * NOT to be confused with Form::getFormType().
+             */
             Type getType() const {
                 return type_;
             }
@@ -97,6 +100,9 @@ namespace Swift {
                 type_ = type;
             }
 
+            /** Returns the value of the field FORM_TYPE
+             * NOT to be confused with Form::getType().
+             */
             std::string getFormType() const;
             FormField::ref getField(const std::string& name) const;
             void addItem(const FormItem& item);
-- 
cgit v0.10.2-6-g49f6