summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRemko Tronçon <git@el-tramo.be>2010-08-18 20:08:34 (GMT)
committerRemko Tronçon <git@el-tramo.be>2010-08-18 20:08:34 (GMT)
commite1f9cdc38b600d930760ed0e0b867ab739127f5a (patch)
tree928b9ad82c1341640631035ffa28fdf01dc4dcc5 /Swiften/Parser
parent6fd3078f8f512c74bfc54c3d31d6446098088a69 (diff)
downloadswift-e1f9cdc38b600d930760ed0e0b867ab739127f5a.zip
swift-e1f9cdc38b600d930760ed0e0b867ab739127f5a.tar.bz2
Added command parser.
Diffstat (limited to 'Swiften/Parser')
-rw-r--r--Swiften/Parser/PayloadParsers/CommandParser.cpp140
-rw-r--r--Swiften/Parser/PayloadParsers/CommandParser.h45
-rw-r--r--Swiften/Parser/PayloadParsers/CommandParserFactory.h29
-rw-r--r--Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp2
-rw-r--r--Swiften/Parser/PayloadParsers/UnitTest/CommandParserTest.cpp86
-rw-r--r--Swiften/Parser/PayloadParsers/UnitTest/FormParserTest.cpp2
-rw-r--r--Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h7
-rw-r--r--Swiften/Parser/SConscript1
8 files changed, 311 insertions, 1 deletions
diff --git a/Swiften/Parser/PayloadParsers/CommandParser.cpp b/Swiften/Parser/PayloadParsers/CommandParser.cpp
new file mode 100644
index 0000000..4e80829
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/CommandParser.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include "Swiften/Parser/PayloadParsers/CommandParser.h"
+#include "Swiften/Parser/PayloadParsers/FormParserFactory.h"
+#include "Swiften/Parser/PayloadParsers/FormParser.h"
+
+namespace Swift {
+
+CommandParser::CommandParser() : level_(TopLevel), inNote_(false), inActions_(false), formParser_(0) {
+ formParserFactory_ = new FormParserFactory();
+}
+
+CommandParser::~CommandParser() {
+ delete formParserFactory_;
+}
+
+void CommandParser::handleStartElement(const String& element, const String& ns, const AttributeMap& attributes) {
+ ++level_;
+ if (level_ == PayloadLevel) {
+ boost::optional<Command::Action> action = parseAction(attributes.getAttribute("action"));
+ if (action) {
+ getPayloadInternal()->setAction(*action);
+ }
+
+ String status = attributes.getAttribute("status");
+ if (status == "executing") {
+ getPayloadInternal()->setStatus(Command::Executing);
+ }
+ else if (status == "completed") {
+ getPayloadInternal()->setStatus(Command::Completed);
+ }
+ else if (status == "canceled") {
+ getPayloadInternal()->setStatus(Command::Canceled);
+ }
+
+ getPayloadInternal()->setNode(attributes.getAttribute("node"));
+ getPayloadInternal()->setSessionID(attributes.getAttribute("sessionid"));
+ }
+ else if (level_ == FormOrNoteOrActionsLevel) {
+ assert(!formParser_);
+ if (formParserFactory_->canParse(element, ns, attributes)) {
+ formParser_ = dynamic_cast<FormParser*>(formParserFactory_->createPayloadParser());
+ assert(formParser_);
+ }
+ else if (element == "note") {
+ inNote_ = true;
+ currentText_.clear();
+ String noteType = attributes.getAttribute("type");
+ if (noteType == "info") {
+ noteType_ = Command::Note::Info;
+ }
+ else if (noteType == "warn") {
+ noteType_ = Command::Note::Warn;
+ }
+ else if (noteType == "error") {
+ noteType_ = Command::Note::Error;
+ }
+ else {
+ noteType_ = Command::Note::Info;
+ }
+ }
+ else if (element == "actions") {
+ inActions_ = true;
+ boost::optional<Command::Action> action = parseAction(attributes.getAttribute("execute"));
+ if (action) {
+ getPayloadInternal()->setExecuteAction(*action);
+ }
+ }
+ }
+ else if (level_ == ActionsActionLevel) {
+ }
+
+ if (formParser_) {
+ formParser_->handleStartElement(element, ns, attributes);
+ }
+}
+
+void CommandParser::handleEndElement(const String& element, const String& ns) {
+ if (formParser_) {
+ formParser_->handleEndElement(element, ns);
+ }
+
+ if (level_ == FormOrNoteOrActionsLevel) {
+ if (formParser_) {
+ Form::ref form = Form::cast(formParser_->getPayload());
+ assert(form);
+ getPayloadInternal()->setForm(form);
+ delete formParser_;
+ formParser_ = 0;
+ }
+ else if (inNote_) {
+ inNote_ = false;
+ getPayloadInternal()->addNote(Command::Note(currentText_, noteType_));
+ }
+ else if (inActions_) {
+ inActions_ = false;
+ }
+ }
+ else if (level_ == ActionsActionLevel && inActions_) {
+ boost::optional<Command::Action> action = parseAction(element);
+ if (action) {
+ getPayloadInternal()->addAvailableAction(*action);
+ }
+ }
+ --level_;
+}
+
+void CommandParser::handleCharacterData(const String& data) {
+ if (formParser_) {
+ formParser_->handleCharacterData(data);
+ }
+ else {
+ currentText_ += data;
+ }
+}
+
+boost::optional<Command::Action> CommandParser::parseAction(const String& action) {
+ if (action == "execute") {
+ return Command::Execute;
+ }
+ else if (action == "cancel") {
+ return Command::Cancel;
+ }
+ else if (action == "prev") {
+ return Command::Prev;
+ }
+ else if (action == "next") {
+ return Command::Next;
+ }
+ else if (action == "complete") {
+ return Command::Complete;
+ }
+ return boost::optional<Command::Action>();
+}
+
+}
diff --git a/Swiften/Parser/PayloadParsers/CommandParser.h b/Swiften/Parser/PayloadParsers/CommandParser.h
new file mode 100644
index 0000000..a682a80
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/CommandParser.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/optional.hpp>
+
+#include "Swiften/Elements/Command.h"
+#include "Swiften/Parser/GenericPayloadParser.h"
+
+namespace Swift {
+ class FormParserFactory;
+ class FormParser;
+
+ class CommandParser : public GenericPayloadParser<Command> {
+ public:
+ CommandParser();
+ ~CommandParser();
+
+ virtual void handleStartElement(const String& element, const String&, const AttributeMap& attributes);
+ virtual void handleEndElement(const String& element, const String&);
+ virtual void handleCharacterData(const String& data);
+
+ private:
+ static boost::optional<Command::Action> parseAction(const String& action);
+
+ private:
+ enum Level {
+ TopLevel = 0,
+ PayloadLevel = 1,
+ FormOrNoteOrActionsLevel = 2,
+ ActionsActionLevel = 3
+ };
+ int level_;
+ bool inNote_;
+ bool inActions_;
+ Command::Note::Type noteType_;
+ FormParserFactory* formParserFactory_;
+ FormParser* formParser_;
+ String currentText_;
+ };
+}
diff --git a/Swiften/Parser/PayloadParsers/CommandParserFactory.h b/Swiften/Parser/PayloadParsers/CommandParserFactory.h
new file mode 100644
index 0000000..da2f484
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/CommandParserFactory.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include "Swiften/Parser/PayloadParserFactory.h"
+#include "Swiften/Parser/PayloadParsers/CommandParser.h"
+
+namespace Swift {
+ class PayloadParserFactoryCollection;
+
+ class CommandParserFactory : public PayloadParserFactory {
+ public:
+ CommandParserFactory() {
+ }
+
+ virtual bool canParse(const String& element, const String& ns, const AttributeMap&) const {
+ return ns == "http://jabber.org/protocol/commands" && element == "command";
+ }
+
+ virtual PayloadParser* createPayloadParser() {
+ return new CommandParser();
+ }
+
+ };
+}
diff --git a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp
index b115b10..ce6c9f8 100644
--- a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp
+++ b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp
@@ -25,6 +25,7 @@
#include "Swiften/Parser/PayloadParsers/SecurityLabelParserFactory.h"
#include "Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParserFactory.h"
#include "Swiften/Parser/PayloadParsers/FormParserFactory.h"
+#include "Swiften/Parser/PayloadParsers/CommandParserFactory.h"
#include "Swiften/Parser/PayloadParsers/VCardUpdateParserFactory.h"
#include "Swiften/Parser/PayloadParsers/VCardParserFactory.h"
#include "Swiften/Parser/PayloadParsers/RawXMLPayloadParserFactory.h"
@@ -53,6 +54,7 @@ FullPayloadParserFactoryCollection::FullPayloadParserFactoryCollection() {
factories_.push_back(shared_ptr<PayloadParserFactory>(new SecurityLabelParserFactory()));
factories_.push_back(shared_ptr<PayloadParserFactory>(new SecurityLabelsCatalogParserFactory()));
factories_.push_back(shared_ptr<PayloadParserFactory>(new FormParserFactory()));
+ factories_.push_back(shared_ptr<PayloadParserFactory>(new CommandParserFactory()));
factories_.push_back(shared_ptr<PayloadParserFactory>(new VCardUpdateParserFactory()));
factories_.push_back(shared_ptr<PayloadParserFactory>(new VCardParserFactory()));
factories_.push_back(shared_ptr<PayloadParserFactory>(new PrivateStorageParserFactory(this)));
diff --git a/Swiften/Parser/PayloadParsers/UnitTest/CommandParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/CommandParserTest.cpp
new file mode 100644
index 0000000..5f11718
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/UnitTest/CommandParserTest.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
+#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h"
+#include "Swiften/Elements/Command.h"
+
+using namespace Swift;
+
+class CommandParserTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(CommandParserTest);
+ CPPUNIT_TEST(testParse);
+ CPPUNIT_TEST(testParse_Result);
+ CPPUNIT_TEST(testParse_Form);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ void testParse() {
+ PayloadsParserTester parser;
+
+ CPPUNIT_ASSERT(parser.parse(
+ "<command xmlns='http://jabber.org/protocol/commands' node='list' action='prev' sessionid='myid'/>"
+ ));
+
+ Command::ref payload = parser.getPayload<Command>();
+ CPPUNIT_ASSERT_EQUAL(Command::Prev, payload->getAction());
+ CPPUNIT_ASSERT_EQUAL(String("list"), payload->getNode());
+ CPPUNIT_ASSERT_EQUAL(String("myid"), payload->getSessionID());
+ }
+
+ void testParse_Result() {
+ PayloadsParserTester parser;
+
+ CPPUNIT_ASSERT(parser.parse(
+ "<command xmlns='http://jabber.org/protocol/commands' node='config' status='completed' sessionid='myid'>"
+ "<note type='warn'>Service 'httpd' has been configured.</note>"
+ "<note type='error'>I lied.</note>"
+ "<actions execute='next'>"
+ "<prev/>"
+ "<next/>"
+ "</actions>"
+ "</command>"
+ ));
+
+ Command::ref payload = parser.getPayload<Command>();
+ CPPUNIT_ASSERT_EQUAL(Command::Completed, payload->getStatus());
+ std::vector<Command::Note> notes = payload->getNotes();
+ CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(notes.size()));
+ CPPUNIT_ASSERT_EQUAL(Command::Note::Warn, notes[0].type);
+ CPPUNIT_ASSERT_EQUAL(String("Service 'httpd' has been configured."), notes[0].note);
+ CPPUNIT_ASSERT_EQUAL(Command::Note::Error, notes[1].type);
+ CPPUNIT_ASSERT_EQUAL(String("I lied."), notes[1].note);
+ std::vector<Command::Action> actions = payload->getAvailableActions();
+ CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(actions.size()));
+ CPPUNIT_ASSERT_EQUAL(Command::Prev, actions[0]);
+ CPPUNIT_ASSERT_EQUAL(Command::Next, actions[1]);
+ CPPUNIT_ASSERT_EQUAL(Command::Next, payload->getExecuteAction());
+ }
+
+ void testParse_Form() {
+ PayloadsParserTester parser;
+
+ CPPUNIT_ASSERT(parser.parse(
+ "<command xmlns='http://jabber.org/protocol/commands' node='config' status='completed'>"
+ "<x type=\"result\" xmlns=\"jabber:x:data\">"
+ "<title>Bot Configuration</title>"
+ "<instructions>Hello!</instructions>"
+ "<instructions>Fill out this form to configure your new bot!</instructions>"
+ "</x>"
+ "</command>"
+ ));
+
+ Command::ref payload = parser.getPayload<Command>();
+ Form::ref form = payload->getForm();
+ CPPUNIT_ASSERT_EQUAL(String("Bot Configuration"), form->getTitle());
+ CPPUNIT_ASSERT_EQUAL(String("Hello!\nFill out this form to configure your new bot!"), form->getInstructions());
+ CPPUNIT_ASSERT_EQUAL(Form::ResultType, form->getType());
+ }
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(CommandParserTest);
diff --git a/Swiften/Parser/PayloadParsers/UnitTest/FormParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/FormParserTest.cpp
index e7d80e3..0d6e85e 100644
--- a/Swiften/Parser/PayloadParsers/UnitTest/FormParserTest.cpp
+++ b/Swiften/Parser/PayloadParsers/UnitTest/FormParserTest.cpp
@@ -7,8 +7,8 @@
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
-#include "Swiften/Parser/PayloadParsers/FormParser.h"
#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h"
+#include "Swiften/Elements/Form.h"
using namespace Swift;
diff --git a/Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h b/Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h
index 9ce0ac4..ee64181 100644
--- a/Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h
+++ b/Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h
@@ -12,6 +12,8 @@
#include "Swiften/Parser/XMLParser.h"
#include "Swiften/Parser/XMLParserClient.h"
#include "Swiften/Parser/PlatformXMLParserFactory.h"
+#include "Swiften/Elements/Payload.h"
+#include "Swiften/Parser/PayloadParser.h"
namespace Swift {
class PayloadsParserTester : public XMLParserClient {
@@ -52,6 +54,11 @@ namespace Swift {
return payloadParser->getPayload();
}
+ template<typename T>
+ boost::shared_ptr<T> getPayload() const {
+ return boost::dynamic_pointer_cast<T>(payloadParser->getPayload());
+ }
+
private:
XMLParser* xmlParser;
FullPayloadParserFactoryCollection factories;
diff --git a/Swiften/Parser/SConscript b/Swiften/Parser/SConscript
index 1826432..4efd343 100644
--- a/Swiften/Parser/SConscript
+++ b/Swiften/Parser/SConscript
@@ -24,6 +24,7 @@ sources = [
"PayloadParsers/DiscoItemsParser.cpp",
"PayloadParsers/ErrorParser.cpp",
"PayloadParsers/FormParser.cpp",
+ "PayloadParsers/CommandParser.cpp",
"PayloadParsers/FullPayloadParserFactoryCollection.cpp",
"PayloadParsers/PriorityParser.cpp",
"PayloadParsers/PrivateStorageParser.cpp",