summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Swift/Controllers/Chat/MUCController.cpp18
-rw-r--r--Swift/Controllers/Chat/MUCController.h5
-rw-r--r--Swift/Controllers/UIInterfaces/ChatWindow.h9
-rw-r--r--Swift/Controllers/UnitTest/MockChatWindow.h1
-rw-r--r--Swift/QtUI/QtChatWindow.cpp16
-rw-r--r--Swift/QtUI/QtChatWindow.h8
-rw-r--r--Swift/QtUI/QtMainWindow.cpp4
-rw-r--r--Swift/QtUI/Roster/QtOccupantListWidget.cpp53
-rw-r--r--Swift/QtUI/Roster/QtOccupantListWidget.h7
-rw-r--r--Swift/QtUI/Roster/QtRosterWidget.cpp16
-rw-r--r--Swift/QtUI/Roster/QtRosterWidget.h5
-rw-r--r--Swift/QtUI/Roster/QtTreeWidget.cpp15
-rw-r--r--Swift/QtUI/Roster/QtTreeWidget.h4
-rw-r--r--Swiften/Elements/MUCAdminPayload.h35
-rw-r--r--Swiften/Elements/MUCItem.h21
-rw-r--r--Swiften/Elements/MUCUserPayload.h15
-rw-r--r--Swiften/MUC/MUC.cpp22
-rw-r--r--Swiften/MUC/MUC.h4
-rw-r--r--Swiften/Parser/GenericPayloadTreeParser.cpp8
-rw-r--r--Swiften/Parser/GenericPayloadTreeParser.h58
-rw-r--r--Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp2
-rw-r--r--Swiften/Parser/PayloadParsers/MUCAdminPayloadParser.cpp23
-rw-r--r--Swiften/Parser/PayloadParsers/MUCAdminPayloadParser.h20
-rw-r--r--Swiften/Parser/PayloadParsers/MUCItemParser.cpp82
-rw-r--r--Swiften/Parser/PayloadParsers/MUCItemParser.h20
-rw-r--r--Swiften/Parser/PayloadParsers/MUCUserPayloadParser.cpp87
-rw-r--r--Swiften/Parser/PayloadParsers/MUCUserPayloadParser.h19
-rw-r--r--Swiften/Parser/PayloadParsers/UnitTest/MUCAdminPayloadParserTest.cpp41
-rw-r--r--Swiften/Parser/SConscript4
-rw-r--r--Swiften/Parser/Tree/NullParserElement.h19
-rw-r--r--Swiften/Parser/Tree/ParserElement.cpp72
-rw-r--r--Swiften/Parser/Tree/ParserElement.h41
-rw-r--r--Swiften/Parser/UnitTest/GenericPayloadTreeParserTest.cpp58
-rw-r--r--Swiften/SConscript4
-rw-r--r--Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp2
-rw-r--r--Swiften/Serializer/PayloadSerializers/MUCAdminPayloadSerializer.cpp34
-rw-r--r--Swiften/Serializer/PayloadSerializers/MUCAdminPayloadSerializer.h22
-rw-r--r--Swiften/Serializer/PayloadSerializers/MUCItemSerializer.h69
-rw-r--r--Swiften/Serializer/PayloadSerializers/MUCUserPayloadSerializer.cpp39
-rw-r--r--Swiften/Serializer/PayloadSerializers/MUCUserPayloadSerializer.h2
-rw-r--r--Swiften/Serializer/PayloadSerializers/UnitTest/MUCAdminPayloadSerializerTest.cpp39
41 files changed, 824 insertions, 199 deletions
diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp
index aa0a1e7..19d7b4d 100644
--- a/Swift/Controllers/Chat/MUCController.cpp
+++ b/Swift/Controllers/Chat/MUCController.cpp
@@ -23,6 +23,7 @@
#include <Swift/Controllers/UIEvents/UIEventStream.h>
#include <Swift/Controllers/UIEvents/RequestChatUIEvent.h>
#include <Swift/Controllers/Roster/GroupRosterItem.h>
+#include <Swift/Controllers/Roster/ContactRosterItem.h>
#include <Swiften/Avatars/AvatarManager.h>
#include <Swiften/Elements/Delay.h>
#include <Swiften/MUC/MUC.h>
@@ -68,6 +69,8 @@ MUCController::MUCController (
chatWindow_->setTabComplete(completer_);
chatWindow_->setName(muc->getJID().getNode());
chatWindow_->onClosed.connect(boost::bind(&MUCController::handleWindowClosed, this));
+ chatWindow_->onOccupantSelectionChanged.connect(boost::bind(&MUCController::handleWindowOccupantSelectionChanged, this, _1));
+ chatWindow_->onOccupantActionSelected.connect(boost::bind(&MUCController::handleActionRequestedOnOccupant, this, _1, _2));
muc_->onJoinComplete.connect(boost::bind(&MUCController::handleJoinComplete, this, _1));
muc_->onJoinFailed.connect(boost::bind(&MUCController::handleJoinFailed, this, _1));
muc_->onOccupantJoined.connect(boost::bind(&MUCController::handleOccupantJoined, this, _1));
@@ -97,6 +100,21 @@ MUCController::~MUCController() {
delete completer_;
}
+void MUCController::handleWindowOccupantSelectionChanged(ContactRosterItem* item) {
+ std::vector<ChatWindow::OccupantAction> actions;
+ //FIXME
+ if (item) {
+ actions.push_back(ChatWindow::Kick);
+ }
+ chatWindow_->setAvailableOccupantActions(actions);
+}
+
+void MUCController::handleActionRequestedOnOccupant(ChatWindow::OccupantAction action, ContactRosterItem* item) {
+ switch (action) {
+ case ChatWindow::Kick: muc_->kickUser(item->getJID());break;
+ }
+}
+
void MUCController::handleBareJIDCapsChanged(const JID& /*jid*/) {
ChatWindow::Tristate support = ChatWindow::Yes;
bool any = false;
diff --git a/Swift/Controllers/Chat/MUCController.h b/Swift/Controllers/Chat/MUCController.h
index 3a79920..39e5fa4 100644
--- a/Swift/Controllers/Chat/MUCController.h
+++ b/Swift/Controllers/Chat/MUCController.h
@@ -19,11 +19,12 @@
#include <Swiften/JID/JID.h>
#include <Swiften/MUC/MUC.h>
#include <Swiften/Elements/MUCOccupant.h>
+#include <Swift/Controllers/Roster/RosterItem.h>
+#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
namespace Swift {
class StanzaChannel;
class IQRouter;
- class ChatWindow;
class ChatWindowFactory;
class Roster;
class AvatarManager;
@@ -64,6 +65,8 @@ namespace Swift {
private:
void clearPresenceQueue();
void addPresenceMessage(const std::string& message);
+ void handleWindowOccupantSelectionChanged(ContactRosterItem* item);
+ void handleActionRequestedOnOccupant(ChatWindow::OccupantAction, ContactRosterItem* item);
void handleWindowClosed();
void handleAvatarChanged(const JID& jid);
void handleOccupantJoined(const MUCOccupant& occupant);
diff --git a/Swift/Controllers/UIInterfaces/ChatWindow.h b/Swift/Controllers/UIInterfaces/ChatWindow.h
index e84116d..faef5c8 100644
--- a/Swift/Controllers/UIInterfaces/ChatWindow.h
+++ b/Swift/Controllers/UIInterfaces/ChatWindow.h
@@ -22,11 +22,14 @@ namespace Swift {
class TreeWidget;
class Roster;
class TabComplete;
+ class RosterItem;
+ class ContactRosterItem;
class ChatWindow {
public:
enum AckState {Pending, Received, Failed};
enum Tristate {Yes, No, Maybe};
+ enum OccupantAction {Kick};
ChatWindow() {}
virtual ~ChatWindow() {};
@@ -72,6 +75,10 @@ namespace Swift {
*/
virtual void cancelAlert() = 0;
+ /**
+ * Actions that can be performed on the selected occupant.
+ */
+ virtual void setAvailableOccupantActions(const std::vector<OccupantAction>& actions) = 0;
boost::signal<void ()> onClosed;
boost::signal<void ()> onAllMessagesRead;
boost::signal<void (const std::string&, bool isCorrection)> onSendMessageRequest;
@@ -79,6 +86,8 @@ namespace Swift {
boost::signal<void ()> onUserTyping;
boost::signal<void ()> onUserCancelsTyping;
boost::signal<void ()> onAlertButtonClicked;
+ boost::signal<void (ContactRosterItem*)> onOccupantSelectionChanged;
+ boost::signal<void (ChatWindow::OccupantAction, ContactRosterItem*)> onOccupantActionSelected;
};
}
#endif
diff --git a/Swift/Controllers/UnitTest/MockChatWindow.h b/Swift/Controllers/UnitTest/MockChatWindow.h
index 7d6828f..574248f 100644
--- a/Swift/Controllers/UnitTest/MockChatWindow.h
+++ b/Swift/Controllers/UnitTest/MockChatWindow.h
@@ -40,6 +40,7 @@ namespace Swift {
virtual void setAlert(const std::string& /*alertText*/, const std::string& /*buttonText*/) {};
virtual void cancelAlert() {};
virtual void setCorrectionEnabled(Tristate /*enabled*/) {}
+ void setAvailableOccupantActions(const std::vector<OccupantAction>& actions) {}
boost::signal<void ()> onClosed;
boost::signal<void ()> onAllMessagesRead;
diff --git a/Swift/QtUI/QtChatWindow.cpp b/Swift/QtUI/QtChatWindow.cpp
index a52d2de..a36bc32 100644
--- a/Swift/QtUI/QtChatWindow.cpp
+++ b/Swift/QtUI/QtChatWindow.cpp
@@ -7,7 +7,9 @@
#include "QtChatWindow.h"
#include "QtSwiftUtil.h"
#include "Swift/Controllers/Roster/Roster.h"
-#include "Roster/QtTreeWidget.h"
+#include "Swift/Controllers/Roster/RosterItem.h"
+#include "Swift/Controllers/Roster/ContactRosterItem.h"
+#include "Roster/QtOccupantListWidget.h"
#include "SwifTools/Linkify.h"
#include "QtChatView.h"
#include "MessageSnippet.h"
@@ -70,7 +72,7 @@ QtChatWindow::QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventSt
messageLog_ = new QtChatView(theme, this);
logRosterSplitter_->addWidget(messageLog_);
- treeWidget_ = new QtTreeWidget(eventStream_);
+ treeWidget_ = new QtOccupantListWidget(eventStream_, this);
treeWidget_->hide();
logRosterSplitter_->addWidget(treeWidget_);
logRosterSplitter_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
@@ -115,7 +117,8 @@ QtChatWindow::QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventSt
connect(messageLog_, SIGNAL(gotFocus()), input_, SLOT(setFocus()));
resize(400,300);
connect(messageLog_, SIGNAL(fontResized(int)), this, SIGNAL(fontResized(int)));
-
+ treeWidget_->onSomethingSelectedChanged.connect(boost::bind(&QtChatWindow::handleOccupantSelectionChanged, this, _1));
+ treeWidget_->onOccupantActionSelected.connect(boost::bind(boost::ref(onOccupantActionSelected), _1, _2));
}
@@ -123,6 +126,9 @@ QtChatWindow::~QtChatWindow() {
}
+void QtChatWindow::handleOccupantSelectionChanged(RosterItem* item) {
+ onOccupantSelectionChanged(dynamic_cast<ContactRosterItem*>(item));
+}
void QtChatWindow::handleFontResized(int fontSizeSteps) {
messageLog_->resizeFont(fontSizeSteps);
@@ -530,4 +536,8 @@ void QtChatWindow::replaceLastMessage(const std::string& message) {
messageLog_->replaceLastMessage(P2QSTRING(Linkify::linkify(message)));
}
+void QtChatWindow::setAvailableOccupantActions(const std::vector<OccupantAction>& actions) {
+ treeWidget_->setAvailableOccupantActions(actions);
+}
+
}
diff --git a/Swift/QtUI/QtChatWindow.h b/Swift/QtUI/QtChatWindow.h
index bc1045d..d38e9c6 100644
--- a/Swift/QtUI/QtChatWindow.h
+++ b/Swift/QtUI/QtChatWindow.h
@@ -23,8 +23,7 @@ class QPushButton;
namespace Swift {
class QtChatView;
- class QtTreeWidget;
- class QtTreeWidgetFactory;
+ class QtOccupantListWidget;
class QtChatTheme;
class TreeWidget;
class QtTextEdit;
@@ -60,6 +59,7 @@ namespace Swift {
void setAckState(const std::string& id, AckState state);
void flash();
QByteArray getSplitterState();
+ virtual void setAvailableOccupantActions(const std::vector<OccupantAction>& actions);
public slots:
void handleChangeSplitterState(QByteArray state);
@@ -88,13 +88,13 @@ namespace Swift {
void handleKeyPressEvent(QKeyEvent* event);
void handleSplitterMoved(int pos, int index);
void handleAlertButtonClicked();
-
private:
void updateTitleWithUnreadCount();
void tabComplete();
void beginCorrection();
void cancelCorrection();
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);
+ void handleOccupantSelectionChanged(RosterItem* item);
int unreadCount_;
bool contactIsTyping_;
@@ -105,7 +105,7 @@ namespace Swift {
QtChatTheme* theme_;
QtTextEdit* input_;
QComboBox* labelsWidget_;
- QtTreeWidget* treeWidget_;
+ QtOccupantListWidget* treeWidget_;
QLabel* correctingLabel_;
QLabel* alertLabel_;
QWidget* alertWidget_;
diff --git a/Swift/QtUI/QtMainWindow.cpp b/Swift/QtUI/QtMainWindow.cpp
index 7c84773..9d35435 100644
--- a/Swift/QtUI/QtMainWindow.cpp
+++ b/Swift/QtUI/QtMainWindow.cpp
@@ -62,7 +62,7 @@ QtMainWindow::QtMainWindow(QtSettingsProvider* settings, UIEventStream* uiEventS
contactTabLayout->setSpacing(0);
contactTabLayout->setContentsMargins(0, 0, 0, 0);
- treeWidget_ = new QtRosterWidget(uiEventStream_);
+ treeWidget_ = new QtRosterWidget(uiEventStream_, this);
contactTabLayout->addWidget(treeWidget_);
tabs_->addTab(contactsTabWidget_, tr("&Contacts"));
@@ -115,7 +115,7 @@ QtMainWindow::QtMainWindow(QtSettingsProvider* settings, UIEventStream* uiEventS
connect(signOutAction, SIGNAL(triggered()), SLOT(handleSignOutAction()));
actionsMenu->addAction(signOutAction);
- connect(treeWidget_, SIGNAL(onSomethingSelectedChanged(bool)), editUserAction_, SLOT(setEnabled(bool)));
+ treeWidget_->onSomethingSelectedChanged.connect(boost::bind(&QAction::setEnabled, editUserAction_, _1));
setAvailableAdHocCommands(std::vector<DiscoItems::Item>());
QAction* adHocAction = new QAction(tr("Collecting commands..."), this);
diff --git a/Swift/QtUI/Roster/QtOccupantListWidget.cpp b/Swift/QtUI/Roster/QtOccupantListWidget.cpp
index 2f992bf..cbda0f1 100644
--- a/Swift/QtUI/Roster/QtOccupantListWidget.cpp
+++ b/Swift/QtUI/Roster/QtOccupantListWidget.cpp
@@ -9,6 +9,7 @@
#include <QContextMenuEvent>
#include <QMenu>
+#include <QAction>
#include <QInputDialog>
#include "Swift/Controllers/Roster/ContactRosterItem.h"
@@ -26,33 +27,33 @@ QtOccupantListWidget::~QtOccupantListWidget() {
}
+void QtOccupantListWidget::setAvailableOccupantActions(const std::vector<ChatWindow::OccupantAction>& actions) {
+ availableOccupantActions_ = actions;
+}
+
void QtOccupantListWidget::contextMenuEvent(QContextMenuEvent* event) {
-// QModelIndex index = indexAt(event->pos());
-// if (!index.isValid()) {
-// return;
-// }
-// RosterItem* item = static_cast<RosterItem*>(index.internalPointer());
-// QMenu contextMenu;
-// if (ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item)) {
-// QAction* editContact = contextMenu.addAction(tr("Edit"));
-// QAction* removeContact = contextMenu.addAction(tr("Remove"));
-// QAction* result = contextMenu.exec(event->globalPos());
-// if (result == editContact) {
-// eventStream_->send(boost::make_shared<RequestContactEditorUIEvent>(contact->getJID()));
-// }
-// else if (result == removeContact) {
-// if (QtContactEditWindow::confirmContactDeletion(contact->getJID())) {
-// eventStream_->send(boost::make_shared<RemoveRosterItemUIEvent>(contact->getJID()));
-// }
-// }
-// }
-// else if (GroupRosterItem* group = dynamic_cast<GroupRosterItem*>(item)) {
-// QAction* renameGroupAction = contextMenu.addAction(tr("Rename"));
-// QAction* result = contextMenu.exec(event->globalPos());
-// if (result == renameGroupAction) {
-// renameGroup(group);
-// }
-// }
+ QModelIndex index = indexAt(event->pos());
+ if (!index.isValid()) {
+ return;
+ }
+ RosterItem* item = static_cast<RosterItem*>(index.internalPointer());
+ ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item);
+ if (contact) {
+ QMenu contextMenu;
+ std::map<QAction*, ChatWindow::OccupantAction> actions;
+ foreach (ChatWindow::OccupantAction availableAction, availableOccupantActions_) {
+ QString text = "Error: missing string";
+ switch (availableAction) {
+ case ChatWindow::Kick: text = tr("Kick user"); break;
+ }
+ QAction* action = contextMenu.addAction(text);
+ actions[action] = availableAction;
+ }
+ QAction* result = contextMenu.exec(event->globalPos());
+ if (result) {
+ onOccupantActionSelected(actions[result], contact);
+ }
+ }
}
}
diff --git a/Swift/QtUI/Roster/QtOccupantListWidget.h b/Swift/QtUI/Roster/QtOccupantListWidget.h
index 5444210..ef29c00 100644
--- a/Swift/QtUI/Roster/QtOccupantListWidget.h
+++ b/Swift/QtUI/Roster/QtOccupantListWidget.h
@@ -8,6 +8,9 @@
#include "Swift/QtUI/Roster/QtTreeWidget.h"
+#include "Swiften/Base/boost_bsignals.h"
+#include "Swift/Controllers/UIInterfaces/ChatWindow.h"
+
namespace Swift {
class QtOccupantListWidget : public QtTreeWidget {
@@ -15,8 +18,12 @@ class QtOccupantListWidget : public QtTreeWidget {
public:
QtOccupantListWidget(UIEventStream* eventStream, QWidget* parent = 0);
virtual ~QtOccupantListWidget();
+ void setAvailableOccupantActions(const std::vector<ChatWindow::OccupantAction>& actions);
+ boost::signal<void (ChatWindow::OccupantAction, ContactRosterItem*)> onOccupantActionSelected;
protected:
void contextMenuEvent(QContextMenuEvent* event);
+ private:
+ std::vector<ChatWindow::OccupantAction> availableOccupantActions_;
};
}
diff --git a/Swift/QtUI/Roster/QtRosterWidget.cpp b/Swift/QtUI/Roster/QtRosterWidget.cpp
index 79d7f67..923f977 100644
--- a/Swift/QtUI/Roster/QtRosterWidget.cpp
+++ b/Swift/QtUI/Roster/QtRosterWidget.cpp
@@ -81,20 +81,4 @@ void QtRosterWidget::renameGroup(GroupRosterItem* group) {
}
}
-void QtRosterWidget::currentChanged(const QModelIndex& current, const QModelIndex& previous) {
- bool valid = false;
- QModelIndexList selectedIndexList = getSelectedIndexes();
- if (selectedIndexList.empty() || !selectedIndexList[0].isValid()) {
- /* I didn't quite understand why using current didn't seem to work here.*/
- }
- else if (current.isValid()) {
- RosterItem* item = static_cast<RosterItem*>(current.internalPointer());
- if (dynamic_cast<ContactRosterItem*>(item)) {
- valid = true;
- }
- }
- onSomethingSelectedChanged(valid);
- QTreeView::currentChanged(current, previous);
-}
-
}
diff --git a/Swift/QtUI/Roster/QtRosterWidget.h b/Swift/QtUI/Roster/QtRosterWidget.h
index 7781e07..f870237 100644
--- a/Swift/QtUI/Roster/QtRosterWidget.h
+++ b/Swift/QtUI/Roster/QtRosterWidget.h
@@ -9,7 +9,6 @@
#include "Swift/QtUI/Roster/QtTreeWidget.h"
namespace Swift {
-
class QtRosterWidget : public QtTreeWidget {
Q_OBJECT
public:
@@ -17,12 +16,8 @@ class QtRosterWidget : public QtTreeWidget {
virtual ~QtRosterWidget();
public slots:
void handleEditUserActionTriggered(bool checked);
- signals:
- void onSomethingSelectedChanged(bool);
protected:
void contextMenuEvent(QContextMenuEvent* event);
- protected slots:
- virtual void currentChanged(const QModelIndex& current, const QModelIndex& previous);
private:
void renameGroup(GroupRosterItem* group);
};
diff --git a/Swift/QtUI/Roster/QtTreeWidget.cpp b/Swift/QtUI/Roster/QtTreeWidget.cpp
index 7de4028..96a078b 100644
--- a/Swift/QtUI/Roster/QtTreeWidget.cpp
+++ b/Swift/QtUI/Roster/QtTreeWidget.cpp
@@ -81,6 +81,21 @@ QModelIndexList QtTreeWidget::getSelectedIndexes() const {
return selectedIndexList;
}
+void QtTreeWidget::currentChanged(const QModelIndex& current, const QModelIndex& previous) {
+ RosterItem* item = NULL;
+ QModelIndexList selectedIndexList = getSelectedIndexes();
+ if (selectedIndexList.empty() || !selectedIndexList[0].isValid()) {
+ /* I didn't quite understand why using current didn't seem to work here.*/
+ }
+ else if (current.isValid()) {
+ item = static_cast<RosterItem*>(current.internalPointer());
+ item = dynamic_cast<ContactRosterItem*>(item);
+ }
+ onSomethingSelectedChanged(item);
+ QTreeView::currentChanged(current, previous);
+}
+
+
void QtTreeWidget::handleItemActivated(const QModelIndex& index) {
RosterItem* item = static_cast<RosterItem*>(index.internalPointer());
ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item);
diff --git a/Swift/QtUI/Roster/QtTreeWidget.h b/Swift/QtUI/Roster/QtTreeWidget.h
index c45a1cd..1ad56d6 100644
--- a/Swift/QtUI/Roster/QtTreeWidget.h
+++ b/Swift/QtUI/Roster/QtTreeWidget.h
@@ -23,6 +23,7 @@ class QtTreeWidget : public QTreeView{
QtTreeWidgetItem* getRoot();
void setRosterModel(Roster* roster);
Roster* getRoster() {return roster_;}
+ boost::signal<void (RosterItem*)> onSomethingSelectedChanged;
private slots:
void handleItemActivated(const QModelIndex&);
@@ -35,7 +36,8 @@ class QtTreeWidget : public QTreeView{
QModelIndexList getSelectedIndexes() const;
private:
void drawBranches(QPainter*, const QRect&, const QModelIndex&) const;
-
+ protected slots:
+ virtual void currentChanged(const QModelIndex& current, const QModelIndex& previous);
protected:
UIEventStream* eventStream_;
diff --git a/Swiften/Elements/MUCAdminPayload.h b/Swiften/Elements/MUCAdminPayload.h
new file mode 100644
index 0000000..7b3da20
--- /dev/null
+++ b/Swiften/Elements/MUCAdminPayload.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/optional.hpp>
+#include <boost/shared_ptr.hpp>
+#include <string>
+#include <vector>
+
+#include <Swiften/JID/JID.h>
+#include <Swiften/Elements/Payload.h>
+#include <Swiften/Elements/MUCOccupant.h>
+#include <Swiften/Elements/MUCItem.h>
+
+namespace Swift {
+ class MUCAdminPayload : public Payload {
+ public:
+ typedef boost::shared_ptr<MUCAdminPayload> ref;
+
+
+ MUCAdminPayload() {
+ }
+
+ void addItem(MUCItem item) {items_.push_back(item);}
+
+ const std::vector<MUCItem>& getItems() const {return items_;}
+
+ private:
+ std::vector<MUCItem> items_;
+ };
+}
diff --git a/Swiften/Elements/MUCItem.h b/Swiften/Elements/MUCItem.h
new file mode 100644
index 0000000..86217ec
--- /dev/null
+++ b/Swiften/Elements/MUCItem.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Elements/MUCOccupant.h>
+#include <Swiften/JID/JID.h>
+namespace Swift {
+struct MUCItem {
+ MUCItem() {}
+ boost::optional<JID> realJID;
+ boost::optional<std::string> nick;
+ boost::optional<MUCOccupant::Affiliation> affiliation;
+ boost::optional<MUCOccupant::Role> role;
+ boost::optional<JID> actor;
+ boost::optional<std::string> reason;
+};
+}
diff --git a/Swiften/Elements/MUCUserPayload.h b/Swiften/Elements/MUCUserPayload.h
index 0276964..de9f1e5 100644
--- a/Swiften/Elements/MUCUserPayload.h
+++ b/Swiften/Elements/MUCUserPayload.h
@@ -14,20 +14,13 @@
#include <Swiften/JID/JID.h>
#include <Swiften/Elements/Payload.h>
#include <Swiften/Elements/MUCOccupant.h>
+#include <Swiften/Elements/MUCItem.h>
namespace Swift {
class MUCUserPayload : public Payload {
public:
typedef boost::shared_ptr<MUCUserPayload> ref;
- struct Item {
- Item(MUCOccupant::Affiliation affiliation = MUCOccupant::NoAffiliation, MUCOccupant::Role role = MUCOccupant::NoRole) : affiliation(affiliation), role(role) {}
- boost::optional<JID> realJID;
- boost::optional<std::string> nick;
- MUCOccupant::Affiliation affiliation;
- MUCOccupant::Role role;
- };
-
struct StatusCode {
StatusCode() : code(0) {}
int code;
@@ -48,16 +41,16 @@ namespace Swift {
MUCUserPayload() {
}
- void addItem(Item item) {items_.push_back(item);}
+ void addItem(MUCItem item) {items_.push_back(item);}
void addStatusCode(StatusCode code) {statusCodes_.push_back(code);}
- const std::vector<Item>& getItems() const {return items_;}
+ const std::vector<MUCItem>& getItems() const {return items_;}
const std::vector<StatusCode>& getStatusCodes() const {return statusCodes_;}
private:
- std::vector<Item> items_;
+ std::vector<MUCItem> items_;
std::vector<StatusCode> statusCodes_;
};
}
diff --git a/Swiften/MUC/MUC.cpp b/Swiften/MUC/MUC.cpp
index 1ade7e3..4b3960f 100644
--- a/Swiften/MUC/MUC.cpp
+++ b/Swiften/MUC/MUC.cpp
@@ -17,6 +17,7 @@
#include <Swiften/Elements/Form.h>
#include <Swiften/Elements/IQ.h>
#include <Swiften/Elements/MUCUserPayload.h>
+#include <Swiften/Elements/MUCAdminPayload.h>
#include <Swiften/Elements/MUCPayload.h>
#include <Swiften/MUC/MUCRegistry.h>
#include <Swiften/Queries/GenericRequest.h>
@@ -121,8 +122,8 @@ void MUC::handleIncomingPresence(Presence::ref presence) {
MUCOccupant::Affiliation affiliation(MUCOccupant::NoAffiliation);
boost::optional<JID> realJID;
if (mucPayload && mucPayload->getItems().size() > 0) {
- role = mucPayload->getItems()[0].role;
- affiliation = mucPayload->getItems()[0].affiliation;
+ role = mucPayload->getItems()[0].role ? mucPayload->getItems()[0].role.get() : MUCOccupant::NoRole;
+ affiliation = mucPayload->getItems()[0].affiliation ? mucPayload->getItems()[0].affiliation.get() : MUCOccupant::NoAffiliation;
realJID = mucPayload->getItems()[0].realJID;
}
@@ -217,6 +218,23 @@ MUCOccupant MUC::getOccupant(const std::string& nick) {
return occupants.find(nick)->second;
}
+void MUC::kickUser(const JID& jid) {
+ MUCAdminPayload::ref mucPayload = boost::make_shared<MUCAdminPayload>();
+ MUCItem item;
+ item.role = MUCOccupant::NoRole;
+ item.nick = jid.getResource();
+ mucPayload->addItem(item);
+ GenericRequest<MUCAdminPayload>* request = new GenericRequest<MUCAdminPayload>(IQ::Set, getJID(), mucPayload, iqRouter_);
+ request->onResponse.connect(boost::bind(&MUC::handleKickResponse, this, _1, _2, jid));
+ request->send();
+}
+
+void MUC::handleKickResponse(MUCAdminPayload::ref /*unused*/, ErrorPayload::ref error, const JID& jid) {
+ if (error) {
+ onKickFailed(error, jid);
+ }
+}
+
//FIXME: Recognise Topic changes
//TODO: Invites(direct/mediated)
diff --git a/Swiften/MUC/MUC.h b/Swiften/MUC/MUC.h
index 828a36f..41dbc4a 100644
--- a/Swiften/MUC/MUC.h
+++ b/Swiften/MUC/MUC.h
@@ -13,6 +13,7 @@
#include <Swiften/Elements/MUCOccupant.h>
#include <Swiften/MUC/MUCRegistry.h>
#include <Swiften/Elements/MUCOwnerPayload.h>
+#include <Swiften/Elements/MUCAdminPayload.h>
#include <boost/shared_ptr.hpp>
#include <Swiften/Base/boost_bsignals.h>
@@ -54,9 +55,11 @@ namespace Swift {
/** Get occupant information*/
MUCOccupant getOccupant(const std::string& nick);
bool hasOccupant(const std::string& nick);
+ void kickUser(const JID& jid);
public:
boost::signal<void (const std::string& /*nick*/)> onJoinComplete;
boost::signal<void (ErrorPayload::ref)> onJoinFailed;
+ boost::signal<void (ErrorPayload::ref, const JID&)> onKickFailed;
boost::signal<void (Presence::ref)> onOccupantPresenceChange;
boost::signal<void (const std::string&, const MUCOccupant& /*now*/, const MUCOccupant::Role& /*old*/)> onOccupantRoleChanged;
boost::signal<void (const std::string&, const MUCOccupant::Affiliation& /*new*/, const MUCOccupant::Affiliation& /*old*/)> onOccupantAffiliationChanged;
@@ -79,6 +82,7 @@ namespace Swift {
void handleIncomingPresence(Presence::ref presence);
void internalJoin(const std::string& nick);
void handleCreationConfigResponse(MUCOwnerPayload::ref, ErrorPayload::ref);
+ void handleKickResponse(MUCAdminPayload::ref, ErrorPayload::ref, const JID&);
private:
JID ownMUCJID;
diff --git a/Swiften/Parser/GenericPayloadTreeParser.cpp b/Swiften/Parser/GenericPayloadTreeParser.cpp
new file mode 100644
index 0000000..0e25cbc
--- /dev/null
+++ b/Swiften/Parser/GenericPayloadTreeParser.cpp
@@ -0,0 +1,8 @@
+/*
+ * Copyright (c) 2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/Parser/GenericPayloadTreeParser.h>
+
diff --git a/Swiften/Parser/GenericPayloadTreeParser.h b/Swiften/Parser/GenericPayloadTreeParser.h
new file mode 100644
index 0000000..0030af7
--- /dev/null
+++ b/Swiften/Parser/GenericPayloadTreeParser.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <deque>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Parser/GenericPayloadParser.h>
+#include <Swiften/Parser/Tree/ParserElement.h>
+#include <Swiften/Parser/Tree/NullParserElement.h>
+
+#include <iostream>
+
+namespace Swift {
+
+
+ /**
+ * Generic parser offering something a bit like a DOM to work with.
+ */
+ template<typename PAYLOAD_TYPE>
+ class GenericPayloadTreeParser : public GenericPayloadParser<PAYLOAD_TYPE> {
+ public:
+ virtual void handleStartElement(const std::string& element, const std::string& xmlns, const AttributeMap& attributes) {
+ //std::cerr << element << ", " << xmlns << ", " << attributes.getEntries().size();
+ if (!root_) {
+ root_ = boost::make_shared<ParserElement>(element, xmlns, attributes);
+ elementStack_.push_back(root_);
+ } else {
+ ParserElement::ref current = *elementStack_.rbegin();
+ elementStack_.push_back(current->addChild(element, xmlns, attributes));
+ }
+ }
+
+ virtual void handleEndElement(const std::string& /*element*/, const std::string&) {
+ elementStack_.pop_back();
+ if (elementStack_.empty()) {
+ handleTree(root_);
+ }
+ }
+
+ virtual void handleCharacterData(const std::string& data) {
+ ParserElement::ref current = *elementStack_.rbegin();
+ current->appendCharacterData(data);
+ }
+
+ virtual void handleTree(ParserElement::ref root) = 0;
+
+ private:
+ std::deque<ParserElement::ref> elementStack_;
+ ParserElement::ref root_;
+ };
+}
diff --git a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp
index e9c49ee..1b59f6f 100644
--- a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp
+++ b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp
@@ -44,6 +44,7 @@
#include <Swiften/Parser/PayloadParsers/PrivateStorageParserFactory.h>
#include <Swiften/Parser/PayloadParsers/DelayParser.h>
#include <Swiften/Parser/PayloadParsers/MUCUserPayloadParserFactory.h>
+#include <Swiften/Parser/PayloadParsers/MUCAdminPayloadParser.h>
#include <Swiften/Parser/PayloadParsers/NicknameParserFactory.h>
#include <Swiften/Parser/PayloadParsers/ReplaceParser.h>
#include <Swiften/Parser/PayloadParsers/LastParser.h>
@@ -88,6 +89,7 @@ FullPayloadParserFactoryCollection::FullPayloadParserFactoryCollection() {
factories_.push_back(shared_ptr<PayloadParserFactory>(new PrivateStorageParserFactory(this)));
factories_.push_back(shared_ptr<PayloadParserFactory>(new ChatStateParserFactory()));
factories_.push_back(shared_ptr<PayloadParserFactory>(new MUCUserPayloadParserFactory()));
+ factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<MUCAdminPayloadParser>("query", "http://jabber.org/protocol/muc#admin")));
factories_.push_back(shared_ptr<PayloadParserFactory>(new NicknameParserFactory()));
foreach(shared_ptr<PayloadParserFactory> factory, factories_) {
addFactory(factory.get());
diff --git a/Swiften/Parser/PayloadParsers/MUCAdminPayloadParser.cpp b/Swiften/Parser/PayloadParsers/MUCAdminPayloadParser.cpp
new file mode 100644
index 0000000..137ead4
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/MUCAdminPayloadParser.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/Parser/PayloadParsers/MUCAdminPayloadParser.h>
+
+#include <boost/lexical_cast.hpp>
+
+#include <Swiften/Base/foreach.h>
+#include <Swiften/Elements/MUCOccupant.h>
+
+namespace Swift {
+
+void MUCAdminPayloadParser::handleTree(ParserElement::ref root) {
+ foreach (ParserElement::ref itemElement, root->getChildren("item", "http://jabber.org/protocol/muc#admin")) {
+ MUCItem item = MUCItemParser::itemFromTree(itemElement);
+ getPayloadInternal()->addItem(item);
+ }
+}
+
+}
diff --git a/Swiften/Parser/PayloadParsers/MUCAdminPayloadParser.h b/Swiften/Parser/PayloadParsers/MUCAdminPayloadParser.h
new file mode 100644
index 0000000..dfa26da
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/MUCAdminPayloadParser.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/optional.hpp>
+
+#include <Swiften/Elements/MUCAdminPayload.h>
+#include <Swiften/Parser/GenericPayloadTreeParser.h>
+#include <Swiften/Parser/PayloadParsers/MUCItemParser.h>
+
+namespace Swift {
+ class MUCAdminPayloadParser : public GenericPayloadTreeParser<MUCAdminPayload> {
+ public:
+ virtual void handleTree(ParserElement::ref root);
+ };
+}
diff --git a/Swiften/Parser/PayloadParsers/MUCItemParser.cpp b/Swiften/Parser/PayloadParsers/MUCItemParser.cpp
new file mode 100644
index 0000000..2eb9997
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/MUCItemParser.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/Parser/PayloadParsers/MUCItemParser.h>
+
+#include <boost/lexical_cast.hpp>
+
+#include <Swiften/Elements/MUCOccupant.h>
+
+#include <cassert>
+#include <iostream>
+
+namespace Swift {
+
+MUCItem MUCItemParser::itemFromTree(ParserElement::ref root) {
+ MUCItem item;
+ std::string affiliation = root->getAttributes().getAttribute("affiliation");
+ std::string role = root->getAttributes().getAttribute("role");
+ std::string nick = root->getAttributes().getAttribute("nick");
+ std::string jid = root->getAttributes().getAttribute("jid");
+ item.affiliation = parseAffiliation(affiliation);
+ item.role = parseRole(role);
+ if (!jid.empty()) {
+ item.realJID = JID(jid);
+ }
+ if (!nick.empty()) {
+ item.nick = nick;
+ }
+ std::string xmlns = root->getNamespace();
+ std::string reason = root->getChild("reason", xmlns)->getText();
+ std::string actor = root->getChild("actor", xmlns)->getAttributes().getAttribute("jid");
+ if (!reason.empty()) {
+ item.reason = reason;
+ }
+ if (!actor.empty()) {
+ item.actor = JID(actor);
+ }
+
+ return item;
+}
+
+boost::optional<MUCOccupant::Role> MUCItemParser::parseRole(const std::string& roleString) {
+ if (roleString == "moderator") {
+ return MUCOccupant::Moderator;
+ }
+ if (roleString == "participant") {
+ return MUCOccupant::Participant;
+ }
+ if (roleString == "visitor") {
+ return MUCOccupant::Visitor;
+ }
+ if (roleString == "none") {
+ return MUCOccupant::NoRole;
+ }
+ return boost::optional<MUCOccupant::Role>();
+}
+
+boost::optional<MUCOccupant::Affiliation> MUCItemParser::parseAffiliation(const std::string& affiliationString) {
+ if (affiliationString == "owner") {
+ return MUCOccupant::Owner;
+ }
+ if (affiliationString == "admin") {
+ return MUCOccupant::Admin;
+ }
+ if (affiliationString == "member") {
+ return MUCOccupant::Member;
+ }
+ if (affiliationString == "outcast") {
+ return MUCOccupant::Outcast;
+ }
+ if (affiliationString == "none") {
+ return MUCOccupant::NoAffiliation;
+ }
+ return boost::optional<MUCOccupant::Affiliation>();
+}
+
+}
+
+
diff --git a/Swiften/Parser/PayloadParsers/MUCItemParser.h b/Swiften/Parser/PayloadParsers/MUCItemParser.h
new file mode 100644
index 0000000..a0ea060
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/MUCItemParser.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Elements/MUCItem.h>
+#include <Swiften/Parser/GenericPayloadTreeParser.h>
+
+namespace Swift {
+ class MUCItemParser {
+ public:
+ static MUCItem itemFromTree(ParserElement::ref root);
+ private:
+ static boost::optional<MUCOccupant::Role> parseRole(const std::string& itemString);
+ static boost::optional<MUCOccupant::Affiliation> parseAffiliation(const std::string& statusString);
+ };
+}
diff --git a/Swiften/Parser/PayloadParsers/MUCUserPayloadParser.cpp b/Swiften/Parser/PayloadParsers/MUCUserPayloadParser.cpp
index bd81b88..71ae571 100644
--- a/Swiften/Parser/PayloadParsers/MUCUserPayloadParser.cpp
+++ b/Swiften/Parser/PayloadParsers/MUCUserPayloadParser.cpp
@@ -8,87 +8,24 @@
#include <boost/lexical_cast.hpp>
+#include <Swiften/Base/foreach.h>
#include <Swiften/Elements/MUCOccupant.h>
-#include <cassert>
-#include <iostream>
-
namespace Swift {
-MUCUserPayloadParser::MUCUserPayloadParser() : level(TopLevel) {
-}
-
-void MUCUserPayloadParser::handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) {
- if (level == ItemLevel) {
- if (element == "item") {
- MUCUserPayload::Item item;
- std::string affiliation = attributes.getAttribute("affiliation");
- std::string role = attributes.getAttribute("role");
- std::string nick = attributes.getAttribute("nick");
- std::string jid = attributes.getAttribute("jid");
- item.affiliation = parseAffiliation(affiliation);
- item.role = parseRole(role);
- if (!jid.empty()) {
- item.realJID = JID(jid);
- }
- if (!nick.empty()) {
- item.nick = nick;
- }
- getPayloadInternal()->addItem(item);
- } else if (element == "status") {
- MUCUserPayload::StatusCode status;
- try {
- status.code = boost::lexical_cast<int>(attributes.getAttribute("code").c_str());
- getPayloadInternal()->addStatusCode(status);
- } catch (boost::bad_lexical_cast&) {
- }
+void MUCUserPayloadParser::handleTree(ParserElement::ref root) {
+ foreach (ParserElement::ref itemElement, root->getChildren("item", "http://jabber.org/protocol/muc#user")) {
+ MUCItem item = MUCItemParser::itemFromTree(itemElement);
+ getPayloadInternal()->addItem(item);
+ }
+ foreach (ParserElement::ref statusElement, root->getChildren("item", "http://jabber.org/protocol/muc#user")) {
+ MUCUserPayload::StatusCode status;
+ try {
+ status.code = boost::lexical_cast<int>(statusElement->getAttributes().getAttribute("code").c_str());
+ getPayloadInternal()->addStatusCode(status);
+ } catch (boost::bad_lexical_cast&) {
}
}
- ++level;
-}
-
-MUCOccupant::Role MUCUserPayloadParser::parseRole(const std::string& roleString) const {
- if (roleString == "moderator") {
- return MUCOccupant::Moderator;
- }
- if (roleString == "participant") {
- return MUCOccupant::Participant;
- }
- if (roleString == "visitor") {
- return MUCOccupant::Visitor;
- }
- if (roleString == "none") {
- return MUCOccupant::NoRole;
- }
- return MUCOccupant::NoRole;
-}
-
-MUCOccupant::Affiliation MUCUserPayloadParser::parseAffiliation(const std::string& affiliationString) const {
- if (affiliationString == "owner") {
- return MUCOccupant::Owner;
- }
- if (affiliationString == "admin") {
- return MUCOccupant::Admin;
- }
- if (affiliationString == "member") {
- return MUCOccupant::Member;
- }
- if (affiliationString == "outcast") {
- return MUCOccupant::Outcast;
- }
- if (affiliationString == "none") {
- return MUCOccupant::NoAffiliation;
- }
- return MUCOccupant::NoAffiliation;
-}
-
-
-void MUCUserPayloadParser::handleEndElement(const std::string& /*element*/, const std::string&) {
- --level;
-}
-
-void MUCUserPayloadParser::handleCharacterData(const std::string& /*data*/) {
-
}
}
diff --git a/Swiften/Parser/PayloadParsers/MUCUserPayloadParser.h b/Swiften/Parser/PayloadParsers/MUCUserPayloadParser.h
index b819905..e020127 100644
--- a/Swiften/Parser/PayloadParsers/MUCUserPayloadParser.h
+++ b/Swiften/Parser/PayloadParsers/MUCUserPayloadParser.h
@@ -9,23 +9,12 @@
#include <boost/optional.hpp>
#include <Swiften/Elements/MUCUserPayload.h>
-#include <Swiften/Parser/GenericPayloadParser.h>
+#include <Swiften/Parser/GenericPayloadTreeParser.h>
+#include <Swiften/Parser/PayloadParsers/MUCItemParser.h>
namespace Swift {
- class MUCUserPayloadParser : public GenericPayloadParser<MUCUserPayload> {
+ class MUCUserPayloadParser : public GenericPayloadTreeParser<MUCUserPayload> {
public:
- MUCUserPayloadParser();
-
- 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);
- MUCOccupant::Role parseRole(const std::string& itemString) const;
- MUCOccupant::Affiliation parseAffiliation(const std::string& statusString) const;
- private:
- enum Level {
- TopLevel = 0,
- ItemLevel = 1
- };
- int level;
+ virtual void handleTree(ParserElement::ref root);
};
}
diff --git a/Swiften/Parser/PayloadParsers/UnitTest/MUCAdminPayloadParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/MUCAdminPayloadParserTest.cpp
new file mode 100644
index 0000000..0648f58
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/UnitTest/MUCAdminPayloadParserTest.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
+#include <Swiften/Parser/PayloadParsers/MUCAdminPayloadParser.h>
+#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h>
+
+using namespace Swift;
+
+class MUCAdminPayloadParserTest : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE(MUCAdminPayloadParserTest);
+ CPPUNIT_TEST(testParse);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ MUCAdminPayloadParserTest() {}
+
+ void testParse() {
+ PayloadsParserTester parser;
+
+ CPPUNIT_ASSERT(parser.parse("<query xmlns=\"http://jabber.org/protocol/muc#admin\"><item affiliation=\"owner\" role=\"visitor\"><actor jid=\"kev@tester.lit\"/><reason>malice</reason></item></query>"));
+
+ MUCAdminPayload::ref payload = boost::dynamic_pointer_cast<MUCAdminPayload>(parser.getPayload());
+ MUCItem item = payload->getItems()[0];
+ CPPUNIT_ASSERT_EQUAL(MUCOccupant::Owner, item.affiliation.get());
+ CPPUNIT_ASSERT_EQUAL(MUCOccupant::Visitor, item.role.get());
+ CPPUNIT_ASSERT_EQUAL(JID("kev@tester.lit"), item.actor.get());
+ CPPUNIT_ASSERT_EQUAL(std::string("malice"), item.reason.get());
+ }
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(MUCAdminPayloadParserTest);
+
+
+
diff --git a/Swiften/Parser/SConscript b/Swiften/Parser/SConscript
index 17505f1..b9fcebb 100644
--- a/Swiften/Parser/SConscript
+++ b/Swiften/Parser/SConscript
@@ -14,6 +14,7 @@ sources = [
"CompressParser.cpp",
"ElementParser.cpp",
"IQParser.cpp",
+ "GenericPayloadTreeParser.cpp",
"MessageParser.cpp",
"PayloadParser.cpp",
"StanzaAckParser.cpp",
@@ -51,6 +52,8 @@ sources = [
"PayloadParsers/VCardUpdateParser.cpp",
"PayloadParsers/DelayParser.cpp",
"PayloadParsers/MUCUserPayloadParser.cpp",
+ "PayloadParsers/MUCAdminPayloadParser.cpp",
+ "PayloadParsers/MUCItemParser.cpp",
"PayloadParsers/NicknameParser.cpp",
"PayloadParsers/ReplaceParser.cpp",
"PayloadParsers/LastParser.cpp",
@@ -63,6 +66,7 @@ sources = [
"StreamManagementEnabledParser.cpp",
"StreamResumeParser.cpp",
"StreamResumedParser.cpp",
+ "Tree/ParserElement.cpp",
"XMLParser.cpp",
"XMLParserClient.cpp",
"XMLParserFactory.cpp",
diff --git a/Swiften/Parser/Tree/NullParserElement.h b/Swiften/Parser/Tree/NullParserElement.h
new file mode 100644
index 0000000..93c0662
--- /dev/null
+++ b/Swiften/Parser/Tree/NullParserElement.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <string>
+#include <Swiften/Parser/Tree/ParserElement.h>
+
+namespace Swift {
+
+ class NullParserElement : public ParserElement {
+ public:
+ NullParserElement() : ParserElement("", "", AttributeMap()) {}
+ virtual operator bool() {return false;};
+ };
+}
diff --git a/Swiften/Parser/Tree/ParserElement.cpp b/Swiften/Parser/Tree/ParserElement.cpp
new file mode 100644
index 0000000..c851b41
--- /dev/null
+++ b/Swiften/Parser/Tree/ParserElement.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+
+#include <Swiften/Parser/Tree/ParserElement.h>
+#include <Swiften/Parser/Tree/NullParserElement.h>
+
+#include <iostream>
+
+namespace Swift{
+
+ParserElement::ParserElement(const std::string& name, const std::string& xmlns, const AttributeMap& attributes) : name_(name), xmlns_(xmlns), attributes_(attributes) {
+
+}
+
+ParserElement::~ParserElement() {
+
+}
+
+ParserElement::operator bool() {
+ return true;
+}
+
+ParserElement::ref ParserElement::addChild(const std::string& name, const std::string& xmlns, const AttributeMap& attributes) {
+ ParserElement::ref child = boost::make_shared<ParserElement>(name, xmlns, attributes);
+ children_.push_back(child);
+ return child;
+}
+
+void ParserElement::appendCharacterData(const std::string& data) {
+ text_ += data;
+}
+
+std::string ParserElement::getText() {
+ return text_;
+}
+
+std::string ParserElement::getName() {
+ return name_;
+}
+
+std::string ParserElement::getNamespace() {
+ return xmlns_;
+}
+
+struct DoesntMatch {
+ public:
+ DoesntMatch(const std::string& tagName, const std::string& ns) : tagName(tagName), ns(ns) {}
+ bool operator()(ParserElement::ref element) { return element->getName() != tagName || element->getNamespace() != ns; }
+ private:
+ std::string tagName;
+ std::string ns;
+};
+
+
+std::vector<ParserElement::ref> ParserElement::getChildren(const std::string& name, const std::string& xmlns) {
+ std::vector<ParserElement::ref> result;
+ std::remove_copy_if(children_.begin(), children_.end(), std::back_inserter(result), DoesntMatch(name, xmlns));
+ return result;
+}
+
+ParserElement::ref ParserElement::getChild(const std::string& name, const std::string& xmlns) {
+ std::vector<ParserElement::ref> results = getChildren(name, xmlns);
+ boost::shared_ptr<NullParserElement> nullParser = boost::make_shared<NullParserElement>();
+ ParserElement::ref result = results.empty() ? boost::dynamic_pointer_cast<ParserElement>(nullParser) : results[0];
+ return result;
+}
+
+}
diff --git a/Swiften/Parser/Tree/ParserElement.h b/Swiften/Parser/Tree/ParserElement.h
new file mode 100644
index 0000000..ddf67fa
--- /dev/null
+++ b/Swiften/Parser/Tree/ParserElement.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+
+#pragma once
+
+#include <string>
+#include <vector>
+#include <Swiften/Base/boost_bsignals.h>
+#include <Swiften/Parser/AttributeMap.h>
+#include <boost/shared_ptr.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+namespace Swift {
+class ParserElement {
+ public:
+ typedef boost::shared_ptr<ParserElement> ref;
+ ParserElement(const std::string& name, const std::string& xmlns, const AttributeMap& attributes);
+ virtual ~ParserElement();
+ virtual operator bool();
+ ParserElement::ref addChild(const std::string& name, const std::string& xmlns, const AttributeMap& attributes);
+ void appendCharacterData(const std::string& data);
+ std::string getText();
+ std::string getName();
+ std::string getNamespace();
+ std::vector<ParserElement::ref> getChildren(const std::string& name, const std::string& xmlns);
+ ParserElement::ref getChild(const std::string& name, const std::string& xmlns);
+ const AttributeMap& getAttributes() const {return attributes_;}
+ private:
+ std::vector<ParserElement::ref> children_;
+ std::string name_;
+ std::string xmlns_;
+ AttributeMap attributes_;
+ std::string text_;
+
+};
+
+}
diff --git a/Swiften/Parser/UnitTest/GenericPayloadTreeParserTest.cpp b/Swiften/Parser/UnitTest/GenericPayloadTreeParserTest.cpp
new file mode 100644
index 0000000..d095afc
--- /dev/null
+++ b/Swiften/Parser/UnitTest/GenericPayloadTreeParserTest.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
+#include <Swiften/Parser/GenericPayloadTreeParser.h>
+#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadParserTester.h>
+#include <Swiften/Elements/RawXMLPayload.h>
+
+using namespace Swift;
+
+class GenericPayloadTreeParserTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(GenericPayloadTreeParserTest);
+ CPPUNIT_TEST(testTree);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ void testTree() {
+ MyParser testling;
+
+ std::string data = "<topLevel xmlns='urn:test:top'><firstLevelInheritedEmpty/><firstLevelInherited><secondLevelMultiChildren num='1'/><secondLevelMultiChildren num='2'/></firstLevelInherited><firstLevelNS xmlns='urn:test:first'/></topLevel>";
+
+ PayloadParserTester tester(&testling);
+ tester.parse(data);
+
+ ParserElement::ref tree = testling.tree;
+
+ CPPUNIT_ASSERT_EQUAL(std::string("topLevel"), tree->getName());
+ CPPUNIT_ASSERT_EQUAL(std::string("urn:test:top"), tree->getNamespace());
+ CPPUNIT_ASSERT(tree->getChild("firstLevelInheritedEmpty", "urn:test:top"));
+ CPPUNIT_ASSERT(!*tree->getChild("firstLevelInheritedEmpty", ""));
+ CPPUNIT_ASSERT(tree->getChild("firstLevelInherited", "urn:test:top"));
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), tree->getChild("firstLevelInherited", "urn:test:top")->getChildren("secondLevelMultiChildren", "urn:test:top").size());
+ CPPUNIT_ASSERT_EQUAL(std::string("1"), tree->getChild("firstLevelInherited", "urn:test:top")->getChildren("secondLevelMultiChildren", "urn:test:top")[0]->getAttributes().getAttribute("num"));
+ CPPUNIT_ASSERT_EQUAL(std::string("2"), tree->getChild("firstLevelInherited", "urn:test:top")->getChildren("secondLevelMultiChildren", "urn:test:top")[1]->getAttributes().getAttribute("num"));
+ CPPUNIT_ASSERT(tree->getChild("firstLevelNS", "urn:test:first"));
+ }
+
+ private:
+
+
+ class MyParser : public GenericPayloadTreeParser<RawXMLPayload>
+ {
+ public:
+ virtual ~MyParser() {}
+ virtual void handleTree(ParserElement::ref root) {
+ tree = root;
+ }
+ ParserElement::ref tree;
+ };
+
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(GenericPayloadTreeParserTest);
diff --git a/Swiften/SConscript b/Swiften/SConscript
index 0144ddb..e20e5e6 100644
--- a/Swiften/SConscript
+++ b/Swiften/SConscript
@@ -146,6 +146,7 @@ if env["SCONS_STAGE"] == "build" :
"Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp",
"Serializer/PayloadSerializers/MUCPayloadSerializer.cpp",
"Serializer/PayloadSerializers/MUCUserPayloadSerializer.cpp",
+ "Serializer/PayloadSerializers/MUCAdminPayloadSerializer.cpp",
"Serializer/PayloadSerializers/MUCOwnerPayloadSerializer.cpp",
"Serializer/PayloadSerializers/ResourceBindSerializer.cpp",
"Serializer/PayloadSerializers/RosterItemExchangeSerializer.cpp",
@@ -292,8 +293,10 @@ if env["SCONS_STAGE"] == "build" :
File("Parser/PayloadParsers/UnitTest/PrivateStorageParserTest.cpp"),
File("Parser/PayloadParsers/UnitTest/VCardUpdateParserTest.cpp"),
File("Parser/PayloadParsers/UnitTest/ReplaceTest.cpp"),
+ File("Parser/PayloadParsers/UnitTest/MUCAdminPayloadParserTest.cpp"),
File("Parser/UnitTest/AttributeMapTest.cpp"),
File("Parser/UnitTest/IQParserTest.cpp"),
+ File("Parser/UnitTest/GenericPayloadTreeParserTest.cpp"),
File("Parser/UnitTest/MessageParserTest.cpp"),
File("Parser/UnitTest/PayloadParserFactoryCollectionTest.cpp"),
File("Parser/UnitTest/PresenceParserTest.cpp"),
@@ -336,6 +339,7 @@ if env["SCONS_STAGE"] == "build" :
File("Serializer/PayloadSerializers/UnitTest/StorageSerializerTest.cpp"),
File("Serializer/PayloadSerializers/UnitTest/PrivateStorageSerializerTest.cpp"),
File("Serializer/PayloadSerializers/UnitTest/ReplaceSerializerTest.cpp"),
+ File("Serializer/PayloadSerializers/UnitTest/MUCAdminPayloadSerializerTest.cpp"),
File("Serializer/UnitTest/StreamFeaturesSerializerTest.cpp"),
File("Serializer/UnitTest/AuthSuccessSerializerTest.cpp"),
File("Serializer/UnitTest/AuthChallengeSerializerTest.cpp"),
diff --git a/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp b/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp
index 0746c37..0ddd445 100644
--- a/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp
+++ b/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp
@@ -21,6 +21,7 @@
#include <Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.h>
#include <Swiften/Serializer/PayloadSerializers/MUCPayloadSerializer.h>
#include <Swiften/Serializer/PayloadSerializers/MUCUserPayloadSerializer.h>
+#include <Swiften/Serializer/PayloadSerializers/MUCAdminPayloadSerializer.h>
#include <Swiften/Serializer/PayloadSerializers/MUCOwnerPayloadSerializer.h>
#include <Swiften/Serializer/PayloadSerializers/SoftwareVersionSerializer.h>
#include <Swiften/Serializer/PayloadSerializers/StatusSerializer.h>
@@ -61,6 +62,7 @@ FullPayloadSerializerCollection::FullPayloadSerializerCollection() {
serializers_.push_back(new RosterItemExchangeSerializer());
serializers_.push_back(new MUCPayloadSerializer());
serializers_.push_back(new MUCUserPayloadSerializer());
+ serializers_.push_back(new MUCAdminPayloadSerializer());
serializers_.push_back(new MUCOwnerPayloadSerializer(this));
serializers_.push_back(new SoftwareVersionSerializer());
serializers_.push_back(new StatusSerializer());
diff --git a/Swiften/Serializer/PayloadSerializers/MUCAdminPayloadSerializer.cpp b/Swiften/Serializer/PayloadSerializers/MUCAdminPayloadSerializer.cpp
new file mode 100644
index 0000000..552f7f1
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/MUCAdminPayloadSerializer.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/Serializer/PayloadSerializers/MUCAdminPayloadSerializer.h>
+
+#include <sstream>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Base/foreach.h>
+#include <Swiften/Serializer/XML/XMLElement.h>
+#include <Swiften/Serializer/XML/XMLTextNode.h>
+#include <Swiften/Serializer/PayloadSerializers/MUCItemSerializer.h>
+
+
+namespace Swift {
+
+MUCAdminPayloadSerializer::MUCAdminPayloadSerializer() : GenericPayloadSerializer<MUCAdminPayload>() {
+}
+
+std::string MUCAdminPayloadSerializer::serializePayload(boost::shared_ptr<MUCAdminPayload> payload) const {
+ XMLElement mucElement("query", "http://jabber.org/protocol/muc#admin");
+ foreach (const MUCItem item, payload->getItems()) {
+ mucElement.addNode(MUCItemSerializer::itemToElement(item));
+ }
+ return mucElement.serialize();
+}
+
+
+}
diff --git a/Swiften/Serializer/PayloadSerializers/MUCAdminPayloadSerializer.h b/Swiften/Serializer/PayloadSerializers/MUCAdminPayloadSerializer.h
new file mode 100644
index 0000000..e288cd7
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/MUCAdminPayloadSerializer.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2011 Kevin Smith
+ * 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/MUCAdminPayload.h>
+
+namespace Swift {
+ class MUCAdminPayloadSerializer : public GenericPayloadSerializer<MUCAdminPayload> {
+ public:
+ MUCAdminPayloadSerializer();
+ std::string affiliationToString(MUCOccupant::Affiliation affiliation) const;
+ std::string roleToString(MUCOccupant::Role role) const;
+
+ virtual std::string serializePayload(boost::shared_ptr<MUCAdminPayload> version) const;
+ };
+}
+
diff --git a/Swiften/Serializer/PayloadSerializers/MUCItemSerializer.h b/Swiften/Serializer/PayloadSerializers/MUCItemSerializer.h
new file mode 100644
index 0000000..7cb662c
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/MUCItemSerializer.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2011 Kevin Smith
+ * 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/MUCItem.h>
+#include <boost/smart_ptr/make_shared.hpp>
+
+namespace Swift {
+ class MUCItemSerializer {
+ public:
+ static std::string affiliationToString(MUCOccupant::Affiliation affiliation) {
+ std::string result;
+ switch (affiliation) {
+ case MUCOccupant::Owner: result = "owner"; break;
+ case MUCOccupant::Admin: result = "admin"; break;
+ case MUCOccupant::Member: result = "member"; break;
+ case MUCOccupant::Outcast: result = "outcast"; break;
+ case MUCOccupant::NoAffiliation: result = "none"; break;
+ default: assert(false);
+ }
+ return result;
+ }
+
+ static std::string roleToString(MUCOccupant::Role role) {
+ std::string result;
+ switch (role) {
+ case MUCOccupant::Moderator: result = "moderator"; break;
+ case MUCOccupant::NoRole: result = "none"; break;
+ case MUCOccupant::Participant: result = "participant"; break;
+ case MUCOccupant::Visitor: result = "visitor"; break;
+ default: assert(false);
+ }
+ return result;
+
+ }
+
+ static boost::shared_ptr<XMLElement> itemToElement(const MUCItem& item) {
+ boost::shared_ptr<XMLElement> itemElement(new XMLElement("item"));
+ if (item.affiliation) {
+ itemElement->setAttribute("affiliation", affiliationToString(item.affiliation.get()));
+ }
+ if (item.role) {
+ itemElement->setAttribute("role", roleToString(item.role.get()));
+ }
+ if (item.realJID) {
+ itemElement->setAttribute("jid", item.realJID.get());
+ }
+ if (item.nick) {
+ itemElement->setAttribute("nick", item.nick.get());
+ }
+ if (item.actor) {
+ boost::shared_ptr<XMLElement> actorElement(new XMLElement("actor"));
+ actorElement->setAttribute("jid", item.actor->toString());
+ itemElement->addNode(actorElement);
+ }
+ if (item.reason) {
+ boost::shared_ptr<XMLElement> reasonElement(new XMLElement("reason"));
+ reasonElement->addNode(boost::make_shared<XMLTextNode>(*item.reason));
+ itemElement->addNode(reasonElement);
+ }
+ return itemElement;
+ }
+ };
+}
diff --git a/Swiften/Serializer/PayloadSerializers/MUCUserPayloadSerializer.cpp b/Swiften/Serializer/PayloadSerializers/MUCUserPayloadSerializer.cpp
index 44aa506..0a8153d 100644
--- a/Swiften/Serializer/PayloadSerializers/MUCUserPayloadSerializer.cpp
+++ b/Swiften/Serializer/PayloadSerializers/MUCUserPayloadSerializer.cpp
@@ -13,7 +13,7 @@
#include <Swiften/Base/foreach.h>
#include <Swiften/Serializer/XML/XMLElement.h>
#include <Swiften/Serializer/XML/XMLTextNode.h>
-
+#include <Swiften/Serializer/PayloadSerializers/MUCItemSerializer.h>
namespace Swift {
@@ -29,46 +29,13 @@ std::string MUCUserPayloadSerializer::serializePayload(boost::shared_ptr<MUCUser
statusElement->setAttribute("code", code.str());
mucElement.addNode(statusElement);
}
- foreach (const MUCUserPayload::Item item, payload->getItems()) {
- boost::shared_ptr<XMLElement> itemElement(new XMLElement("item"));
- itemElement->setAttribute("affiliation", affiliationToString(item.affiliation));
- itemElement->setAttribute("role", roleToString(item.role));
- if (item.realJID) {
- itemElement->setAttribute("jid", item.realJID.get());
- }
- if (item.nick) {
- itemElement->setAttribute("nick", item.nick.get());
- }
- mucElement.addNode(itemElement);
+ foreach (const MUCItem item, payload->getItems()) {
+ mucElement.addNode(MUCItemSerializer::itemToElement(item));
}
return mucElement.serialize();
}
-std::string MUCUserPayloadSerializer::affiliationToString(MUCOccupant::Affiliation affiliation) const {
- std::string result;
- switch (affiliation) {
- case MUCOccupant::Owner: result = "owner"; break;
- case MUCOccupant::Admin: result = "admin"; break;
- case MUCOccupant::Member: result = "member"; break;
- case MUCOccupant::Outcast: result = "outcast"; break;
- case MUCOccupant::NoAffiliation: result = "none"; break;
- default: assert(false);
- }
- return result;
-}
-
-std::string MUCUserPayloadSerializer::roleToString(MUCOccupant::Role role) const {
- std::string result;
- switch (role) {
- case MUCOccupant::Moderator: result = "moderator"; break;
- case MUCOccupant::NoRole: result = "none"; break;
- case MUCOccupant::Participant: result = "participant"; break;
- case MUCOccupant::Visitor: result = "visitor"; break;
- default: assert(false);
- }
- return result;
-}
}
diff --git a/Swiften/Serializer/PayloadSerializers/MUCUserPayloadSerializer.h b/Swiften/Serializer/PayloadSerializers/MUCUserPayloadSerializer.h
index 634ce22..84c4a96 100644
--- a/Swiften/Serializer/PayloadSerializers/MUCUserPayloadSerializer.h
+++ b/Swiften/Serializer/PayloadSerializers/MUCUserPayloadSerializer.h
@@ -13,8 +13,6 @@ namespace Swift {
class MUCUserPayloadSerializer : public GenericPayloadSerializer<MUCUserPayload> {
public:
MUCUserPayloadSerializer();
- std::string affiliationToString(MUCOccupant::Affiliation affiliation) const;
- std::string roleToString(MUCOccupant::Role role) const;
virtual std::string serializePayload(boost::shared_ptr<MUCUserPayload> version) const;
};
diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/MUCAdminPayloadSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/MUCAdminPayloadSerializerTest.cpp
new file mode 100644
index 0000000..a8acf80
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/UnitTest/MUCAdminPayloadSerializerTest.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Serializer/PayloadSerializers/MUCAdminPayloadSerializer.h>
+
+using namespace Swift;
+
+class MUCAdminPayloadSerializerTest : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE(MUCAdminPayloadSerializerTest);
+ CPPUNIT_TEST(testSerialize);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ MUCAdminPayloadSerializerTest() {}
+
+ void testSerialize() {
+ MUCAdminPayloadSerializer testling;
+ boost::shared_ptr<MUCAdminPayload> admin = boost::make_shared<MUCAdminPayload>();
+ MUCItem item;
+ item.affiliation = MUCOccupant::Owner;
+ item.role = MUCOccupant::Visitor;
+ item.reason = "malice";
+ item.actor = JID("kev@tester.lit");
+ admin->addItem(item);
+
+ CPPUNIT_ASSERT_EQUAL(std::string("<query xmlns=\"http://jabber.org/protocol/muc#admin\"><item affiliation=\"owner\" role=\"visitor\"><actor jid=\"kev@tester.lit\"/><reason>malice</reason></item></query>"), testling.serialize(admin));
+ }
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(MUCAdminPayloadSerializerTest);