Reland of "Remove webrtc/libjingle/{xmllite,xmpp}"

Last references to the old code were fixed in Chromium with
https://codereview.chromium.org/2616873002/ and
https://codereview.chromium.org/2617363002/

Original issue's description:
> Revert of Remove webrtc/libjingle/{xmllite,xmpp} (patchset #1 id:1 of https://codereview.webrtc.org/2617443003/ )
>
> Reason for revert:
> Breaks Chromium FYI bots.
>
> tommi, please let me land this (I forgot to run them).
>
> Original issue's description:
> > Remove webrtc/libjingle/{xmllite,xmpp} as it's dead code.
> >
> > These sources have now been imported into Chromium's
> > src/third_party/libjingle_xmpp.
> >
> > BUG=webrtc:5539
> > NOTRY=True
> >
> > Review-Url: https://codereview.webrtc.org/2617443003
> > Cr-Commit-Position: refs/heads/master@{#15910}
> > Committed: 1670b1fe6b
>
> TBR=tommi@webrtc.org
> # Skipping CQ checks because original CL landed less than 1 days ago.
> NOPRESUBMIT=true
> NOTREECHECKS=true
> NOTRY=true
> BUG=webrtc:5539
>
> Review-Url: https://codereview.webrtc.org/2618633003
> Cr-Commit-Position: refs/heads/master@{#15911}
> Committed: 60ef117be4

TBR=tommi@webrtc.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=webrtc:5539

Review-Url: https://codereview.webrtc.org/2618693002
Cr-Commit-Position: refs/heads/master@{#15954}
This commit is contained in:
kjellander 2017-01-08 23:02:01 -08:00 committed by Commit bot
parent 1b47618006
commit 13ced17068
118 changed files with 0 additions and 19602 deletions

View File

@ -253,8 +253,6 @@ if (!build_with_chromium) {
"call",
"common_audio",
"common_video",
"libjingle/xmllite",
"libjingle/xmpp",
"logging",
"media",
"modules",
@ -291,7 +289,6 @@ if (!build_with_chromium) {
"api:peerconnection_unittests",
"common_audio:common_audio_unittests",
"common_video:common_video_unittests",
"libjingle:xmllite_xmpp_unittests",
"media:rtc_media_unittests",
"modules:modules_tests",
"modules:modules_unittests",

View File

@ -95,8 +95,4 @@
"label": "//webrtc:webrtc_nonparallel_tests",
"type": "non_parallel_console_test_launcher",
},
"xmllite_xmpp_unittests": {
"label": "//webrtc/libjingle:xmllite_xmpp_unittests",
"type": "console_test_launcher",
}
}

View File

@ -1,59 +0,0 @@
# Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
#
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE file in the root of the source
# tree. An additional intellectual property rights grant can be found
# in the file PATENTS. All contributing project authors may
# be found in the AUTHORS file in the root of the source tree.
import("../build/webrtc.gni")
group("libjingle") {
public_deps = [
"xmllite",
"xmpp",
]
}
if (rtc_include_tests) {
rtc_test("xmllite_xmpp_unittests") {
configs += [ "..:rtc_unittests_config" ]
if (!build_with_chromium && is_clang) {
# Suppress warnings from the Chromium Clang plugin.
# See http://code.google.com/p/webrtc/issues/detail?id=163 for details.
suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
}
deps = [
"../base:rtc_base_tests_utils",
"xmllite",
"xmpp",
"//testing/gtest",
]
sources = [
"xmllite/qname_unittest.cc",
"xmllite/xmlbuilder_unittest.cc",
"xmllite/xmlelement_unittest.cc",
"xmllite/xmlnsstack_unittest.cc",
"xmllite/xmlparser_unittest.cc",
"xmllite/xmlprinter_unittest.cc",
"xmpp/fakexmppclient.h",
"xmpp/hangoutpubsubclient_unittest.cc",
"xmpp/jid_unittest.cc",
"xmpp/mucroomconfigtask_unittest.cc",
"xmpp/mucroomdiscoverytask_unittest.cc",
"xmpp/mucroomlookuptask_unittest.cc",
"xmpp/mucroomuniquehangoutidtask_unittest.cc",
"xmpp/pingtask_unittest.cc",
"xmpp/pubsubclient_unittest.cc",
"xmpp/pubsubtasks_unittest.cc",
"xmpp/util_unittest.cc",
"xmpp/util_unittest.h",
"xmpp/xmppengine_unittest.cc",
"xmpp/xmpplogintask_unittest.cc",
"xmpp/xmppstanzaparser_unittest.cc",
]
}
}

View File

@ -1,5 +0,0 @@
include_rules = [
"+third_party/expat",
"+webrtc/base",
"+webrtc/p2p",
]

View File

@ -1,10 +0,0 @@
henrika@webrtc.org
henrikg@webrtc.org
hta@webrtc.org
jiayl@webrtc.org
juberti@webrtc.org
mflodman@webrtc.org
perkj@webrtc.org
pthatcher@webrtc.org
sergeyu@chromium.org
tommi@webrtc.org

View File

@ -1,51 +0,0 @@
# Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
#
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE file in the root of the source
# tree. An additional intellectual property rights grant can be found
# in the file PATENTS. All contributing project authors may
# be found in the AUTHORS file in the root of the source tree.
import("../../build/webrtc.gni")
group("xmllite") {
public_deps = [
":rtc_xmllite",
]
}
rtc_static_library("rtc_xmllite") {
sources = [
"qname.cc",
"qname.h",
"xmlbuilder.cc",
"xmlbuilder.h",
"xmlconstants.cc",
"xmlconstants.h",
"xmlelement.cc",
"xmlelement.h",
"xmlnsstack.cc",
"xmlnsstack.h",
"xmlparser.cc",
"xmlparser.h",
"xmlprinter.cc",
"xmlprinter.h",
]
deps = [
"../../base:rtc_base",
]
if (rtc_build_expat) {
deps += [ "//third_party/expat" ]
public_deps = [
"//third_party/expat",
]
}
if (!build_with_chromium && is_clang) {
# Suppress warnings from Chrome's Clang plugins.
# See http://code.google.com/p/webrtc/issues/detail?id=163 for details.
suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
}
}

View File

@ -1,6 +0,0 @@
# See ../OWNERS for more owners.
# These are for the common case of adding or renaming files. If you're doing
# structural changes, please get a review from a reviewer in this file.
per-file *.gn=*
per-file *.gni=*

View File

@ -1,78 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/xmllite/qname.h"
namespace buzz {
QName::QName() {
}
QName::QName(const QName& qname)
: namespace_(qname.namespace_),
local_part_(qname.local_part_) {
}
QName::QName(const StaticQName& const_value)
: namespace_(const_value.ns),
local_part_(const_value.local) {
}
QName::QName(const std::string& ns, const std::string& local)
: namespace_(ns),
local_part_(local) {
}
QName::QName(const std::string& merged_or_local) {
size_t i = merged_or_local.rfind(':');
if (i == std::string::npos) {
local_part_ = merged_or_local;
} else {
namespace_ = merged_or_local.substr(0, i);
local_part_ = merged_or_local.substr(i + 1);
}
}
QName::~QName() {
}
std::string QName::Merged() const {
if (namespace_[0] == '\0')
return local_part_;
std::string result;
result.reserve(namespace_.length() + 1 + local_part_.length());
result += namespace_;
result += ':';
result += local_part_;
return result;
}
bool QName::IsEmpty() const {
return namespace_.empty() && local_part_.empty();
}
int QName::Compare(const StaticQName& other) const {
int result = local_part_.compare(other.local);
if (result != 0)
return result;
return namespace_.compare(other.ns);
}
int QName::Compare(const QName& other) const {
int result = local_part_.compare(other.local_part_);
if (result != 0)
return result;
return namespace_.compare(other.namespace_);
}
} // namespace buzz

View File

@ -1,83 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMLLITE_QNAME_H_
#define WEBRTC_LIBJINGLE_XMLLITE_QNAME_H_
#include <string>
namespace buzz {
class QName;
// StaticQName is used to represend constant quailified names. They
// can be initialized statically and don't need intializers code, e.g.
// const StaticQName QN_FOO = { "foo_namespace", "foo" };
//
// Beside this use case, QName should be used everywhere
// else. StaticQName instances are implicitly converted to QName
// objects.
struct StaticQName {
const char* const ns;
const char* const local;
bool operator==(const QName& other) const;
bool operator!=(const QName& other) const;
};
class QName {
public:
QName();
QName(const QName& qname);
QName(const StaticQName& const_value);
QName(const std::string& ns, const std::string& local);
explicit QName(const std::string& merged_or_local);
~QName();
const std::string& Namespace() const { return namespace_; }
const std::string& LocalPart() const { return local_part_; }
std::string Merged() const;
bool IsEmpty() const;
int Compare(const StaticQName& other) const;
int Compare(const QName& other) const;
bool operator==(const StaticQName& other) const {
return Compare(other) == 0;
}
bool operator==(const QName& other) const {
return Compare(other) == 0;
}
bool operator!=(const StaticQName& other) const {
return Compare(other) != 0;
}
bool operator!=(const QName& other) const {
return Compare(other) != 0;
}
bool operator<(const QName& other) const {
return Compare(other) < 0;
}
private:
std::string namespace_;
std::string local_part_;
};
inline bool StaticQName::operator==(const QName& other) const {
return other.Compare(*this) == 0;
}
inline bool StaticQName::operator!=(const QName& other) const {
return other.Compare(*this) != 0;
}
} // namespace buzz
#endif // WEBRTC_LIBJINGLE_XMLLITE_QNAME_H_

View File

@ -1,114 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <string>
#include "webrtc/libjingle/xmllite/qname.h"
#include "webrtc/base/gunit.h"
using buzz::StaticQName;
using buzz::QName;
TEST(QNameTest, TestTrivial) {
QName name("test");
EXPECT_EQ(name.LocalPart(), "test");
EXPECT_EQ(name.Namespace(), "");
}
TEST(QNameTest, TestSplit) {
QName name("a:test");
EXPECT_EQ(name.LocalPart(), "test");
EXPECT_EQ(name.Namespace(), "a");
QName name2("a-very:long:namespace:test-this");
EXPECT_EQ(name2.LocalPart(), "test-this");
EXPECT_EQ(name2.Namespace(), "a-very:long:namespace");
}
TEST(QNameTest, TestMerge) {
QName name("a", "test");
EXPECT_EQ(name.LocalPart(), "test");
EXPECT_EQ(name.Namespace(), "a");
EXPECT_EQ(name.Merged(), "a:test");
QName name2("a-very:long:namespace", "test-this");
EXPECT_EQ(name2.LocalPart(), "test-this");
EXPECT_EQ(name2.Namespace(), "a-very:long:namespace");
EXPECT_EQ(name2.Merged(), "a-very:long:namespace:test-this");
}
TEST(QNameTest, TestAssignment) {
QName name("a", "test");
// copy constructor
QName namecopy(name);
EXPECT_EQ(namecopy.LocalPart(), "test");
EXPECT_EQ(namecopy.Namespace(), "a");
QName nameassigned("");
nameassigned = name;
EXPECT_EQ(nameassigned.LocalPart(), "test");
EXPECT_EQ(nameassigned.Namespace(), "a");
}
TEST(QNameTest, TestConstAssignment) {
StaticQName name = { "a", "test" };
QName namecopy(name);
EXPECT_EQ(namecopy.LocalPart(), "test");
EXPECT_EQ(namecopy.Namespace(), "a");
QName nameassigned("");
nameassigned = name;
EXPECT_EQ(nameassigned.LocalPart(), "test");
EXPECT_EQ(nameassigned.Namespace(), "a");
}
TEST(QNameTest, TestEquality) {
QName name("a-very:long:namespace:test-this");
QName name2("a-very:long:namespace", "test-this");
QName name3("a-very:long:namespaxe", "test-this");
EXPECT_TRUE(name == name2);
EXPECT_FALSE(name == name3);
}
TEST(QNameTest, TestCompare) {
QName name("a");
QName name2("nsa", "a");
QName name3("nsa", "b");
QName name4("nsb", "b");
EXPECT_TRUE(name < name2);
EXPECT_FALSE(name2 < name);
EXPECT_FALSE(name2 < name2);
EXPECT_TRUE(name2 < name3);
EXPECT_FALSE(name3 < name2);
EXPECT_TRUE(name3 < name4);
EXPECT_FALSE(name4 < name3);
}
TEST(QNameTest, TestStaticQName) {
const StaticQName const_name1 = { "namespace", "local-name1" };
const StaticQName const_name2 = { "namespace", "local-name2" };
const QName name("namespace", "local-name1");
const QName name1 = const_name1;
const QName name2 = const_name2;
EXPECT_TRUE(name == const_name1);
EXPECT_TRUE(const_name1 == name);
EXPECT_FALSE(name != const_name1);
EXPECT_FALSE(const_name1 != name);
EXPECT_TRUE(name == name1);
EXPECT_TRUE(name1 == name);
EXPECT_FALSE(name != name1);
EXPECT_FALSE(name1 != name);
EXPECT_FALSE(name == name2);
EXPECT_FALSE(name2 == name);
EXPECT_TRUE(name != name2);
EXPECT_TRUE(name2 != name);
}

View File

@ -1,130 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/xmllite/xmlbuilder.h"
#include <set>
#include <vector>
#include "webrtc/libjingle/xmllite/xmlconstants.h"
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/base/common.h"
namespace buzz {
XmlBuilder::XmlBuilder() :
pelCurrent_(NULL),
pelRoot_(),
pvParents_(new std::vector<XmlElement *>()) {
}
void
XmlBuilder::Reset() {
pelRoot_.reset();
pelCurrent_ = NULL;
pvParents_->clear();
}
XmlElement *
XmlBuilder::BuildElement(XmlParseContext * pctx,
const char * name, const char ** atts) {
QName tagName(pctx->ResolveQName(name, false));
if (tagName.IsEmpty())
return NULL;
XmlElement * pelNew = new XmlElement(tagName);
if (!*atts)
return pelNew;
std::set<QName> seenNonlocalAtts;
while (*atts) {
QName attName(pctx->ResolveQName(*atts, true));
if (attName.IsEmpty()) {
delete pelNew;
return NULL;
}
// verify that namespaced names are unique
if (!attName.Namespace().empty()) {
if (seenNonlocalAtts.count(attName)) {
delete pelNew;
return NULL;
}
seenNonlocalAtts.insert(attName);
}
pelNew->AddAttr(attName, std::string(*(atts + 1)));
atts += 2;
}
return pelNew;
}
void
XmlBuilder::StartElement(XmlParseContext * pctx,
const char * name, const char ** atts) {
XmlElement * pelNew = BuildElement(pctx, name, atts);
if (pelNew == NULL) {
pctx->RaiseError(XML_ERROR_SYNTAX);
return;
}
if (!pelCurrent_) {
pelCurrent_ = pelNew;
pelRoot_.reset(pelNew);
pvParents_->push_back(NULL);
} else {
pelCurrent_->AddElement(pelNew);
pvParents_->push_back(pelCurrent_);
pelCurrent_ = pelNew;
}
}
void
XmlBuilder::EndElement(XmlParseContext * pctx, const char * name) {
RTC_UNUSED(pctx);
RTC_UNUSED(name);
pelCurrent_ = pvParents_->back();
pvParents_->pop_back();
}
void
XmlBuilder::CharacterData(XmlParseContext * pctx,
const char * text, int len) {
RTC_UNUSED(pctx);
if (pelCurrent_) {
pelCurrent_->AddParsedText(text, len);
}
}
void
XmlBuilder::Error(XmlParseContext * pctx, XML_Error err) {
RTC_UNUSED(pctx);
RTC_UNUSED(err);
pelRoot_.reset(NULL);
pelCurrent_ = NULL;
pvParents_->clear();
}
XmlElement *
XmlBuilder::CreateElement() {
return pelRoot_.release();
}
XmlElement *
XmlBuilder::BuiltElement() {
return pelRoot_.get();
}
XmlBuilder::~XmlBuilder() {
}
} // namespace buzz

View File

@ -1,61 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef _xmlbuilder_h_
#define _xmlbuilder_h_
#include <memory>
#include <string>
#include <vector>
#include "webrtc/libjingle/xmllite/xmlparser.h"
#ifdef EXPAT_RELATIVE_PATH
#include "expat.h"
#else
#include "third_party/expat/v2_0_1/Source/lib/expat.h"
#endif // EXPAT_RELATIVE_PATH
namespace buzz {
class XmlElement;
class XmlParseContext;
class XmlBuilder : public XmlParseHandler {
public:
XmlBuilder();
static XmlElement * BuildElement(XmlParseContext * pctx,
const char * name, const char ** atts);
virtual void StartElement(XmlParseContext * pctx,
const char * name, const char ** atts);
virtual void EndElement(XmlParseContext * pctx, const char * name);
virtual void CharacterData(XmlParseContext * pctx,
const char * text, int len);
virtual void Error(XmlParseContext * pctx, XML_Error);
virtual ~XmlBuilder();
void Reset();
// Take ownership of the built element; second call returns NULL
XmlElement * CreateElement();
// Peek at the built element without taking ownership
XmlElement * BuiltElement();
private:
XmlElement * pelCurrent_;
std::unique_ptr<XmlElement> pelRoot_;
std::unique_ptr<std::vector<XmlElement*> > pvParents_;
};
}
#endif

View File

@ -1,177 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <iostream>
#include <sstream>
#include <string>
#include "webrtc/libjingle/xmllite/xmlbuilder.h"
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/libjingle/xmllite/xmlparser.h"
#include "webrtc/base/common.h"
#include "webrtc/base/gunit.h"
using buzz::XmlBuilder;
using buzz::XmlElement;
using buzz::XmlParser;
TEST(XmlBuilderTest, TestTrivial) {
XmlBuilder builder;
XmlParser::ParseXml(&builder, "<testing/>");
EXPECT_EQ("<testing/>", builder.BuiltElement()->Str());
}
TEST(XmlBuilderTest, TestAttributes1) {
XmlBuilder builder;
XmlParser::ParseXml(&builder, "<testing a='b'/>");
EXPECT_EQ("<testing a=\"b\"/>", builder.BuiltElement()->Str());
}
TEST(XmlBuilderTest, TestAttributes2) {
XmlBuilder builder;
XmlParser::ParseXml(&builder, "<testing e='' long='some text'/>");
EXPECT_EQ("<testing e=\"\" long=\"some text\"/>",
builder.BuiltElement()->Str());
}
TEST(XmlBuilderTest, TestNesting1) {
XmlBuilder builder;
XmlParser::ParseXml(&builder,
"<top><first/><second><third></third></second></top>");
EXPECT_EQ("<top><first/><second><third/></second></top>",
builder.BuiltElement()->Str());
}
TEST(XmlBuilderTest, TestNesting2) {
XmlBuilder builder;
XmlParser::ParseXml(&builder,
"<top><fifth><deeper><and><deeper/></and><sibling><leaf/>"
"</sibling></deeper></fifth><first/><second><third></third>"
"</second></top>");
EXPECT_EQ("<top><fifth><deeper><and><deeper/></and><sibling><leaf/>"
"</sibling></deeper></fifth><first/><second><third/>"
"</second></top>", builder.BuiltElement()->Str());
}
TEST(XmlBuilderTest, TestQuoting1) {
XmlBuilder builder;
XmlParser::ParseXml(&builder, "<testing a='>'/>");
EXPECT_EQ("<testing a=\"&gt;\"/>", builder.BuiltElement()->Str());
}
TEST(XmlBuilderTest, TestQuoting2) {
XmlBuilder builder;
XmlParser::ParseXml(&builder, "<testing a='&lt;>&amp;&quot;'/>");
EXPECT_EQ("<testing a=\"&lt;&gt;&amp;&quot;\"/>",
builder.BuiltElement()->Str());
}
TEST(XmlBuilderTest, TestQuoting3) {
XmlBuilder builder;
XmlParser::ParseXml(&builder, "<testing a='so &quot;important&quot;'/>");
EXPECT_EQ("<testing a=\"so &quot;important&quot;\"/>",
builder.BuiltElement()->Str());
}
TEST(XmlBuilderTest, TestQuoting4) {
XmlBuilder builder;
XmlParser::ParseXml(&builder, "<testing a='&quot;important&quot;, yes'/>");
EXPECT_EQ("<testing a=\"&quot;important&quot;, yes\"/>",
builder.BuiltElement()->Str());
}
TEST(XmlBuilderTest, TestQuoting5) {
XmlBuilder builder;
XmlParser::ParseXml(&builder,
"<testing a='&lt;what is &quot;important&quot;&gt;'/>");
EXPECT_EQ("<testing a=\"&lt;what is &quot;important&quot;&gt;\"/>",
builder.BuiltElement()->Str());
}
TEST(XmlBuilderTest, TestText1) {
XmlBuilder builder;
XmlParser::ParseXml(&builder, "<testing>></testing>");
EXPECT_EQ("<testing>&gt;</testing>", builder.BuiltElement()->Str());
}
TEST(XmlBuilderTest, TestText2) {
XmlBuilder builder;
XmlParser::ParseXml(&builder, "<testing>&lt;>&amp;&quot;</testing>");
EXPECT_EQ("<testing>&lt;&gt;&amp;\"</testing>",
builder.BuiltElement()->Str());
}
TEST(XmlBuilderTest, TestText3) {
XmlBuilder builder;
XmlParser::ParseXml(&builder, "<testing>so &lt;important&gt;</testing>");
EXPECT_EQ("<testing>so &lt;important&gt;</testing>",
builder.BuiltElement()->Str());
}
TEST(XmlBuilderTest, TestText4) {
XmlBuilder builder;
XmlParser::ParseXml(&builder, "<testing>&lt;important&gt;, yes</testing>");
EXPECT_EQ("<testing>&lt;important&gt;, yes</testing>",
builder.BuiltElement()->Str());
}
TEST(XmlBuilderTest, TestText5) {
XmlBuilder builder;
XmlParser::ParseXml(&builder,
"<testing>importance &amp;&lt;important&gt;&amp;</testing>");
EXPECT_EQ("<testing>importance &amp;&lt;important&gt;&amp;</testing>",
builder.BuiltElement()->Str());
}
TEST(XmlBuilderTest, TestNamespace1) {
XmlBuilder builder;
XmlParser::ParseXml(&builder, "<testing xmlns='foo'/>");
EXPECT_EQ("<testing xmlns=\"foo\"/>", builder.BuiltElement()->Str());
}
TEST(XmlBuilderTest, TestNamespace2) {
XmlBuilder builder;
XmlParser::ParseXml(&builder, "<testing xmlns:a='foo' a:b='c'/>");
EXPECT_EQ("<testing xmlns:a=\"foo\" a:b=\"c\"/>",
builder.BuiltElement()->Str());
}
TEST(XmlBuilderTest, TestNamespace3) {
XmlBuilder builder;
XmlParser::ParseXml(&builder, "<testing xmlns:a=''/>");
EXPECT_TRUE(NULL == builder.BuiltElement());
}
TEST(XmlBuilderTest, TestNamespace4) {
XmlBuilder builder;
XmlParser::ParseXml(&builder, "<testing a:b='c'/>");
EXPECT_TRUE(NULL == builder.BuiltElement());
}
TEST(XmlBuilderTest, TestAttrCollision1) {
XmlBuilder builder;
XmlParser::ParseXml(&builder, "<testing a='first' a='second'/>");
EXPECT_TRUE(NULL == builder.BuiltElement());
}
TEST(XmlBuilderTest, TestAttrCollision2) {
XmlBuilder builder;
XmlParser::ParseXml(&builder,
"<testing xmlns:a='foo' xmlns:b='foo' a:x='c' b:x='d'/>");
EXPECT_TRUE(NULL == builder.BuiltElement());
}
TEST(XmlBuilderTest, TestAttrCollision3) {
XmlBuilder builder;
XmlParser::ParseXml(&builder,
"<testing xmlns:a='foo'><nested xmlns:b='foo' a:x='c' b:x='d'/>"
"</testing>");
EXPECT_TRUE(NULL == builder.BuiltElement());
}

View File

@ -1,25 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/xmllite/xmlconstants.h"
namespace buzz {
const char STR_EMPTY[] = "";
const char NS_XML[] = "http://www.w3.org/XML/1998/namespace";
const char NS_XMLNS[] = "http://www.w3.org/2000/xmlns/";
const char STR_XMLNS[] = "xmlns";
const char STR_XML[] = "xml";
const char STR_VERSION[] = "version";
const char STR_ENCODING[] = "encoding";
const StaticQName QN_XMLNS = { STR_EMPTY, STR_XMLNS };
} // namespace buzz

View File

@ -1,30 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMLLITE_XMLCONSTANTS_H_
#define WEBRTC_LIBJINGLE_XMLLITE_XMLCONSTANTS_H_
#include "webrtc/libjingle/xmllite/qname.h"
namespace buzz {
extern const char STR_EMPTY[];
extern const char NS_XML[];
extern const char NS_XMLNS[];
extern const char STR_XMLNS[];
extern const char STR_XML[];
extern const char STR_VERSION[];
extern const char STR_ENCODING[];
extern const StaticQName QN_XMLNS;
} // namespace buzz
#endif // WEBRTC_LIBJINGLE_XMLLITE_XMLCONSTANTS_H_

View File

@ -1,496 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include <ostream>
#include <sstream>
#include <string>
#include <vector>
#include "webrtc/libjingle/xmllite/qname.h"
#include "webrtc/libjingle/xmllite/xmlbuilder.h"
#include "webrtc/libjingle/xmllite/xmlconstants.h"
#include "webrtc/libjingle/xmllite/xmlparser.h"
#include "webrtc/libjingle/xmllite/xmlprinter.h"
#include "webrtc/base/common.h"
namespace buzz {
XmlChild::~XmlChild() {
}
bool XmlText::IsTextImpl() const {
return true;
}
XmlElement* XmlText::AsElementImpl() const {
return NULL;
}
XmlText* XmlText::AsTextImpl() const {
return const_cast<XmlText *>(this);
}
void XmlText::SetText(const std::string& text) {
text_ = text;
}
void XmlText::AddParsedText(const char* buf, int len) {
text_.append(buf, len);
}
void XmlText::AddText(const std::string& text) {
text_ += text;
}
XmlText::~XmlText() {
}
XmlElement::XmlElement(const QName& name) :
name_(name),
first_attr_(NULL),
last_attr_(NULL),
first_child_(NULL),
last_child_(NULL),
cdata_(false) {
}
XmlElement::XmlElement(const XmlElement& elt) :
XmlChild(),
name_(elt.name_),
first_attr_(NULL),
last_attr_(NULL),
first_child_(NULL),
last_child_(NULL),
cdata_(false) {
// copy attributes
XmlAttr* attr;
XmlAttr ** plast_attr = &first_attr_;
XmlAttr* newAttr = NULL;
for (attr = elt.first_attr_; attr; attr = attr->NextAttr()) {
newAttr = new XmlAttr(*attr);
*plast_attr = newAttr;
plast_attr = &(newAttr->next_attr_);
}
last_attr_ = newAttr;
// copy children
XmlChild* pChild;
XmlChild ** ppLast = &first_child_;
XmlChild* newChild = NULL;
for (pChild = elt.first_child_; pChild; pChild = pChild->NextChild()) {
if (pChild->IsText()) {
newChild = new XmlText(*(pChild->AsText()));
} else {
newChild = new XmlElement(*(pChild->AsElement()));
}
*ppLast = newChild;
ppLast = &(newChild->next_child_);
}
last_child_ = newChild;
cdata_ = elt.cdata_;
}
XmlElement::XmlElement(const QName& name, bool useDefaultNs) :
name_(name),
first_attr_(useDefaultNs ? new XmlAttr(QN_XMLNS, name.Namespace()) : NULL),
last_attr_(first_attr_),
first_child_(NULL),
last_child_(NULL),
cdata_(false) {
}
bool XmlElement::IsTextImpl() const {
return false;
}
XmlElement* XmlElement::AsElementImpl() const {
return const_cast<XmlElement *>(this);
}
XmlText* XmlElement::AsTextImpl() const {
return NULL;
}
const std::string XmlElement::BodyText() const {
if (first_child_ && first_child_->IsText() && last_child_ == first_child_) {
return first_child_->AsText()->Text();
}
return std::string();
}
void XmlElement::SetBodyText(const std::string& text) {
if (text.empty()) {
ClearChildren();
} else if (first_child_ == NULL) {
AddText(text);
} else if (first_child_->IsText() && last_child_ == first_child_) {
first_child_->AsText()->SetText(text);
} else {
ClearChildren();
AddText(text);
}
}
const QName XmlElement::FirstElementName() const {
const XmlElement* element = FirstElement();
if (element == NULL)
return QName();
return element->Name();
}
XmlAttr* XmlElement::FirstAttr() {
return first_attr_;
}
const std::string XmlElement::Attr(const StaticQName& name) const {
XmlAttr* attr;
for (attr = first_attr_; attr; attr = attr->next_attr_) {
if (attr->name_ == name)
return attr->value_;
}
return std::string();
}
const std::string XmlElement::Attr(const QName& name) const {
XmlAttr* attr;
for (attr = first_attr_; attr; attr = attr->next_attr_) {
if (attr->name_ == name)
return attr->value_;
}
return std::string();
}
bool XmlElement::HasAttr(const StaticQName& name) const {
XmlAttr* attr;
for (attr = first_attr_; attr; attr = attr->next_attr_) {
if (attr->name_ == name)
return true;
}
return false;
}
bool XmlElement::HasAttr(const QName& name) const {
XmlAttr* attr;
for (attr = first_attr_; attr; attr = attr->next_attr_) {
if (attr->name_ == name)
return true;
}
return false;
}
void XmlElement::SetAttr(const QName& name, const std::string& value) {
XmlAttr* attr;
for (attr = first_attr_; attr; attr = attr->next_attr_) {
if (attr->name_ == name)
break;
}
if (!attr) {
attr = new XmlAttr(name, value);
if (last_attr_)
last_attr_->next_attr_ = attr;
else
first_attr_ = attr;
last_attr_ = attr;
return;
}
attr->value_ = value;
}
void XmlElement::ClearAttr(const QName& name) {
XmlAttr* attr;
XmlAttr* last_attr = NULL;
for (attr = first_attr_; attr; attr = attr->next_attr_) {
if (attr->name_ == name)
break;
last_attr = attr;
}
if (!attr)
return;
if (!last_attr)
first_attr_ = attr->next_attr_;
else
last_attr->next_attr_ = attr->next_attr_;
if (last_attr_ == attr)
last_attr_ = last_attr;
delete attr;
}
XmlChild* XmlElement::FirstChild() {
return first_child_;
}
XmlElement* XmlElement::FirstElement() {
XmlChild* pChild;
for (pChild = first_child_; pChild; pChild = pChild->next_child_) {
if (!pChild->IsText())
return pChild->AsElement();
}
return NULL;
}
XmlElement* XmlElement::NextElement() {
XmlChild* pChild;
for (pChild = next_child_; pChild; pChild = pChild->next_child_) {
if (!pChild->IsText())
return pChild->AsElement();
}
return NULL;
}
XmlElement* XmlElement::FirstWithNamespace(const std::string& ns) {
XmlChild* pChild;
for (pChild = first_child_; pChild; pChild = pChild->next_child_) {
if (!pChild->IsText() && pChild->AsElement()->Name().Namespace() == ns)
return pChild->AsElement();
}
return NULL;
}
XmlElement *
XmlElement::NextWithNamespace(const std::string& ns) {
XmlChild* pChild;
for (pChild = next_child_; pChild; pChild = pChild->next_child_) {
if (!pChild->IsText() && pChild->AsElement()->Name().Namespace() == ns)
return pChild->AsElement();
}
return NULL;
}
XmlElement *
XmlElement::FirstNamed(const QName& name) {
XmlChild* pChild;
for (pChild = first_child_; pChild; pChild = pChild->next_child_) {
if (!pChild->IsText() && pChild->AsElement()->Name() == name)
return pChild->AsElement();
}
return NULL;
}
XmlElement *
XmlElement::FirstNamed(const StaticQName& name) {
XmlChild* pChild;
for (pChild = first_child_; pChild; pChild = pChild->next_child_) {
if (!pChild->IsText() && pChild->AsElement()->Name() == name)
return pChild->AsElement();
}
return NULL;
}
XmlElement *
XmlElement::NextNamed(const QName& name) {
XmlChild* pChild;
for (pChild = next_child_; pChild; pChild = pChild->next_child_) {
if (!pChild->IsText() && pChild->AsElement()->Name() == name)
return pChild->AsElement();
}
return NULL;
}
XmlElement *
XmlElement::NextNamed(const StaticQName& name) {
XmlChild* pChild;
for (pChild = next_child_; pChild; pChild = pChild->next_child_) {
if (!pChild->IsText() && pChild->AsElement()->Name() == name)
return pChild->AsElement();
}
return NULL;
}
XmlElement* XmlElement::FindOrAddNamedChild(const QName& name) {
XmlElement* child = FirstNamed(name);
if (!child) {
child = new XmlElement(name);
AddElement(child);
}
return child;
}
const std::string XmlElement::TextNamed(const QName& name) const {
XmlChild* pChild;
for (pChild = first_child_; pChild; pChild = pChild->next_child_) {
if (!pChild->IsText() && pChild->AsElement()->Name() == name)
return pChild->AsElement()->BodyText();
}
return std::string();
}
void XmlElement::InsertChildAfter(XmlChild* predecessor, XmlChild* next) {
if (predecessor == NULL) {
next->next_child_ = first_child_;
first_child_ = next;
}
else {
next->next_child_ = predecessor->next_child_;
predecessor->next_child_ = next;
}
}
void XmlElement::RemoveChildAfter(XmlChild* predecessor) {
XmlChild* next;
if (predecessor == NULL) {
next = first_child_;
first_child_ = next->next_child_;
}
else {
next = predecessor->next_child_;
predecessor->next_child_ = next->next_child_;
}
if (last_child_ == next)
last_child_ = predecessor;
delete next;
}
void XmlElement::AddAttr(const QName& name, const std::string& value) {
ASSERT(!HasAttr(name));
XmlAttr ** pprev = last_attr_ ? &(last_attr_->next_attr_) : &first_attr_;
last_attr_ = (*pprev = new XmlAttr(name, value));
}
void XmlElement::AddAttr(const QName& name, const std::string& value,
int depth) {
XmlElement* element = this;
while (depth--) {
element = element->last_child_->AsElement();
}
element->AddAttr(name, value);
}
void XmlElement::AddParsedText(const char* cstr, int len) {
if (len == 0)
return;
if (last_child_ && last_child_->IsText()) {
last_child_->AsText()->AddParsedText(cstr, len);
return;
}
XmlChild ** pprev = last_child_ ? &(last_child_->next_child_) : &first_child_;
last_child_ = *pprev = new XmlText(cstr, len);
}
void XmlElement::AddCDATAText(const char* buf, int len) {
cdata_ = true;
AddParsedText(buf, len);
}
void XmlElement::AddText(const std::string& text) {
if (text == STR_EMPTY)
return;
if (last_child_ && last_child_->IsText()) {
last_child_->AsText()->AddText(text);
return;
}
XmlChild ** pprev = last_child_ ? &(last_child_->next_child_) : &first_child_;
last_child_ = *pprev = new XmlText(text);
}
void XmlElement::AddText(const std::string& text, int depth) {
// note: the first syntax is ambigious for msvc 6
// XmlElement* pel(this);
XmlElement* element = this;
while (depth--) {
element = element->last_child_->AsElement();
}
element->AddText(text);
}
void XmlElement::AddElement(XmlElement *child) {
if (child == NULL)
return;
XmlChild ** pprev = last_child_ ? &(last_child_->next_child_) : &first_child_;
*pprev = child;
last_child_ = child;
child->next_child_ = NULL;
}
void XmlElement::AddElement(XmlElement *child, int depth) {
XmlElement* element = this;
while (depth--) {
element = element->last_child_->AsElement();
}
element->AddElement(child);
}
void XmlElement::ClearNamedChildren(const QName& name) {
XmlChild* prev_child = NULL;
XmlChild* next_child;
XmlChild* child;
for (child = FirstChild(); child; child = next_child) {
next_child = child->NextChild();
if (!child->IsText() && child->AsElement()->Name() == name)
{
RemoveChildAfter(prev_child);
continue;
}
prev_child = child;
}
}
void XmlElement::ClearAttributes() {
XmlAttr* attr;
for (attr = first_attr_; attr; ) {
XmlAttr* to_delete = attr;
attr = attr->next_attr_;
delete to_delete;
}
first_attr_ = last_attr_ = NULL;
}
void XmlElement::ClearChildren() {
XmlChild* pchild;
for (pchild = first_child_; pchild; ) {
XmlChild* to_delete = pchild;
pchild = pchild->next_child_;
delete to_delete;
}
first_child_ = last_child_ = NULL;
}
std::string XmlElement::Str() const {
std::stringstream ss;
XmlPrinter::PrintXml(&ss, this);
return ss.str();
}
XmlElement* XmlElement::ForStr(const std::string& str) {
XmlBuilder builder;
XmlParser::ParseXml(&builder, str);
return builder.CreateElement();
}
XmlElement::~XmlElement() {
XmlAttr* attr;
for (attr = first_attr_; attr; ) {
XmlAttr* to_delete = attr;
attr = attr->next_attr_;
delete to_delete;
}
XmlChild* pchild;
for (pchild = first_child_; pchild; ) {
XmlChild* to_delete = pchild;
pchild = pchild->next_child_;
delete to_delete;
}
}
} // namespace buzz

View File

@ -1,233 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMLLITE_XMLELEMENT_H_
#define WEBRTC_LIBJINGLE_XMLLITE_XMLELEMENT_H_
#include <iosfwd>
#include <string>
#include "webrtc/libjingle/xmllite/qname.h"
namespace buzz {
class XmlChild;
class XmlText;
class XmlElement;
class XmlAttr;
class XmlChild {
public:
XmlChild* NextChild() { return next_child_; }
const XmlChild* NextChild() const { return next_child_; }
bool IsText() const { return IsTextImpl(); }
XmlElement* AsElement() { return AsElementImpl(); }
const XmlElement* AsElement() const { return AsElementImpl(); }
XmlText* AsText() { return AsTextImpl(); }
const XmlText* AsText() const { return AsTextImpl(); }
protected:
XmlChild() :
next_child_(NULL) {
}
virtual bool IsTextImpl() const = 0;
virtual XmlElement* AsElementImpl() const = 0;
virtual XmlText* AsTextImpl() const = 0;
virtual ~XmlChild();
private:
friend class XmlElement;
XmlChild(const XmlChild& noimpl);
XmlChild* next_child_;
};
class XmlText : public XmlChild {
public:
explicit XmlText(const std::string& text) :
XmlChild(),
text_(text) {
}
explicit XmlText(const XmlText& t) :
XmlChild(),
text_(t.text_) {
}
explicit XmlText(const char* cstr, size_t len) :
XmlChild(),
text_(cstr, len) {
}
virtual ~XmlText();
const std::string& Text() const { return text_; }
void SetText(const std::string& text);
void AddParsedText(const char* buf, int len);
void AddText(const std::string& text);
protected:
virtual bool IsTextImpl() const;
virtual XmlElement* AsElementImpl() const;
virtual XmlText* AsTextImpl() const;
private:
std::string text_;
};
class XmlAttr {
public:
XmlAttr* NextAttr() const { return next_attr_; }
const QName& Name() const { return name_; }
const std::string& Value() const { return value_; }
private:
friend class XmlElement;
explicit XmlAttr(const QName& name, const std::string& value) :
next_attr_(NULL),
name_(name),
value_(value) {
}
explicit XmlAttr(const XmlAttr& att) :
next_attr_(NULL),
name_(att.name_),
value_(att.value_) {
}
XmlAttr* next_attr_;
QName name_;
std::string value_;
};
class XmlElement : public XmlChild {
public:
explicit XmlElement(const QName& name);
explicit XmlElement(const QName& name, bool useDefaultNs);
explicit XmlElement(const XmlElement& elt);
virtual ~XmlElement();
const QName& Name() const { return name_; }
void SetName(const QName& name) { name_ = name; }
const std::string BodyText() const;
void SetBodyText(const std::string& text);
const QName FirstElementName() const;
XmlAttr* FirstAttr();
const XmlAttr* FirstAttr() const
{ return const_cast<XmlElement *>(this)->FirstAttr(); }
// Attr will return an empty string if the attribute isn't there:
// use HasAttr to test presence of an attribute.
const std::string Attr(const StaticQName& name) const;
const std::string Attr(const QName& name) const;
bool HasAttr(const StaticQName& name) const;
bool HasAttr(const QName& name) const;
void SetAttr(const QName& name, const std::string& value);
void ClearAttr(const QName& name);
XmlChild* FirstChild();
const XmlChild* FirstChild() const {
return const_cast<XmlElement *>(this)->FirstChild();
}
XmlElement* FirstElement();
const XmlElement* FirstElement() const {
return const_cast<XmlElement *>(this)->FirstElement();
}
XmlElement* NextElement();
const XmlElement* NextElement() const {
return const_cast<XmlElement *>(this)->NextElement();
}
XmlElement* FirstWithNamespace(const std::string& ns);
const XmlElement* FirstWithNamespace(const std::string& ns) const {
return const_cast<XmlElement *>(this)->FirstWithNamespace(ns);
}
XmlElement* NextWithNamespace(const std::string& ns);
const XmlElement* NextWithNamespace(const std::string& ns) const {
return const_cast<XmlElement *>(this)->NextWithNamespace(ns);
}
XmlElement* FirstNamed(const StaticQName& name);
const XmlElement* FirstNamed(const StaticQName& name) const {
return const_cast<XmlElement *>(this)->FirstNamed(name);
}
XmlElement* FirstNamed(const QName& name);
const XmlElement* FirstNamed(const QName& name) const {
return const_cast<XmlElement *>(this)->FirstNamed(name);
}
XmlElement* NextNamed(const StaticQName& name);
const XmlElement* NextNamed(const StaticQName& name) const {
return const_cast<XmlElement *>(this)->NextNamed(name);
}
XmlElement* NextNamed(const QName& name);
const XmlElement* NextNamed(const QName& name) const {
return const_cast<XmlElement *>(this)->NextNamed(name);
}
// Finds the first element named 'name'. If that element can't be found then
// adds one and returns it.
XmlElement* FindOrAddNamedChild(const QName& name);
const std::string TextNamed(const QName& name) const;
void InsertChildAfter(XmlChild* predecessor, XmlChild* new_child);
void RemoveChildAfter(XmlChild* predecessor);
void AddParsedText(const char* buf, int len);
// Note: CDATA is not supported by XMPP, therefore using this function will
// generate non-XMPP compatible XML.
void AddCDATAText(const char* buf, int len);
void AddText(const std::string& text);
void AddText(const std::string& text, int depth);
void AddElement(XmlElement* child);
void AddElement(XmlElement* child, int depth);
void AddAttr(const QName& name, const std::string& value);
void AddAttr(const QName& name, const std::string& value, int depth);
void ClearNamedChildren(const QName& name);
void ClearAttributes();
void ClearChildren();
static XmlElement* ForStr(const std::string& str);
std::string Str() const;
bool IsCDATA() const { return cdata_; }
protected:
virtual bool IsTextImpl() const;
virtual XmlElement* AsElementImpl() const;
virtual XmlText* AsTextImpl() const;
private:
QName name_;
XmlAttr* first_attr_;
XmlAttr* last_attr_;
XmlChild* first_child_;
XmlChild* last_child_;
bool cdata_;
};
} // namespace buzz
#endif // WEBRTC_LIBJINGLE_XMLLITE_XMLELEMENT_H_

View File

@ -1,258 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <iostream>
#include <sstream>
#include <string>
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/base/common.h"
#include "webrtc/base/gunit.h"
#include "webrtc/base/thread.h"
using buzz::QName;
using buzz::XmlAttr;
using buzz::XmlChild;
using buzz::XmlElement;
std::ostream& operator<<(std::ostream& os, const QName& name) {
os << name.Namespace() << ":" << name.LocalPart();
return os;
}
TEST(XmlElementTest, TestConstructors) {
XmlElement elt(QName("google:test", "first"));
EXPECT_EQ("<test:first xmlns:test=\"google:test\"/>", elt.Str());
XmlElement elt2(QName("google:test", "first"), true);
EXPECT_EQ("<first xmlns=\"google:test\"/>", elt2.Str());
}
TEST(XmlElementTest, TestAdd) {
XmlElement elt(QName("google:test", "root"), true);
elt.AddElement(new XmlElement(QName("google:test", "first")));
elt.AddElement(new XmlElement(QName("google:test", "nested")), 1);
elt.AddText("nested-value", 2);
elt.AddText("between-", 1);
elt.AddText("value", 1);
elt.AddElement(new XmlElement(QName("google:test", "nested2")), 1);
elt.AddElement(new XmlElement(QName("google:test", "second")));
elt.AddText("init-value", 1);
elt.AddElement(new XmlElement(QName("google:test", "nested3")), 1);
elt.AddText("trailing-value", 1);
// make sure it looks ok overall
EXPECT_EQ("<root xmlns=\"google:test\">"
"<first><nested>nested-value</nested>between-value<nested2/></first>"
"<second>init-value<nested3/>trailing-value</second></root>",
elt.Str());
// make sure text was concatenated
XmlChild * pchild =
elt.FirstChild()->AsElement()->FirstChild()->NextChild();
EXPECT_TRUE(pchild->IsText());
EXPECT_EQ("between-value", pchild->AsText()->Text());
}
TEST(XmlElementTest, TestAttrs) {
XmlElement elt(QName("", "root"));
elt.SetAttr(QName("", "a"), "avalue");
EXPECT_EQ("<root a=\"avalue\"/>", elt.Str());
elt.SetAttr(QName("", "b"), "bvalue");
EXPECT_EQ("<root a=\"avalue\" b=\"bvalue\"/>", elt.Str());
elt.SetAttr(QName("", "a"), "avalue2");
EXPECT_EQ("<root a=\"avalue2\" b=\"bvalue\"/>", elt.Str());
elt.SetAttr(QName("", "b"), "bvalue2");
EXPECT_EQ("<root a=\"avalue2\" b=\"bvalue2\"/>", elt.Str());
elt.SetAttr(QName("", "c"), "cvalue");
EXPECT_EQ("<root a=\"avalue2\" b=\"bvalue2\" c=\"cvalue\"/>", elt.Str());
XmlAttr * patt = elt.FirstAttr();
EXPECT_EQ(QName("", "a"), patt->Name());
EXPECT_EQ("avalue2", patt->Value());
patt = patt->NextAttr();
EXPECT_EQ(QName("", "b"), patt->Name());
EXPECT_EQ("bvalue2", patt->Value());
patt = patt->NextAttr();
EXPECT_EQ(QName("", "c"), patt->Name());
EXPECT_EQ("cvalue", patt->Value());
patt = patt->NextAttr();
EXPECT_TRUE(NULL == patt);
EXPECT_TRUE(elt.HasAttr(QName("", "a")));
EXPECT_TRUE(elt.HasAttr(QName("", "b")));
EXPECT_TRUE(elt.HasAttr(QName("", "c")));
EXPECT_FALSE(elt.HasAttr(QName("", "d")));
elt.SetAttr(QName("", "d"), "dvalue");
EXPECT_EQ("<root a=\"avalue2\" b=\"bvalue2\" c=\"cvalue\" d=\"dvalue\"/>",
elt.Str());
EXPECT_TRUE(elt.HasAttr(QName("", "d")));
elt.ClearAttr(QName("", "z")); // not found, no effect
EXPECT_EQ("<root a=\"avalue2\" b=\"bvalue2\" c=\"cvalue\" d=\"dvalue\"/>",
elt.Str());
elt.ClearAttr(QName("", "b"));
EXPECT_EQ("<root a=\"avalue2\" c=\"cvalue\" d=\"dvalue\"/>", elt.Str());
elt.ClearAttr(QName("", "a"));
EXPECT_EQ("<root c=\"cvalue\" d=\"dvalue\"/>", elt.Str());
elt.ClearAttr(QName("", "d"));
EXPECT_EQ("<root c=\"cvalue\"/>", elt.Str());
elt.ClearAttr(QName("", "c"));
EXPECT_EQ("<root/>", elt.Str());
}
TEST(XmlElementTest, TestBodyText) {
XmlElement elt(QName("", "root"));
EXPECT_EQ("", elt.BodyText());
elt.AddText("body value text");
EXPECT_EQ("body value text", elt.BodyText());
elt.ClearChildren();
elt.AddText("more value ");
elt.AddText("text");
EXPECT_EQ("more value text", elt.BodyText());
elt.ClearChildren();
elt.AddText("decoy");
elt.AddElement(new XmlElement(QName("", "dummy")));
EXPECT_EQ("", elt.BodyText());
elt.SetBodyText("replacement");
EXPECT_EQ("replacement", elt.BodyText());
elt.SetBodyText("");
EXPECT_TRUE(NULL == elt.FirstChild());
elt.SetBodyText("goodbye");
EXPECT_EQ("goodbye", elt.FirstChild()->AsText()->Text());
EXPECT_EQ("goodbye", elt.BodyText());
}
TEST(XmlElementTest, TestCopyConstructor) {
XmlElement * element = XmlElement::ForStr(
"<root xmlns='test-foo'>This is a <em a='avalue' b='bvalue'>"
"little <b>little</b></em> test</root>");
XmlElement * pelCopy = new XmlElement(*element);
EXPECT_EQ("<root xmlns=\"test-foo\">This is a <em a=\"avalue\" b=\"bvalue\">"
"little <b>little</b></em> test</root>", pelCopy->Str());
delete pelCopy;
pelCopy = new XmlElement(*(element->FirstChild()->NextChild()->AsElement()));
EXPECT_EQ("<foo:em a=\"avalue\" b=\"bvalue\" xmlns:foo=\"test-foo\">"
"little <foo:b>little</foo:b></foo:em>", pelCopy->Str());
XmlAttr * patt = pelCopy->FirstAttr();
EXPECT_EQ(QName("", "a"), patt->Name());
EXPECT_EQ("avalue", patt->Value());
patt = patt->NextAttr();
EXPECT_EQ(QName("", "b"), patt->Name());
EXPECT_EQ("bvalue", patt->Value());
patt = patt->NextAttr();
EXPECT_TRUE(NULL == patt);
delete pelCopy;
delete element;
}
TEST(XmlElementTest, TestNameSearch) {
XmlElement * element = XmlElement::ForStr(
"<root xmlns='test-foo'>"
"<firstname>George</firstname>"
"<middlename>X.</middlename>"
"some text"
"<lastname>Harrison</lastname>"
"<firstname>John</firstname>"
"<middlename>Y.</middlename>"
"<lastname>Lennon</lastname>"
"</root>");
EXPECT_TRUE(NULL ==
element->FirstNamed(QName("", "firstname")));
EXPECT_EQ(element->FirstChild(),
element->FirstNamed(QName("test-foo", "firstname")));
EXPECT_EQ(element->FirstChild()->NextChild(),
element->FirstNamed(QName("test-foo", "middlename")));
EXPECT_EQ(element->FirstElement()->NextElement(),
element->FirstNamed(QName("test-foo", "middlename")));
EXPECT_EQ("Harrison",
element->TextNamed(QName("test-foo", "lastname")));
EXPECT_EQ(element->FirstElement()->NextElement()->NextElement(),
element->FirstNamed(QName("test-foo", "lastname")));
EXPECT_EQ("John", element->FirstNamed(QName("test-foo", "firstname"))->
NextNamed(QName("test-foo", "firstname"))->BodyText());
EXPECT_EQ("Y.", element->FirstNamed(QName("test-foo", "middlename"))->
NextNamed(QName("test-foo", "middlename"))->BodyText());
EXPECT_EQ("Lennon", element->FirstNamed(QName("test-foo", "lastname"))->
NextNamed(QName("test-foo", "lastname"))->BodyText());
EXPECT_TRUE(NULL == element->FirstNamed(QName("test-foo", "firstname"))->
NextNamed(QName("test-foo", "firstname"))->
NextNamed(QName("test-foo", "firstname")));
delete element;
}
class XmlElementCreatorThread : public rtc::Thread {
public:
XmlElementCreatorThread(int count, buzz::QName qname) :
count_(count), qname_(qname) {}
virtual ~XmlElementCreatorThread() {
Stop();
}
virtual void Run() {
std::vector<buzz::XmlElement*> elems;
for (int i = 0; i < count_; i++) {
elems.push_back(new XmlElement(qname_));
}
for (int i = 0; i < count_; i++) {
delete elems[i];
}
}
private:
int count_;
buzz::QName qname_;
};
// If XmlElement creation and destruction isn't thread safe,
// this test should crash.
TEST(XmlElementTest, TestMultithread) {
int thread_count = 2; // Was 100, but that's too slow.
int elem_count = 100; // Was 100000, but that's too slow.
buzz::QName qname("foo", "bar");
std::vector<rtc::Thread*> threads;
for (int i = 0; i < thread_count; i++) {
threads.push_back(
new XmlElementCreatorThread(elem_count, qname));
threads[i]->Start();
}
for (int i = 0; i < thread_count; i++) {
threads[i]->Stop();
delete threads[i];
}
}

View File

@ -1,178 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/xmllite/xmlnsstack.h"
#include <sstream>
#include <string>
#include <vector>
#include "webrtc/libjingle/xmllite/xmlconstants.h"
#include "webrtc/libjingle/xmllite/xmlelement.h"
namespace buzz {
XmlnsStack::XmlnsStack() :
pxmlnsStack_(new std::vector<std::string>),
pxmlnsDepthStack_(new std::vector<size_t>) {
}
XmlnsStack::~XmlnsStack() {}
void XmlnsStack::PushFrame() {
pxmlnsDepthStack_->push_back(pxmlnsStack_->size());
}
void XmlnsStack::PopFrame() {
size_t prev_size = pxmlnsDepthStack_->back();
pxmlnsDepthStack_->pop_back();
if (prev_size < pxmlnsStack_->size()) {
pxmlnsStack_->erase(pxmlnsStack_->begin() + prev_size,
pxmlnsStack_->end());
}
}
std::pair<std::string, bool> XmlnsStack::NsForPrefix(
const std::string& prefix) {
if (prefix.length() >= 3 &&
(prefix[0] == 'x' || prefix[0] == 'X') &&
(prefix[1] == 'm' || prefix[1] == 'M') &&
(prefix[2] == 'l' || prefix[2] == 'L')) {
if (prefix == "xml")
return std::make_pair(NS_XML, true);
if (prefix == "xmlns")
return std::make_pair(NS_XMLNS, true);
// Other names with xml prefix are illegal.
return std::make_pair(STR_EMPTY, false);
}
std::vector<std::string>::iterator pos;
for (pos = pxmlnsStack_->end(); pos > pxmlnsStack_->begin(); ) {
pos -= 2;
if (*pos == prefix)
return std::make_pair(*(pos + 1), true);
}
if (prefix == STR_EMPTY)
return std::make_pair(STR_EMPTY, true); // default namespace
return std::make_pair(STR_EMPTY, false); // none found
}
bool XmlnsStack::PrefixMatchesNs(const std::string& prefix,
const std::string& ns) {
const std::pair<std::string, bool> match = NsForPrefix(prefix);
return match.second && (match.first == ns);
}
std::pair<std::string, bool> XmlnsStack::PrefixForNs(const std::string& ns,
bool isattr) {
if (ns == NS_XML)
return std::make_pair(std::string("xml"), true);
if (ns == NS_XMLNS)
return std::make_pair(std::string("xmlns"), true);
if (isattr ? ns == STR_EMPTY : PrefixMatchesNs(STR_EMPTY, ns))
return std::make_pair(STR_EMPTY, true);
std::vector<std::string>::iterator pos;
for (pos = pxmlnsStack_->end(); pos > pxmlnsStack_->begin(); ) {
pos -= 2;
if (*(pos + 1) == ns &&
(!isattr || !pos->empty()) && PrefixMatchesNs(*pos, ns))
return std::make_pair(*pos, true);
}
return std::make_pair(STR_EMPTY, false); // none found
}
std::string XmlnsStack::FormatQName(const QName& name, bool isAttr) {
std::string prefix(PrefixForNs(name.Namespace(), isAttr).first);
if (prefix == STR_EMPTY)
return name.LocalPart();
else
return prefix + ':' + name.LocalPart();
}
void XmlnsStack::AddXmlns(const std::string & prefix, const std::string & ns) {
pxmlnsStack_->push_back(prefix);
pxmlnsStack_->push_back(ns);
}
void XmlnsStack::RemoveXmlns() {
pxmlnsStack_->pop_back();
pxmlnsStack_->pop_back();
}
static bool IsAsciiLetter(char ch) {
return ((ch >= 'a' && ch <= 'z') ||
(ch >= 'A' && ch <= 'Z'));
}
static std::string AsciiLower(const std::string & s) {
std::string result(s);
size_t i;
for (i = 0; i < result.length(); i++) {
if (result[i] >= 'A' && result[i] <= 'Z')
result[i] += 'a' - 'A';
}
return result;
}
static std::string SuggestPrefix(const std::string & ns) {
size_t len = ns.length();
size_t i = ns.find_last_of('.');
if (i != std::string::npos && len - i <= 4 + 1)
len = i; // chop off ".html" or ".xsd" or ".?{0,4}"
size_t last = len;
while (last > 0) {
last -= 1;
if (IsAsciiLetter(ns[last])) {
size_t first = last;
last += 1;
while (first > 0) {
if (!IsAsciiLetter(ns[first - 1]))
break;
first -= 1;
}
if (last - first > 4)
last = first + 3;
std::string candidate(AsciiLower(ns.substr(first, last - first)));
if (candidate.find("xml") != 0)
return candidate;
break;
}
}
return "ns";
}
std::pair<std::string, bool> XmlnsStack::AddNewPrefix(const std::string& ns,
bool isAttr) {
if (PrefixForNs(ns, isAttr).second)
return std::make_pair(STR_EMPTY, false);
std::string base(SuggestPrefix(ns));
std::string result(base);
int i = 2;
while (NsForPrefix(result).second) {
std::stringstream ss;
ss << base;
ss << (i++);
ss >> result;
}
AddXmlns(result, ns);
return std::make_pair(result, true);
}
void XmlnsStack::Reset() {
pxmlnsStack_->clear();
pxmlnsDepthStack_->clear();
}
}

View File

@ -1,45 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMLLITE_XMLNSSTACK_H_
#define WEBRTC_LIBJINGLE_XMLLITE_XMLNSSTACK_H_
#include <memory>
#include <string>
#include <vector>
#include "webrtc/libjingle/xmllite/qname.h"
namespace buzz {
class XmlnsStack {
public:
XmlnsStack();
~XmlnsStack();
void AddXmlns(const std::string& prefix, const std::string& ns);
void RemoveXmlns();
void PushFrame();
void PopFrame();
void Reset();
std::pair<std::string, bool> NsForPrefix(const std::string& prefix);
bool PrefixMatchesNs(const std::string & prefix, const std::string & ns);
std::pair<std::string, bool> PrefixForNs(const std::string& ns, bool isAttr);
std::pair<std::string, bool> AddNewPrefix(const std::string& ns, bool isAttr);
std::string FormatQName(const QName & name, bool isAttr);
private:
std::unique_ptr<std::vector<std::string> > pxmlnsStack_;
std::unique_ptr<std::vector<size_t> > pxmlnsDepthStack_;
};
}
#endif // WEBRTC_LIBJINGLE_XMLLITE_XMLNSSTACK_H_

View File

@ -1,241 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/xmllite/xmlnsstack.h"
#include <iostream>
#include <sstream>
#include <string>
#include "webrtc/libjingle/xmllite/xmlconstants.h"
#include "webrtc/base/common.h"
#include "webrtc/base/gunit.h"
using buzz::NS_XML;
using buzz::NS_XMLNS;
using buzz::QName;
using buzz::XmlnsStack;
TEST(XmlnsStackTest, TestBuiltin) {
XmlnsStack stack;
EXPECT_EQ(std::string(NS_XML), stack.NsForPrefix("xml").first);
EXPECT_EQ(std::string(NS_XMLNS), stack.NsForPrefix("xmlns").first);
EXPECT_EQ("", stack.NsForPrefix("").first);
EXPECT_EQ("xml", stack.PrefixForNs(NS_XML, false).first);
EXPECT_EQ("xmlns", stack.PrefixForNs(NS_XMLNS, false).first);
EXPECT_EQ("", stack.PrefixForNs("", false).first);
EXPECT_EQ("", stack.PrefixForNs("", true).first);
}
TEST(XmlnsStackTest, TestNsForPrefix) {
XmlnsStack stack;
stack.AddXmlns("pre1", "ns1");
stack.AddXmlns("pre2", "ns2");
stack.AddXmlns("pre1", "ns3");
stack.AddXmlns("", "ns4");
EXPECT_EQ("ns3", stack.NsForPrefix("pre1").first);
EXPECT_TRUE(stack.NsForPrefix("pre1").second);
EXPECT_EQ("ns2", stack.NsForPrefix("pre2").first);
EXPECT_EQ("ns4", stack.NsForPrefix("").first);
EXPECT_EQ("", stack.NsForPrefix("pre3").first);
EXPECT_FALSE(stack.NsForPrefix("pre3").second);
}
TEST(XmlnsStackTest, TestPrefixForNs) {
XmlnsStack stack;
stack.AddXmlns("pre1", "ns1");
stack.AddXmlns("pre2", "ns2");
stack.AddXmlns("pre1", "ns3");
stack.AddXmlns("pre3", "ns2");
stack.AddXmlns("pre4", "ns4");
stack.AddXmlns("", "ns4");
EXPECT_EQ("", stack.PrefixForNs("ns1", false).first);
EXPECT_FALSE(stack.PrefixForNs("ns1", false).second);
EXPECT_EQ("", stack.PrefixForNs("ns1", true).first);
EXPECT_FALSE(stack.PrefixForNs("ns1", true).second);
EXPECT_EQ("pre3", stack.PrefixForNs("ns2", false).first);
EXPECT_TRUE(stack.PrefixForNs("ns2", false).second);
EXPECT_EQ("pre3", stack.PrefixForNs("ns2", true).first);
EXPECT_TRUE(stack.PrefixForNs("ns2", true).second);
EXPECT_EQ("pre1", stack.PrefixForNs("ns3", false).first);
EXPECT_EQ("pre1", stack.PrefixForNs("ns3", true).first);
EXPECT_EQ("", stack.PrefixForNs("ns4", false).first);
EXPECT_TRUE(stack.PrefixForNs("ns4", false).second);
EXPECT_EQ("pre4", stack.PrefixForNs("ns4", true).first);
EXPECT_EQ("", stack.PrefixForNs("ns5", false).first);
EXPECT_FALSE(stack.PrefixForNs("ns5", false).second);
EXPECT_EQ("", stack.PrefixForNs("ns5", true).first);
EXPECT_EQ("", stack.PrefixForNs("", false).first);
EXPECT_EQ("", stack.PrefixForNs("", true).first);
stack.AddXmlns("", "ns6");
EXPECT_EQ("", stack.PrefixForNs("ns6", false).first);
EXPECT_TRUE(stack.PrefixForNs("ns6", false).second);
EXPECT_EQ("", stack.PrefixForNs("ns6", true).first);
EXPECT_FALSE(stack.PrefixForNs("ns6", true).second);
}
TEST(XmlnsStackTest, TestFrames) {
XmlnsStack stack;
stack.PushFrame();
stack.AddXmlns("pre1", "ns1");
stack.AddXmlns("pre2", "ns2");
stack.PushFrame();
stack.AddXmlns("pre1", "ns3");
stack.AddXmlns("pre3", "ns2");
stack.AddXmlns("pre4", "ns4");
stack.PushFrame();
stack.PushFrame();
stack.AddXmlns("", "ns4");
// basic test
EXPECT_EQ("ns3", stack.NsForPrefix("pre1").first);
EXPECT_EQ("ns2", stack.NsForPrefix("pre2").first);
EXPECT_EQ("ns2", stack.NsForPrefix("pre3").first);
EXPECT_EQ("ns4", stack.NsForPrefix("pre4").first);
EXPECT_EQ("", stack.NsForPrefix("pre5").first);
EXPECT_FALSE(stack.NsForPrefix("pre5").second);
EXPECT_EQ("ns4", stack.NsForPrefix("").first);
EXPECT_TRUE(stack.NsForPrefix("").second);
// pop the default xmlns definition
stack.PopFrame();
EXPECT_EQ("ns3", stack.NsForPrefix("pre1").first);
EXPECT_EQ("ns2", stack.NsForPrefix("pre2").first);
EXPECT_EQ("ns2", stack.NsForPrefix("pre3").first);
EXPECT_EQ("ns4", stack.NsForPrefix("pre4").first);
EXPECT_EQ("", stack.NsForPrefix("pre5").first);
EXPECT_FALSE(stack.NsForPrefix("pre5").second);
EXPECT_EQ("", stack.NsForPrefix("").first);
EXPECT_TRUE(stack.NsForPrefix("").second);
// pop empty frame (nop)
stack.PopFrame();
EXPECT_EQ("ns3", stack.NsForPrefix("pre1").first);
EXPECT_EQ("ns2", stack.NsForPrefix("pre2").first);
EXPECT_EQ("ns2", stack.NsForPrefix("pre3").first);
EXPECT_EQ("ns4", stack.NsForPrefix("pre4").first);
EXPECT_EQ("", stack.NsForPrefix("pre5").first);
EXPECT_FALSE(stack.NsForPrefix("pre5").second);
EXPECT_EQ("", stack.NsForPrefix("").first);
EXPECT_TRUE(stack.NsForPrefix("").second);
// pop frame with three defs
stack.PopFrame();
EXPECT_EQ("ns1", stack.NsForPrefix("pre1").first);
EXPECT_EQ("ns2", stack.NsForPrefix("pre2").first);
EXPECT_EQ("", stack.NsForPrefix("pre3").first);
EXPECT_FALSE(stack.NsForPrefix("pre3").second);
EXPECT_EQ("", stack.NsForPrefix("pre4").first);
EXPECT_FALSE(stack.NsForPrefix("pre4").second);
EXPECT_EQ("", stack.NsForPrefix("pre5").first);
EXPECT_FALSE(stack.NsForPrefix("pre5").second);
EXPECT_EQ("", stack.NsForPrefix("").first);
EXPECT_TRUE(stack.NsForPrefix("").second);
// pop frame with last two defs
stack.PopFrame();
EXPECT_FALSE(stack.NsForPrefix("pre1").second);
EXPECT_FALSE(stack.NsForPrefix("pre2").second);
EXPECT_FALSE(stack.NsForPrefix("pre3").second);
EXPECT_FALSE(stack.NsForPrefix("pre4").second);
EXPECT_FALSE(stack.NsForPrefix("pre5").second);
EXPECT_TRUE(stack.NsForPrefix("").second);
EXPECT_EQ("", stack.NsForPrefix("pre1").first);
EXPECT_EQ("", stack.NsForPrefix("pre2").first);
EXPECT_EQ("", stack.NsForPrefix("pre3").first);
EXPECT_EQ("", stack.NsForPrefix("pre4").first);
EXPECT_EQ("", stack.NsForPrefix("pre5").first);
EXPECT_EQ("", stack.NsForPrefix("").first);
}
TEST(XmlnsStackTest, TestAddNewPrefix) {
XmlnsStack stack;
// builtin namespaces cannot be added
EXPECT_FALSE(stack.AddNewPrefix("", true).second);
EXPECT_FALSE(stack.AddNewPrefix("", false).second);
EXPECT_FALSE(stack.AddNewPrefix(NS_XML, true).second);
EXPECT_FALSE(stack.AddNewPrefix(NS_XML, false).second);
EXPECT_FALSE(stack.AddNewPrefix(NS_XMLNS, true).second);
EXPECT_FALSE(stack.AddNewPrefix(NS_XMLNS, false).second);
// namespaces already added cannot be added again.
EXPECT_EQ("foo", stack.AddNewPrefix("http://a.b.com/foo.htm", true).first);
EXPECT_EQ("bare", stack.AddNewPrefix("http://a.b.com/bare", false).first);
EXPECT_EQ("z", stack.AddNewPrefix("z", false).first);
EXPECT_FALSE(stack.AddNewPrefix("http://a.b.com/foo.htm", true).second);
EXPECT_FALSE(stack.AddNewPrefix("http://a.b.com/bare", true).second);
EXPECT_FALSE(stack.AddNewPrefix("z", true).second);
EXPECT_FALSE(stack.AddNewPrefix("http://a.b.com/foo.htm", false).second);
EXPECT_FALSE(stack.AddNewPrefix("http://a.b.com/bare", false).second);
EXPECT_FALSE(stack.AddNewPrefix("z", false).second);
// default namespace usable by non-attributes only
stack.AddXmlns("", "http://my/default");
EXPECT_FALSE(stack.AddNewPrefix("http://my/default", false).second);
EXPECT_EQ("def", stack.AddNewPrefix("http://my/default", true).first);
// namespace cannot start with 'xml'
EXPECT_EQ("ns", stack.AddNewPrefix("http://a.b.com/xmltest", true).first);
EXPECT_EQ("ns2", stack.AddNewPrefix("xmlagain", false).first);
// verify added namespaces are still defined
EXPECT_EQ("http://a.b.com/foo.htm", stack.NsForPrefix("foo").first);
EXPECT_TRUE(stack.NsForPrefix("foo").second);
EXPECT_EQ("http://a.b.com/bare", stack.NsForPrefix("bare").first);
EXPECT_TRUE(stack.NsForPrefix("bare").second);
EXPECT_EQ("z", stack.NsForPrefix("z").first);
EXPECT_TRUE(stack.NsForPrefix("z").second);
EXPECT_EQ("http://my/default", stack.NsForPrefix("").first);
EXPECT_TRUE(stack.NsForPrefix("").second);
EXPECT_EQ("http://my/default", stack.NsForPrefix("def").first);
EXPECT_TRUE(stack.NsForPrefix("def").second);
EXPECT_EQ("http://a.b.com/xmltest", stack.NsForPrefix("ns").first);
EXPECT_TRUE(stack.NsForPrefix("ns").second);
EXPECT_EQ("xmlagain", stack.NsForPrefix("ns2").first);
EXPECT_TRUE(stack.NsForPrefix("ns2").second);
}
TEST(XmlnsStackTest, TestFormatQName) {
XmlnsStack stack;
stack.AddXmlns("pre1", "ns1");
stack.AddXmlns("pre2", "ns2");
stack.AddXmlns("pre1", "ns3");
stack.AddXmlns("", "ns4");
EXPECT_EQ("zip",
stack.FormatQName(QName("ns1", "zip"), false)); // no match
EXPECT_EQ("pre2:abracadabra",
stack.FormatQName(QName("ns2", "abracadabra"), false));
EXPECT_EQ("pre1:a",
stack.FormatQName(QName("ns3", "a"), false));
EXPECT_EQ("simple",
stack.FormatQName(QName("ns4", "simple"), false));
EXPECT_EQ("root",
stack.FormatQName(QName("", "root"), false)); // no match
EXPECT_EQ("zip",
stack.FormatQName(QName("ns1", "zip"), true)); // no match
EXPECT_EQ("pre2:abracadabra",
stack.FormatQName(QName("ns2", "abracadabra"), true));
EXPECT_EQ("pre1:a",
stack.FormatQName(QName("ns3", "a"), true));
EXPECT_EQ("simple",
stack.FormatQName(QName("ns4", "simple"), true)); // no match
EXPECT_EQ("root",
stack.FormatQName(QName("", "root"), true));
}

View File

@ -1,261 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/xmllite/xmlparser.h"
#include <string>
#include <vector>
#include "webrtc/libjingle/xmllite/xmlconstants.h"
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/libjingle/xmllite/xmlnsstack.h"
#include "webrtc/libjingle/xmllite/xmlnsstack.h"
#include "webrtc/base/common.h"
namespace buzz {
static void
StartElementCallback(void * userData, const char *name, const char **atts) {
(static_cast<XmlParser *>(userData))->ExpatStartElement(name, atts);
}
static void
EndElementCallback(void * userData, const char *name) {
(static_cast<XmlParser *>(userData))->ExpatEndElement(name);
}
static void
CharacterDataCallback(void * userData, const char *text, int len) {
(static_cast<XmlParser *>(userData))->ExpatCharacterData(text, len);
}
static void
XmlDeclCallback(void * userData, const char * ver, const char * enc, int st) {
(static_cast<XmlParser *>(userData))->ExpatXmlDecl(ver, enc, st);
}
XmlParser::XmlParser(XmlParseHandler *pxph) :
pxph_(pxph), sentError_(false) {
expat_ = XML_ParserCreate(NULL);
XML_SetUserData(expat_, this);
XML_SetElementHandler(expat_, StartElementCallback, EndElementCallback);
XML_SetCharacterDataHandler(expat_, CharacterDataCallback);
XML_SetXmlDeclHandler(expat_, XmlDeclCallback);
}
void
XmlParser::Reset() {
if (!XML_ParserReset(expat_, NULL)) {
XML_ParserFree(expat_);
expat_ = XML_ParserCreate(NULL);
}
XML_SetUserData(expat_, this);
XML_SetElementHandler(expat_, StartElementCallback, EndElementCallback);
XML_SetCharacterDataHandler(expat_, CharacterDataCallback);
XML_SetXmlDeclHandler(expat_, XmlDeclCallback);
context_.Reset();
sentError_ = false;
}
static bool
XmlParser_StartsWithXmlns(const char *name) {
return name[0] == 'x' &&
name[1] == 'm' &&
name[2] == 'l' &&
name[3] == 'n' &&
name[4] == 's';
}
void
XmlParser::ExpatStartElement(const char *name, const char **atts) {
if (context_.RaisedError() != XML_ERROR_NONE)
return;
const char **att;
context_.StartElement();
for (att = atts; *att; att += 2) {
if (XmlParser_StartsWithXmlns(*att)) {
if ((*att)[5] == '\0') {
context_.StartNamespace("", *(att + 1));
}
else if ((*att)[5] == ':') {
if (**(att + 1) == '\0') {
// In XML 1.0 empty namespace illegal with prefix (not in 1.1)
context_.RaiseError(XML_ERROR_SYNTAX);
return;
}
context_.StartNamespace((*att) + 6, *(att + 1));
}
}
}
context_.SetPosition(XML_GetCurrentLineNumber(expat_),
XML_GetCurrentColumnNumber(expat_),
XML_GetCurrentByteIndex(expat_));
pxph_->StartElement(&context_, name, atts);
}
void
XmlParser::ExpatEndElement(const char *name) {
if (context_.RaisedError() != XML_ERROR_NONE)
return;
context_.EndElement();
context_.SetPosition(XML_GetCurrentLineNumber(expat_),
XML_GetCurrentColumnNumber(expat_),
XML_GetCurrentByteIndex(expat_));
pxph_->EndElement(&context_, name);
}
void
XmlParser::ExpatCharacterData(const char *text, int len) {
if (context_.RaisedError() != XML_ERROR_NONE)
return;
context_.SetPosition(XML_GetCurrentLineNumber(expat_),
XML_GetCurrentColumnNumber(expat_),
XML_GetCurrentByteIndex(expat_));
pxph_->CharacterData(&context_, text, len);
}
void
XmlParser::ExpatXmlDecl(const char * ver, const char * enc, int standalone) {
if (context_.RaisedError() != XML_ERROR_NONE)
return;
if (ver && std::string("1.0") != ver) {
context_.RaiseError(XML_ERROR_SYNTAX);
return;
}
if (standalone == 0) {
context_.RaiseError(XML_ERROR_SYNTAX);
return;
}
if (enc && !((enc[0] == 'U' || enc[0] == 'u') &&
(enc[1] == 'T' || enc[1] == 't') &&
(enc[2] == 'F' || enc[2] == 'f') &&
enc[3] == '-' && enc[4] =='8')) {
context_.RaiseError(XML_ERROR_INCORRECT_ENCODING);
return;
}
}
bool
XmlParser::Parse(const char *data, size_t len, bool isFinal) {
if (sentError_)
return false;
if (XML_Parse(expat_, data, static_cast<int>(len), isFinal) !=
XML_STATUS_OK) {
context_.SetPosition(XML_GetCurrentLineNumber(expat_),
XML_GetCurrentColumnNumber(expat_),
XML_GetCurrentByteIndex(expat_));
context_.RaiseError(XML_GetErrorCode(expat_));
}
if (context_.RaisedError() != XML_ERROR_NONE) {
sentError_ = true;
pxph_->Error(&context_, context_.RaisedError());
return false;
}
return true;
}
XmlParser::~XmlParser() {
XML_ParserFree(expat_);
}
void
XmlParser::ParseXml(XmlParseHandler *pxph, std::string text) {
XmlParser parser(pxph);
parser.Parse(text.c_str(), text.length(), true);
}
XmlParser::ParseContext::ParseContext() :
xmlnsstack_(),
raised_(XML_ERROR_NONE),
line_number_(0),
column_number_(0),
byte_index_(0) {
}
void
XmlParser::ParseContext::StartNamespace(const char *prefix, const char *ns) {
xmlnsstack_.AddXmlns(*prefix ? prefix : STR_EMPTY, ns);
}
void
XmlParser::ParseContext::StartElement() {
xmlnsstack_.PushFrame();
}
void
XmlParser::ParseContext::EndElement() {
xmlnsstack_.PopFrame();
}
QName
XmlParser::ParseContext::ResolveQName(const char* qname, bool isAttr) {
const char *c;
for (c = qname; *c; ++c) {
if (*c == ':') {
const std::pair<std::string, bool> result =
xmlnsstack_.NsForPrefix(std::string(qname, c - qname));
if (!result.second)
return QName();
return QName(result.first, c + 1);
}
}
if (isAttr)
return QName(STR_EMPTY, qname);
std::pair<std::string, bool> result = xmlnsstack_.NsForPrefix(STR_EMPTY);
if (!result.second)
return QName();
return QName(result.first, qname);
}
void
XmlParser::ParseContext::Reset() {
xmlnsstack_.Reset();
raised_ = XML_ERROR_NONE;
}
void
XmlParser::ParseContext::SetPosition(int line, int column,
long byte_index) {
line_number_ = line;
column_number_ = column;
byte_index_ = byte_index;
}
void
XmlParser::ParseContext::GetPosition(unsigned long * line,
unsigned long * column,
unsigned long * byte_index) {
if (line != NULL) {
*line = static_cast<unsigned long>(line_number_);
}
if (column != NULL) {
*column = static_cast<unsigned long>(column_number_);
}
if (byte_index != NULL) {
*byte_index = static_cast<unsigned long>(byte_index_);
}
}
XmlParser::ParseContext::~ParseContext() {
}
} // namespace buzz

View File

@ -1,103 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMLLITE_XMLPARSER_H_
#define WEBRTC_LIBJINGLE_XMLLITE_XMLPARSER_H_
#include <string>
#include "webrtc/libjingle/xmllite/xmlnsstack.h"
#ifdef EXPAT_RELATIVE_PATH
#include "expat.h"
#else
#include "third_party/expat/v2_0_1/Source/lib/expat.h"
#endif // EXPAT_RELATIVE_PATH
struct XML_ParserStruct;
typedef struct XML_ParserStruct* XML_Parser;
namespace buzz {
class XmlParseHandler;
class XmlParseContext;
class XmlParser;
class XmlParseContext {
public:
virtual ~XmlParseContext() {}
virtual QName ResolveQName(const char * qname, bool isAttr) = 0;
virtual void RaiseError(XML_Error err) = 0;
virtual void GetPosition(unsigned long * line, unsigned long * column,
unsigned long * byte_index) = 0;
};
class XmlParseHandler {
public:
virtual ~XmlParseHandler() {}
virtual void StartElement(XmlParseContext * pctx,
const char * name, const char ** atts) = 0;
virtual void EndElement(XmlParseContext * pctx,
const char * name) = 0;
virtual void CharacterData(XmlParseContext * pctx,
const char * text, int len) = 0;
virtual void Error(XmlParseContext * pctx,
XML_Error errorCode) = 0;
};
class XmlParser {
public:
static void ParseXml(XmlParseHandler * pxph, std::string text);
explicit XmlParser(XmlParseHandler * pxph);
bool Parse(const char * data, size_t len, bool isFinal);
void Reset();
virtual ~XmlParser();
// expat callbacks
void ExpatStartElement(const char * name, const char ** atts);
void ExpatEndElement(const char * name);
void ExpatCharacterData(const char * text, int len);
void ExpatXmlDecl(const char * ver, const char * enc, int standalone);
private:
class ParseContext : public XmlParseContext {
public:
ParseContext();
virtual ~ParseContext();
virtual QName ResolveQName(const char * qname, bool isAttr);
virtual void RaiseError(XML_Error err) { if (!raised_) raised_ = err; }
virtual void GetPosition(unsigned long * line, unsigned long * column,
unsigned long * byte_index);
XML_Error RaisedError() { return raised_; }
void Reset();
void StartElement();
void EndElement();
void StartNamespace(const char * prefix, const char * ns);
void SetPosition(int line, int column, long byte_index);
private:
XmlnsStack xmlnsstack_;
XML_Error raised_;
XML_Size line_number_;
XML_Size column_number_;
XML_Index byte_index_;
};
ParseContext context_;
XML_Parser expat_;
XmlParseHandler * pxph_;
bool sentError_;
};
} // namespace buzz
#endif // WEBRTC_LIBJINGLE_XMLLITE_XMLPARSER_H_

View File

@ -1,285 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <iostream>
#include <sstream>
#include <string>
#include "webrtc/libjingle/xmllite/qname.h"
#include "webrtc/libjingle/xmllite/xmlparser.h"
#include "webrtc/base/common.h"
#include "webrtc/base/gunit.h"
using buzz::QName;
using buzz::XmlParser;
using buzz::XmlParseContext;
using buzz::XmlParseHandler;
class XmlParserTestHandler : public XmlParseHandler {
public:
virtual void StartElement(XmlParseContext * pctx,
const char * name, const char ** atts) {
ss_ << "START (" << pctx->ResolveQName(name, false).Merged();
while (*atts) {
ss_ << ", " << pctx->ResolveQName(*atts, true).Merged()
<< "='" << *(atts+1) << "'";
atts += 2;
}
ss_ << ") ";
}
virtual void EndElement(XmlParseContext * pctx, const char * name) {
RTC_UNUSED(pctx);
RTC_UNUSED(name);
ss_ << "END ";
}
virtual void CharacterData(XmlParseContext * pctx,
const char * text, int len) {
RTC_UNUSED(pctx);
ss_ << "TEXT (" << std::string(text, len) << ") ";
}
virtual void Error(XmlParseContext * pctx, XML_Error code) {
RTC_UNUSED(pctx);
ss_ << "ERROR (" << static_cast<int>(code) << ") ";
}
virtual ~XmlParserTestHandler() {
}
std::string Str() {
return ss_.str();
}
std::string StrClear() {
std::string result = ss_.str();
ss_.str("");
return result;
}
private:
std::stringstream ss_;
};
TEST(XmlParserTest, TestTrivial) {
XmlParserTestHandler handler;
XmlParser::ParseXml(&handler, "<testing/>");
EXPECT_EQ("START (testing) END ", handler.Str());
}
TEST(XmlParserTest, TestAttributes) {
{
XmlParserTestHandler handler;
XmlParser::ParseXml(&handler, "<testing a='b'/>");
EXPECT_EQ("START (testing, a='b') END ", handler.Str());
}
{
XmlParserTestHandler handler;
XmlParser::ParseXml(&handler, "<testing e='' long='some text'/>");
EXPECT_EQ("START (testing, e='', long='some text') END ", handler.Str());
}
}
TEST(XmlParserTest, TestNesting) {
{
XmlParserTestHandler handler;
XmlParser::ParseXml(&handler,
"<top><first/><second><third></third></second></top>");
EXPECT_EQ("START (top) START (first) END START (second) START (third) "
"END END END ", handler.Str());
}
{
XmlParserTestHandler handler;
XmlParser::ParseXml(&handler, "<top><fifth><deeper><and><deeper/></and>"
"<sibling><leaf/></sibling></deeper></fifth><first/><second>"
"<third></third></second></top>");
EXPECT_EQ("START (top) START (fifth) START (deeper) START (and) START "
"(deeper) END END START (sibling) START (leaf) END END END "
"END START (first) END START (second) START (third) END END END ",
handler.Str());
}
}
TEST(XmlParserTest, TestXmlDecl) {
{
XmlParserTestHandler handler;
XmlParser::ParseXml(&handler, "<?xml version=\"1.0\"?><testing/>");
EXPECT_EQ("START (testing) END ", handler.Str());
}
{
XmlParserTestHandler handler;
XmlParser::ParseXml(&handler,
"<?xml version=\"1.0\" encoding=\"utf-8\"?><testing/>");
EXPECT_EQ("START (testing) END ", handler.Str());
}
{
XmlParserTestHandler handler;
XmlParser::ParseXml(&handler,
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
"<testing/>");
EXPECT_EQ("START (testing) END ", handler.Str());
}
}
TEST(XmlParserTest, TestNamespace) {
{
XmlParserTestHandler handler;
XmlParser::ParseXml(&handler, "<top xmlns='my-namespace' a='b'/>");
EXPECT_EQ("START (my-namespace:top, xmlns='my-namespace', a='b') END ",
handler.Str());
}
{
XmlParserTestHandler handler;
XmlParser::ParseXml(&handler, "<foo:top xmlns:foo='my-namespace' "
"a='b' foo:c='d'/>");
EXPECT_EQ("START (my-namespace:top, "
"http://www.w3.org/2000/xmlns/:foo='my-namespace', "
"a='b', my-namespace:c='d') END ", handler.Str());
}
{
XmlParserTestHandler handler;
XmlParser::ParseXml(&handler, "<top><nested xmlns='my-namespace'><leaf/>"
"</nested><sibling/></top>");
EXPECT_EQ("START (top) START (my-namespace:nested, xmlns='my-namespace') "
"START (my-namespace:leaf) END END START (sibling) END END ",
handler.Str());
}
}
TEST(XmlParserTest, TestIncremental) {
XmlParserTestHandler handler;
XmlParser parser(&handler);
std::string fragment;
fragment = "<stream:stream";
parser.Parse(fragment.c_str(), fragment.length(), false);
EXPECT_EQ("", handler.StrClear());
fragment = " id=\"abcdefg\" xmlns=\"";
parser.Parse(fragment.c_str(), fragment.length(), false);
EXPECT_EQ("", handler.StrClear());
fragment = "j:c\" xmlns:stream='hm";
parser.Parse(fragment.c_str(), fragment.length(), false);
EXPECT_EQ("", handler.StrClear());
fragment = "ph'><test";
parser.Parse(fragment.c_str(), fragment.length(), false);
EXPECT_EQ("START (hmph:stream, id='abcdefg', xmlns='j:c', "
"http://www.w3.org/2000/xmlns/:stream='hmph') ", handler.StrClear());
fragment = "ing/><again/>abracad";
parser.Parse(fragment.c_str(), fragment.length(), false);
EXPECT_EQ("START (j:c:testing) END START (j:c:again) END TEXT (abracad) ",
handler.StrClear());
fragment = "abra</stream:";
parser.Parse(fragment.c_str(), fragment.length(), false);
EXPECT_EQ("TEXT (abra) ", handler.StrClear());
fragment = "stream>";
parser.Parse(fragment.c_str(), fragment.length(), false);
EXPECT_EQ("END ", handler.StrClear());
}
TEST(XmlParserTest, TestReset) {
{
XmlParserTestHandler handler;
XmlParser parser(&handler);
std::string fragment;
fragment = "<top><first/><second><third></third>";
parser.Parse(fragment.c_str(), fragment.length(), false);
EXPECT_EQ("START (top) START (first) END START (second) START (third) END ",
handler.StrClear());
parser.Reset();
fragment = "<tip><first/><second><third></third>";
parser.Parse(fragment.c_str(), fragment.length(), false);
EXPECT_EQ("START (tip) START (first) END START (second) START (third) END ",
handler.StrClear());
}
{
XmlParserTestHandler handler;
XmlParser parser(&handler);
std::string fragment;
fragment = "<top xmlns='m'>";
parser.Parse(fragment.c_str(), fragment.length(), false);
EXPECT_EQ("START (m:top, xmlns='m') ", handler.StrClear());
fragment = "<testing/><frag";
parser.Parse(fragment.c_str(), fragment.length(), false);
EXPECT_EQ("START (m:testing) END ", handler.StrClear());
parser.Reset();
fragment = "<testing><fragment/";
parser.Parse(fragment.c_str(), fragment.length(), false);
EXPECT_EQ("START (testing) ", handler.StrClear());
fragment = ">";
parser.Parse(fragment.c_str(), fragment.length(), false);
EXPECT_EQ("START (fragment) END ", handler.StrClear());
}
}
TEST(XmlParserTest, TestError) {
{
XmlParserTestHandler handler;
XmlParser::ParseXml(&handler, "junk");
EXPECT_EQ("ERROR (2) ", handler.Str());
}
{
XmlParserTestHandler handler;
XmlParser::ParseXml(&handler, "<top/> garbage ");
EXPECT_EQ("START (top) END ERROR (9) ", handler.Str());
}
{
XmlParserTestHandler handler;
XmlParser::ParseXml(&handler, "<-hm->");
EXPECT_EQ("ERROR (4) ", handler.Str());
}
{
XmlParserTestHandler handler;
XmlParser::ParseXml(&handler, "<hello>&foobar;</hello>");
EXPECT_EQ("START (hello) ERROR (11) ", handler.Str());
}
{
XmlParserTestHandler handler;
XmlParser::ParseXml(&handler,
"<!DOCTYPE HTML PUBLIC \"foobar\" \"barfoo\">");
EXPECT_EQ("ERROR (3) ", handler.Str());
}
{
// XmlParser requires utf-8
XmlParserTestHandler handler;
XmlParser::ParseXml(&handler,
"<?xml version=\"1.0\" encoding=\"iso-8859-1\"?><test/>");
EXPECT_EQ("ERROR (19) ", handler.Str());
}
{
// XmlParser requires version 1.0
XmlParserTestHandler handler;
XmlParser::ParseXml(&handler,
"<?xml version=\"2.0\"?><test/>");
EXPECT_EQ("ERROR (2) ", handler.Str());
}
{
// XmlParser requires standalone documents
XmlParserTestHandler handler;
XmlParser::ParseXml(&handler,
"<?xml version=\"1.0\" standalone=\"no\"?><test/>");
EXPECT_EQ("ERROR (2) ", handler.Str());
}
{
// XmlParser doesn't like empty namespace URIs
XmlParserTestHandler handler;
XmlParser::ParseXml(&handler,
"<test xmlns:foo='' foo:bar='huh?'>");
EXPECT_EQ("ERROR (2) ", handler.Str());
}
}

View File

@ -1,174 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/xmllite/xmlprinter.h"
#include <sstream>
#include <string>
#include <vector>
#include "webrtc/libjingle/xmllite/xmlconstants.h"
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/libjingle/xmllite/xmlnsstack.h"
namespace buzz {
class XmlPrinterImpl {
public:
XmlPrinterImpl(std::ostream* pout, XmlnsStack* ns_stack);
void PrintElement(const XmlElement* element);
void PrintQuotedValue(const std::string& text);
void PrintBodyText(const std::string& text);
void PrintCDATAText(const std::string& text);
private:
std::ostream *pout_;
XmlnsStack* ns_stack_;
};
void XmlPrinter::PrintXml(std::ostream* pout, const XmlElement* element) {
XmlnsStack ns_stack;
PrintXml(pout, element, &ns_stack);
}
void XmlPrinter::PrintXml(std::ostream* pout, const XmlElement* element,
XmlnsStack* ns_stack) {
XmlPrinterImpl printer(pout, ns_stack);
printer.PrintElement(element);
}
XmlPrinterImpl::XmlPrinterImpl(std::ostream* pout, XmlnsStack* ns_stack)
: pout_(pout),
ns_stack_(ns_stack) {
}
void XmlPrinterImpl::PrintElement(const XmlElement* element) {
ns_stack_->PushFrame();
// first go through attrs of pel to add xmlns definitions
const XmlAttr* attr;
for (attr = element->FirstAttr(); attr; attr = attr->NextAttr()) {
if (attr->Name() == QN_XMLNS) {
ns_stack_->AddXmlns(STR_EMPTY, attr->Value());
} else if (attr->Name().Namespace() == NS_XMLNS) {
ns_stack_->AddXmlns(attr->Name().LocalPart(),
attr->Value());
}
}
// then go through qnames to make sure needed xmlns definitons are added
std::vector<std::string> new_ns;
std::pair<std::string, bool> prefix;
prefix = ns_stack_->AddNewPrefix(element->Name().Namespace(), false);
if (prefix.second) {
new_ns.push_back(prefix.first);
new_ns.push_back(element->Name().Namespace());
}
for (attr = element->FirstAttr(); attr; attr = attr->NextAttr()) {
prefix = ns_stack_->AddNewPrefix(attr->Name().Namespace(), true);
if (prefix.second) {
new_ns.push_back(prefix.first);
new_ns.push_back(attr->Name().Namespace());
}
}
// print the element name
*pout_ << '<' << ns_stack_->FormatQName(element->Name(), false);
// and the attributes
for (attr = element->FirstAttr(); attr; attr = attr->NextAttr()) {
*pout_ << ' ' << ns_stack_->FormatQName(attr->Name(), true) << "=\"";
PrintQuotedValue(attr->Value());
*pout_ << '"';
}
// and the extra xmlns declarations
std::vector<std::string>::iterator i(new_ns.begin());
while (i < new_ns.end()) {
if (*i == STR_EMPTY) {
*pout_ << " xmlns=\"" << *(i + 1) << '"';
} else {
*pout_ << " xmlns:" << *i << "=\"" << *(i + 1) << '"';
}
i += 2;
}
// now the children
const XmlChild* child = element->FirstChild();
if (child == NULL)
*pout_ << "/>";
else {
*pout_ << '>';
while (child) {
if (child->IsText()) {
if (element->IsCDATA()) {
PrintCDATAText(child->AsText()->Text());
} else {
PrintBodyText(child->AsText()->Text());
}
} else {
PrintElement(child->AsElement());
}
child = child->NextChild();
}
*pout_ << "</" << ns_stack_->FormatQName(element->Name(), false) << '>';
}
ns_stack_->PopFrame();
}
void XmlPrinterImpl::PrintQuotedValue(const std::string& text) {
size_t safe = 0;
for (;;) {
size_t unsafe = text.find_first_of("<>&\"", safe);
if (unsafe == std::string::npos)
unsafe = text.length();
*pout_ << text.substr(safe, unsafe - safe);
if (unsafe == text.length())
return;
switch (text[unsafe]) {
case '<': *pout_ << "&lt;"; break;
case '>': *pout_ << "&gt;"; break;
case '&': *pout_ << "&amp;"; break;
case '"': *pout_ << "&quot;"; break;
}
safe = unsafe + 1;
if (safe == text.length())
return;
}
}
void XmlPrinterImpl::PrintBodyText(const std::string& text) {
size_t safe = 0;
for (;;) {
size_t unsafe = text.find_first_of("<>&", safe);
if (unsafe == std::string::npos)
unsafe = text.length();
*pout_ << text.substr(safe, unsafe - safe);
if (unsafe == text.length())
return;
switch (text[unsafe]) {
case '<': *pout_ << "&lt;"; break;
case '>': *pout_ << "&gt;"; break;
case '&': *pout_ << "&amp;"; break;
}
safe = unsafe + 1;
if (safe == text.length())
return;
}
}
void XmlPrinterImpl::PrintCDATAText(const std::string& text) {
*pout_ << "<![CDATA[" << text << "]]>";
}
} // namespace buzz

View File

@ -1,32 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMLLITE_XMLPRINTER_H_
#define WEBRTC_LIBJINGLE_XMLLITE_XMLPRINTER_H_
#include <iosfwd>
#include <string>
namespace buzz {
class XmlElement;
class XmlnsStack;
class XmlPrinter {
public:
static void PrintXml(std::ostream* pout, const XmlElement* pelt);
static void PrintXml(std::ostream* pout, const XmlElement* pelt,
XmlnsStack* ns_stack);
};
} // namespace buzz
#endif // WEBRTC_LIBJINGLE_XMLLITE_XMLPRINTER_H_

View File

@ -1,45 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/xmllite/xmlprinter.h"
#include <sstream>
#include <string>
#include "webrtc/libjingle/xmllite/qname.h"
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/libjingle/xmllite/xmlnsstack.h"
#include "webrtc/base/common.h"
#include "webrtc/base/gunit.h"
using buzz::QName;
using buzz::XmlElement;
using buzz::XmlnsStack;
using buzz::XmlPrinter;
TEST(XmlPrinterTest, TestBasicPrinting) {
XmlElement elt(QName("google:test", "first"));
std::stringstream ss;
XmlPrinter::PrintXml(&ss, &elt);
EXPECT_EQ("<test:first xmlns:test=\"google:test\"/>", ss.str());
}
TEST(XmlPrinterTest, TestNamespacedPrinting) {
XmlElement elt(QName("google:test", "first"));
elt.AddElement(new XmlElement(QName("nested:test", "second")));
std::stringstream ss;
XmlnsStack ns_stack;
ns_stack.AddXmlns("gg", "google:test");
ns_stack.AddXmlns("", "nested:test");
XmlPrinter::PrintXml(&ss, &elt, &ns_stack);
EXPECT_EQ("<gg:first><second/></gg:first>", ss.str());
}

View File

@ -1,154 +0,0 @@
# Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
#
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE file in the root of the source
# tree. An additional intellectual property rights grant can be found
# in the file PATENTS. All contributing project authors may
# be found in the AUTHORS file in the root of the source tree.
import("../../build/webrtc.gni")
group("xmpp") {
public_deps = [
":rtc_xmpp",
]
}
config("xmpp_warnings_config") {
# GN orders flags on a target before flags from configs. The default config
# adds these flags so to cancel them out they need to come from a config and
# cannot be on the target directly.
if (is_android) {
cflags = [ "-Wno-error" ]
}
}
config("xmpp_inherited_config") {
defines = [
"FEATURE_ENABLE_SSL",
"FEATURE_ENABLE_VOICEMAIL",
]
}
rtc_static_library("rtc_xmpp") {
cflags = []
sources = [
"asyncsocket.h",
"constants.cc",
"constants.h",
"jid.cc",
"jid.h",
"plainsaslhandler.h",
"prexmppauth.h",
"saslcookiemechanism.h",
"saslhandler.h",
"saslmechanism.cc",
"saslmechanism.h",
"saslplainmechanism.h",
"xmppclient.cc",
"xmppclient.h",
"xmppclientsettings.h",
"xmppengine.h",
"xmppengineimpl.cc",
"xmppengineimpl.h",
"xmppengineimpl_iq.cc",
"xmpplogintask.cc",
"xmpplogintask.h",
"xmppstanzaparser.cc",
"xmppstanzaparser.h",
"xmpptask.cc",
"xmpptask.h",
]
defines = [ "FEATURE_ENABLE_SSL" ]
deps = [
"../../base:rtc_base",
"../xmllite",
]
if (rtc_build_expat) {
deps += [ "//third_party/expat" ]
public_deps = [
"//third_party/expat",
]
}
configs += [ ":xmpp_warnings_config" ]
public_configs = [ ":xmpp_inherited_config" ]
if (build_with_chromium) {
if (is_nacl) {
deps += [ "//native_client_sdk/src/libraries/nacl_io" ]
}
} else {
sources += [
"chatroommodule.h",
"chatroommoduleimpl.cc",
"discoitemsquerytask.cc",
"discoitemsquerytask.h",
"hangoutpubsubclient.cc",
"hangoutpubsubclient.h",
"iqtask.cc",
"iqtask.h",
"module.h",
"moduleimpl.cc",
"moduleimpl.h",
"mucroomconfigtask.cc",
"mucroomconfigtask.h",
"mucroomdiscoverytask.cc",
"mucroomdiscoverytask.h",
"mucroomlookuptask.cc",
"mucroomlookuptask.h",
"mucroomuniquehangoutidtask.cc",
"mucroomuniquehangoutidtask.h",
"pingtask.cc",
"pingtask.h",
"presenceouttask.cc",
"presenceouttask.h",
"presencereceivetask.cc",
"presencereceivetask.h",
"presencestatus.cc",
"presencestatus.h",
"pubsub_task.cc",
"pubsub_task.h",
"pubsubclient.cc",
"pubsubclient.h",
"pubsubstateclient.cc",
"pubsubstateclient.h",
"pubsubtasks.cc",
"pubsubtasks.h",
"receivetask.cc",
"receivetask.h",
"rostermodule.h",
"rostermoduleimpl.cc",
"rostermoduleimpl.h",
"xmppauth.cc",
"xmppauth.h",
"xmpppump.cc",
"xmpppump.h",
"xmppsocket.cc",
"xmppsocket.h",
"xmppthread.cc",
"xmppthread.h",
]
defines += [
"FEATURE_ENABLE_VOICEMAIL",
"FEATURE_ENABLE_PSTN",
]
if (!build_with_chromium && is_clang) {
# Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
}
}
if (is_posix && is_debug) {
# The Chromium build/common.gypi defines this for all posix
# _except_ for ios & mac. We want it there as well, e.g.
# because ASSERT and friends trigger off of it.
defines += [ "_DEBUG" ]
}
}

View File

@ -1,6 +0,0 @@
# See ../OWNERS for more owners.
# These are for the common case of adding or renaming files. If you're doing
# structural changes, please get a review from a reviewer in this file.
per-file *.gn=*
per-file *.gni=*

View File

@ -1,72 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_ASYNCSOCKET_H_
#define WEBRTC_LIBJINGLE_XMPP_ASYNCSOCKET_H_
#include <string>
#include "webrtc/base/sigslot.h"
namespace rtc {
class SocketAddress;
}
namespace buzz {
class AsyncSocket {
public:
enum State {
STATE_CLOSED = 0, //!< Socket is not open.
STATE_CLOSING, //!< Socket is closing but can have buffered data
STATE_CONNECTING, //!< In the process of
STATE_OPEN, //!< Socket is connected
#if defined(FEATURE_ENABLE_SSL)
STATE_TLS_CONNECTING, //!< Establishing TLS connection
STATE_TLS_OPEN, //!< TLS connected
#endif
};
enum Error {
ERROR_NONE = 0, //!< No error
ERROR_WINSOCK, //!< Winsock error
ERROR_DNS, //!< Couldn't resolve host name
ERROR_WRONGSTATE, //!< Call made while socket is in the wrong state
#if defined(FEATURE_ENABLE_SSL)
ERROR_SSL, //!< Something went wrong with OpenSSL
#endif
};
virtual ~AsyncSocket() {}
virtual State state() = 0;
virtual Error error() = 0;
virtual int GetError() = 0; // winsock error code
virtual bool Connect(const rtc::SocketAddress& addr) = 0;
virtual bool Read(char * data, size_t len, size_t* len_read) = 0;
virtual bool Write(const char * data, size_t len) = 0;
virtual bool Close() = 0;
#if defined(FEATURE_ENABLE_SSL)
// We allow matching any passed domain. This allows us to avoid
// handling the valuable certificates for logins into proxies. If
// both names are passed as empty, we do not require a match.
virtual bool StartTls(const std::string & domainname) = 0;
#endif
sigslot::signal0<> SignalConnected;
sigslot::signal0<> SignalSSLConnected;
sigslot::signal0<> SignalClosed;
sigslot::signal0<> SignalRead;
sigslot::signal0<> SignalError;
};
}
#endif // WEBRTC_LIBJINGLE_XMPP_ASYNCSOCKET_H_

View File

@ -1,253 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_CHATROOMMODULE_H_
#define WEBRTC_LIBJINGLE_XMPP_CHATROOMMODULE_H_
#include "webrtc/libjingle/xmpp/module.h"
#include "webrtc/libjingle/xmpp/rostermodule.h"
namespace buzz {
// forward declarations
class XmppChatroomModule;
class XmppChatroomHandler;
class XmppChatroomMember;
class XmppChatroomMemberEnumerator;
enum XmppChatroomState {
XMPP_CHATROOM_STATE_NOT_IN_ROOM = 0,
XMPP_CHATROOM_STATE_REQUESTED_ENTER = 1,
XMPP_CHATROOM_STATE_IN_ROOM = 2,
XMPP_CHATROOM_STATE_REQUESTED_EXIT = 3,
};
//! Module that encapsulates a chatroom.
class XmppChatroomModule : public XmppModule {
public:
//! Creates a new XmppChatroomModule
static XmppChatroomModule* Create();
virtual ~XmppChatroomModule() {}
//! Sets the chatroom handler (callbacks) for the chatroom
virtual XmppReturnStatus set_chatroom_handler(XmppChatroomHandler* handler) = 0;
//! Gets the chatroom handler for the module
virtual XmppChatroomHandler* chatroom_handler() = 0;
//! Sets the jid of the chatroom.
//! Has to be set before entering the chatroom and can't be changed
//! while in the chatroom
virtual XmppReturnStatus set_chatroom_jid(const Jid& chatroom_jid) = 0;
//! The jid for the chatroom
virtual const Jid& chatroom_jid() const = 0;
//! Sets the nickname of the member
//! Has to be set before entering the chatroom and can't be changed
//! while in the chatroom
virtual XmppReturnStatus set_nickname(const std::string& nickname) = 0;
//! The nickname of the member in the chatroom
virtual const std::string& nickname() const = 0;
//! Returns the jid of the member (this is the chatroom_jid plus the
//! nickname as the resource name)
virtual const Jid member_jid() const = 0;
//! Requests that the user enter a chatroom
//! The EnterChatroom callback will be called when the request is complete.
//! Password should be empty for a room that doesn't require a password
//! If the room doesn't exist, the server will create an "Instant Room" if the
//! server policy supports this action.
//! There will be different methods for creating/configuring a "Reserved Room"
//! Async callback for this method is ChatroomEnteredStatus
virtual XmppReturnStatus RequestEnterChatroom(const std::string& password,
const std::string& client_version,
const std::string& locale) = 0;
//! Requests that the user exit a chatroom
//! Async callback for this method is ChatroomExitedStatus
virtual XmppReturnStatus RequestExitChatroom() = 0;
//! Requests a status change
//! status is the standard XMPP status code
//! extended_status is the extended status when status is XMPP_PRESENCE_XA
virtual XmppReturnStatus RequestConnectionStatusChange(
XmppPresenceConnectionStatus connection_status) = 0;
//! Returns the number of members in the room
virtual size_t GetChatroomMemberCount() = 0;
//! Gets an enumerator for the members in the chatroom
//! The caller must delete the enumerator when the caller is finished with it.
//! The caller must also ensure that the lifetime of the enumerator is
//! scoped by the XmppChatRoomModule that created it.
virtual XmppReturnStatus CreateMemberEnumerator(XmppChatroomMemberEnumerator** enumerator) = 0;
//! Gets the subject of the chatroom
virtual const std::string subject() = 0;
//! Returns the current state of the user with respect to the chatroom
virtual XmppChatroomState state() = 0;
virtual XmppReturnStatus SendMessage(const XmlElement& message) = 0;
};
//! Class for enumerating participatns
class XmppChatroomMemberEnumerator {
public:
virtual ~XmppChatroomMemberEnumerator() { }
//! Returns the member at the current position
//! Returns null if the enumerator is before the beginning
//! or after the end of the collection
virtual XmppChatroomMember* current() = 0;
//! Returns whether the enumerator is valid
//! This returns true if the collection has changed
//! since the enumerator was created
virtual bool IsValid() = 0;
//! Returns whether the enumerator is before the beginning
//! This is the initial state of the enumerator
virtual bool IsBeforeBeginning() = 0;
//! Returns whether the enumerator is after the end
virtual bool IsAfterEnd() = 0;
//! Advances the enumerator to the next position
//! Returns false is the enumerator is advanced
//! off the end of the collection
virtual bool Next() = 0;
//! Advances the enumerator to the previous position
//! Returns false is the enumerator is advanced
//! off the end of the collection
virtual bool Prev() = 0;
};
//! Represents a single member in a chatroom
class XmppChatroomMember {
public:
virtual ~XmppChatroomMember() { }
//! The jid for the member in the chatroom
virtual const Jid member_jid() const = 0;
//! The full jid for the member
//! This is only available in non-anonymous rooms.
//! If the room is anonymous, this returns JID_EMPTY
virtual const Jid full_jid() const = 0;
//! Returns the backing presence for this member
virtual const XmppPresence* presence() const = 0;
//! The nickname for this member
virtual const std::string name() const = 0;
};
//! Status codes for ChatroomEnteredStatus callback
enum XmppChatroomEnteredStatus
{
//! User successfully entered the room
XMPP_CHATROOM_ENTERED_SUCCESS = 0,
//! The nickname confliced with somebody already in the room
XMPP_CHATROOM_ENTERED_FAILURE_NICKNAME_CONFLICT = 1,
//! A password is required to enter the room
XMPP_CHATROOM_ENTERED_FAILURE_PASSWORD_REQUIRED = 2,
//! The specified password was incorrect
XMPP_CHATROOM_ENTERED_FAILURE_PASSWORD_INCORRECT = 3,
//! The user is not a member of a member-only room
XMPP_CHATROOM_ENTERED_FAILURE_NOT_A_MEMBER = 4,
//! The user cannot enter because the user has been banned
XMPP_CHATROOM_ENTERED_FAILURE_MEMBER_BANNED = 5,
//! The room has the maximum number of users already
XMPP_CHATROOM_ENTERED_FAILURE_MAX_USERS = 6,
//! The room has been locked by an administrator
XMPP_CHATROOM_ENTERED_FAILURE_ROOM_LOCKED = 7,
//! Someone in the room has blocked you
XMPP_CHATROOM_ENTERED_FAILURE_MEMBER_BLOCKED = 8,
//! You have blocked someone in the room
XMPP_CHATROOM_ENTERED_FAILURE_MEMBER_BLOCKING = 9,
//! Client is old. User must upgrade to a more recent version for
// hangouts to work.
XMPP_CHATROOM_ENTERED_FAILURE_OUTDATED_CLIENT = 10,
//! Some other reason
XMPP_CHATROOM_ENTERED_FAILURE_UNSPECIFIED = 2000,
};
//! Status codes for ChatroomExitedStatus callback
enum XmppChatroomExitedStatus
{
//! The user requested to exit and did so
XMPP_CHATROOM_EXITED_REQUESTED = 0,
//! The user was banned from the room
XMPP_CHATROOM_EXITED_BANNED = 1,
//! The user has been kicked out of the room
XMPP_CHATROOM_EXITED_KICKED = 2,
//! The user has been removed from the room because the
//! user is no longer a member of a member-only room
//! or the room has changed to membership-only
XMPP_CHATROOM_EXITED_NOT_A_MEMBER = 3,
//! The system is shutting down
XMPP_CHATROOM_EXITED_SYSTEM_SHUTDOWN = 4,
//! For some other reason
XMPP_CHATROOM_EXITED_UNSPECIFIED = 5,
};
//! The XmppChatroomHandler is the interface for callbacks from the
//! the chatroom
class XmppChatroomHandler {
public:
virtual ~XmppChatroomHandler() {}
//! Indicates the response to RequestEnterChatroom method
//! XMPP_CHATROOM_SUCCESS represents success.
//! Other status codes are for errors
virtual void ChatroomEnteredStatus(XmppChatroomModule* room,
const XmppPresence* presence,
XmppChatroomEnteredStatus status) = 0;
//! Indicates that the user has exited the chatroom, either due to
//! a call to RequestExitChatroom or for some other reason.
//! status indicates the reason the user exited
virtual void ChatroomExitedStatus(XmppChatroomModule* room,
XmppChatroomExitedStatus status) = 0;
//! Indicates a member entered the room.
//! It can be called before ChatroomEnteredStatus.
virtual void MemberEntered(XmppChatroomModule* room,
const XmppChatroomMember* entered_member) = 0;
//! Indicates that a member exited the room.
virtual void MemberExited(XmppChatroomModule* room,
const XmppChatroomMember* exited_member) = 0;
//! Indicates that the data for the member has changed
//! (such as the nickname or presence)
virtual void MemberChanged(XmppChatroomModule* room,
const XmppChatroomMember* changed_member) = 0;
//! Indicates a new message has been received
//! message is the message -
// $TODO - message should be changed
//! to a strongly-typed message class that contains info
//! such as the sender, message bodies, etc.,
virtual void MessageReceived(XmppChatroomModule* room,
const XmlElement& message) = 0;
};
}
#endif // WEBRTC_LIBJINGLE_XMPP_CHATROOMMODULE_H_

View File

@ -1,737 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <algorithm>
#include <iostream>
#include <map>
#include <memory>
#include <sstream>
#include <string>
#include <vector>
#include "webrtc/libjingle/xmpp/chatroommodule.h"
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/libjingle/xmpp/moduleimpl.h"
#include "webrtc/base/arraysize.h"
#include "webrtc/base/common.h"
namespace buzz {
// forward declarations
class XmppChatroomImpl;
class XmppChatroomMemberImpl;
//! Module that encapsulates multiple chatrooms.
//! Each chatroom is represented by an XmppChatroomImpl instance
class XmppChatroomModuleImpl : public XmppChatroomModule,
public XmppModuleImpl, public XmppIqHandler {
public:
IMPLEMENT_XMPPMODULE
// Creates a chatroom with specified Jid
XmppChatroomModuleImpl();
~XmppChatroomModuleImpl();
// XmppChatroomModule
virtual XmppReturnStatus set_chatroom_handler(XmppChatroomHandler* handler);
virtual XmppChatroomHandler* chatroom_handler();
virtual XmppReturnStatus set_chatroom_jid(const Jid& chatroom_jid);
virtual const Jid& chatroom_jid() const;
virtual XmppReturnStatus set_nickname(const std::string& nickname);
virtual const std::string& nickname() const;
virtual const Jid member_jid() const;
virtual XmppReturnStatus RequestEnterChatroom(const std::string& password,
const std::string& client_version,
const std::string& locale);
virtual XmppReturnStatus RequestExitChatroom();
virtual XmppReturnStatus RequestConnectionStatusChange(
XmppPresenceConnectionStatus connection_status);
virtual size_t GetChatroomMemberCount();
virtual XmppReturnStatus CreateMemberEnumerator(XmppChatroomMemberEnumerator** enumerator);
virtual const std::string subject();
virtual XmppChatroomState state() { return chatroom_state_; }
virtual XmppReturnStatus SendMessage(const XmlElement& message);
// XmppModule
virtual void IqResponse(XmppIqCookie cookie, const XmlElement * pelStanza) {RTC_UNUSED2(cookie, pelStanza);}
virtual bool HandleStanza(const XmlElement *);
private:
friend class XmppChatroomMemberEnumeratorImpl;
XmppReturnStatus ServerChangeMyPresence(const XmlElement& presence);
XmppReturnStatus ClientChangeMyPresence(XmppChatroomState new_state);
XmppReturnStatus ChangePresence(XmppChatroomState new_state, const XmlElement* presence, bool isServer);
XmppReturnStatus ServerChangedOtherPresence(const XmlElement& presence_element);
XmppChatroomEnteredStatus GetEnterFailureFromXml(const XmlElement* presence);
XmppChatroomExitedStatus GetExitFailureFromXml(const XmlElement* presence);
bool CheckEnterChatroomStateOk();
void FireEnteredStatus(const XmlElement* presence,
XmppChatroomEnteredStatus status);
void FireExitStatus(XmppChatroomExitedStatus status);
void FireMessageReceived(const XmlElement& message);
void FireMemberEntered(const XmppChatroomMember* entered_member);
void FireMemberChanged(const XmppChatroomMember* changed_member);
void FireMemberExited(const XmppChatroomMember* exited_member);
typedef std::map<Jid, XmppChatroomMemberImpl*> JidMemberMap;
XmppChatroomHandler* chatroom_handler_;
Jid chatroom_jid_;
std::string nickname_;
XmppChatroomState chatroom_state_;
JidMemberMap chatroom_jid_members_;
int chatroom_jid_members_version_;
};
class XmppChatroomMemberImpl : public XmppChatroomMember {
public:
~XmppChatroomMemberImpl() {}
XmppReturnStatus SetPresence(const XmppPresence* presence);
// XmppChatroomMember
const Jid member_jid() const;
const Jid full_jid() const;
const std::string name() const;
const XmppPresence* presence() const;
private:
std::unique_ptr<XmppPresence> presence_;
};
class XmppChatroomMemberEnumeratorImpl :
public XmppChatroomMemberEnumerator {
public:
XmppChatroomMemberEnumeratorImpl(XmppChatroomModuleImpl::JidMemberMap* chatroom_jid_members,
int* map_version);
// XmppChatroomMemberEnumerator
virtual XmppChatroomMember* current();
virtual bool Next();
virtual bool Prev();
virtual bool IsValid();
virtual bool IsBeforeBeginning();
virtual bool IsAfterEnd();
private:
XmppChatroomModuleImpl::JidMemberMap* map_;
int map_version_created_;
int* map_version_;
XmppChatroomModuleImpl::JidMemberMap::iterator iterator_;
bool before_beginning_;
};
// XmppChatroomModuleImpl ------------------------------------------------
XmppChatroomModule *
XmppChatroomModule::Create() {
return new XmppChatroomModuleImpl();
}
XmppChatroomModuleImpl::XmppChatroomModuleImpl() :
chatroom_handler_(NULL),
chatroom_jid_(STR_EMPTY),
chatroom_state_(XMPP_CHATROOM_STATE_NOT_IN_ROOM),
chatroom_jid_members_version_(0) {
}
XmppChatroomModuleImpl::~XmppChatroomModuleImpl() {
JidMemberMap::iterator iterator = chatroom_jid_members_.begin();
while (iterator != chatroom_jid_members_.end()) {
delete iterator->second;
iterator++;
}
}
bool
XmppChatroomModuleImpl::HandleStanza(const XmlElement* stanza) {
ASSERT(engine() != NULL);
// we handle stanzas that are for one of our chatrooms
Jid from_jid = Jid(stanza->Attr(QN_FROM));
// see if it's one of our chatrooms
if (chatroom_jid_ != from_jid.BareJid()) {
return false; // not one of our chatrooms
} else {
// handle presence stanza
if (stanza->Name() == QN_PRESENCE) {
if (from_jid == member_jid()) {
ServerChangeMyPresence(*stanza);
} else {
ServerChangedOtherPresence(*stanza);
}
} else if (stanza->Name() == QN_MESSAGE) {
FireMessageReceived(*stanza);
}
return true;
}
}
XmppReturnStatus
XmppChatroomModuleImpl::set_chatroom_handler(XmppChatroomHandler* handler) {
// Calling with NULL removes the handler.
chatroom_handler_ = handler;
return XMPP_RETURN_OK;
}
XmppChatroomHandler*
XmppChatroomModuleImpl::chatroom_handler() {
return chatroom_handler_;
}
XmppReturnStatus
XmppChatroomModuleImpl::set_chatroom_jid(const Jid& chatroom_jid) {
if (chatroom_state_ != XMPP_CHATROOM_STATE_NOT_IN_ROOM) {
return XMPP_RETURN_BADSTATE; // $TODO - this isn't a bad state, it's a bad call, diff error code?
}
if (chatroom_jid != chatroom_jid.BareJid()) {
// chatroom_jid must be a bare jid
return XMPP_RETURN_BADARGUMENT;
}
chatroom_jid_ = chatroom_jid;
return XMPP_RETURN_OK;
}
const Jid&
XmppChatroomModuleImpl::chatroom_jid() const {
return chatroom_jid_;
}
XmppReturnStatus
XmppChatroomModuleImpl::set_nickname(const std::string& nickname) {
if (chatroom_state_ != XMPP_CHATROOM_STATE_NOT_IN_ROOM) {
return XMPP_RETURN_BADSTATE; // $TODO - this isn't a bad state, it's a bad call, diff error code?
}
nickname_ = nickname;
return XMPP_RETURN_OK;
}
const std::string&
XmppChatroomModuleImpl::nickname() const {
return nickname_;
}
const Jid
XmppChatroomModuleImpl::member_jid() const {
return Jid(chatroom_jid_.node(), chatroom_jid_.domain(), nickname_);
}
bool
XmppChatroomModuleImpl::CheckEnterChatroomStateOk() {
if (chatroom_jid_.IsValid() == false) {
ASSERT(0);
return false;
}
if (nickname_ == STR_EMPTY) {
ASSERT(0);
return false;
}
return true;
}
std::string GetAttrValueFor(XmppPresenceConnectionStatus connection_status) {
switch (connection_status) {
default:
case XMPP_CONNECTION_STATUS_UNKNOWN:
return "";
case XMPP_CONNECTION_STATUS_CONNECTING:
return STR_PSTN_CONFERENCE_STATUS_CONNECTING;
case XMPP_CONNECTION_STATUS_CONNECTED:
return STR_PSTN_CONFERENCE_STATUS_CONNECTED;
}
}
XmppReturnStatus
XmppChatroomModuleImpl::RequestEnterChatroom(
const std::string& password,
const std::string& client_version,
const std::string& locale) {
RTC_UNUSED(password);
if (!engine())
return XMPP_RETURN_BADSTATE;
if (chatroom_state_ != XMPP_CHATROOM_STATE_NOT_IN_ROOM)
return XMPP_RETURN_BADSTATE; // $TODO - this isn't a bad state, it's a bad call, diff error code?
if (CheckEnterChatroomStateOk() == false) {
return XMPP_RETURN_BADSTATE;
}
// entering a chatroom is a presence request to the server
XmlElement element(QN_PRESENCE);
element.AddAttr(QN_TO, member_jid().Str());
XmlElement* muc_x = new XmlElement(QN_MUC_X);
element.AddElement(muc_x);
if (!client_version.empty()) {
XmlElement* client_version_element = new XmlElement(QN_CLIENT_VERSION,
false);
client_version_element->SetBodyText(client_version);
muc_x->AddElement(client_version_element);
}
if (!locale.empty()) {
XmlElement* locale_element = new XmlElement(QN_LOCALE, false);
locale_element->SetBodyText(locale);
muc_x->AddElement(locale_element);
}
XmppReturnStatus status = engine()->SendStanza(&element);
if (status == XMPP_RETURN_OK) {
return ClientChangeMyPresence(XMPP_CHATROOM_STATE_REQUESTED_ENTER);
}
return status;
}
XmppReturnStatus
XmppChatroomModuleImpl::RequestExitChatroom() {
if (!engine())
return XMPP_RETURN_BADSTATE;
// exiting a chatroom is a presence request to the server
XmlElement element(QN_PRESENCE);
element.AddAttr(QN_TO, member_jid().Str());
element.AddAttr(QN_TYPE, "unavailable");
XmppReturnStatus status = engine()->SendStanza(&element);
if (status == XMPP_RETURN_OK &&
chatroom_state_ == XMPP_CHATROOM_STATE_IN_ROOM) {
return ClientChangeMyPresence(XMPP_CHATROOM_STATE_REQUESTED_EXIT);
}
return status;
}
XmppReturnStatus
XmppChatroomModuleImpl::RequestConnectionStatusChange(
XmppPresenceConnectionStatus connection_status) {
if (!engine())
return XMPP_RETURN_BADSTATE;
if (chatroom_state_ != XMPP_CHATROOM_STATE_IN_ROOM) {
// $TODO - this isn't a bad state, it's a bad call, diff error code?
return XMPP_RETURN_BADSTATE;
}
if (CheckEnterChatroomStateOk() == false) {
return XMPP_RETURN_BADSTATE;
}
// entering a chatroom is a presence request to the server
XmlElement element(QN_PRESENCE);
element.AddAttr(QN_TO, member_jid().Str());
element.AddElement(new XmlElement(QN_MUC_X));
if (connection_status != XMPP_CONNECTION_STATUS_UNKNOWN) {
XmlElement* con_status_element =
new XmlElement(QN_GOOGLE_PSTN_CONFERENCE_STATUS);
con_status_element->AddAttr(QN_STATUS, GetAttrValueFor(connection_status));
element.AddElement(con_status_element);
}
XmppReturnStatus status = engine()->SendStanza(&element);
return status;
}
size_t
XmppChatroomModuleImpl::GetChatroomMemberCount() {
return chatroom_jid_members_.size();
}
XmppReturnStatus
XmppChatroomModuleImpl::CreateMemberEnumerator(XmppChatroomMemberEnumerator** enumerator) {
*enumerator = new XmppChatroomMemberEnumeratorImpl(&chatroom_jid_members_, &chatroom_jid_members_version_);
return XMPP_RETURN_OK;
}
const std::string
XmppChatroomModuleImpl::subject() {
return ""; //NYI
}
XmppReturnStatus
XmppChatroomModuleImpl::SendMessage(const XmlElement& message) {
XmppReturnStatus xmpp_status = XMPP_RETURN_OK;
// can only send a message if we're in the room
if (chatroom_state_ != XMPP_CHATROOM_STATE_IN_ROOM) {
return XMPP_RETURN_BADSTATE; // $TODO - this isn't a bad state, it's a bad call, diff error code?
}
if (message.Name() != QN_MESSAGE) {
IFR(XMPP_RETURN_BADARGUMENT);
}
const std::string& type = message.Attr(QN_TYPE);
if (type != "groupchat") {
IFR(XMPP_RETURN_BADARGUMENT);
}
if (message.HasAttr(QN_FROM)) {
IFR(XMPP_RETURN_BADARGUMENT);
}
if (message.Attr(QN_TO) != chatroom_jid_.Str()) {
IFR(XMPP_RETURN_BADARGUMENT);
}
IFR(engine()->SendStanza(&message));
return xmpp_status;
}
enum TransitionType {
TRANSITION_TYPE_NONE = 0,
TRANSITION_TYPE_ENTER_SUCCESS = 1,
TRANSITION_TYPE_ENTER_FAILURE = 2,
TRANSITION_TYPE_EXIT_VOLUNTARILY = 3,
TRANSITION_TYPE_EXIT_INVOLUNTARILY = 4,
};
struct StateTransitionDescription {
XmppChatroomState old_state;
XmppChatroomState new_state;
bool is_valid_server_transition;
bool is_valid_client_transition;
TransitionType transition_type;
};
StateTransitionDescription Transitions[] = {
{ XMPP_CHATROOM_STATE_NOT_IN_ROOM, XMPP_CHATROOM_STATE_REQUESTED_ENTER, false, true, TRANSITION_TYPE_NONE, },
{ XMPP_CHATROOM_STATE_NOT_IN_ROOM, XMPP_CHATROOM_STATE_IN_ROOM, false, false, TRANSITION_TYPE_ENTER_SUCCESS, },
{ XMPP_CHATROOM_STATE_NOT_IN_ROOM, XMPP_CHATROOM_STATE_REQUESTED_EXIT, false, false, TRANSITION_TYPE_NONE, },
{ XMPP_CHATROOM_STATE_REQUESTED_ENTER, XMPP_CHATROOM_STATE_NOT_IN_ROOM, true, false, TRANSITION_TYPE_ENTER_FAILURE, },
{ XMPP_CHATROOM_STATE_REQUESTED_ENTER, XMPP_CHATROOM_STATE_IN_ROOM, true, false, TRANSITION_TYPE_ENTER_SUCCESS, },
{ XMPP_CHATROOM_STATE_REQUESTED_ENTER, XMPP_CHATROOM_STATE_REQUESTED_EXIT, false, false, TRANSITION_TYPE_NONE, },
{ XMPP_CHATROOM_STATE_IN_ROOM, XMPP_CHATROOM_STATE_NOT_IN_ROOM, true, false, TRANSITION_TYPE_EXIT_INVOLUNTARILY, },
{ XMPP_CHATROOM_STATE_IN_ROOM, XMPP_CHATROOM_STATE_REQUESTED_ENTER, false, false, TRANSITION_TYPE_NONE, },
{ XMPP_CHATROOM_STATE_IN_ROOM, XMPP_CHATROOM_STATE_REQUESTED_EXIT, false, true, TRANSITION_TYPE_NONE, },
{ XMPP_CHATROOM_STATE_REQUESTED_EXIT, XMPP_CHATROOM_STATE_NOT_IN_ROOM, true, false, TRANSITION_TYPE_EXIT_VOLUNTARILY, },
{ XMPP_CHATROOM_STATE_REQUESTED_EXIT, XMPP_CHATROOM_STATE_REQUESTED_ENTER, false, false, TRANSITION_TYPE_NONE, },
{ XMPP_CHATROOM_STATE_REQUESTED_EXIT, XMPP_CHATROOM_STATE_IN_ROOM, false, false, TRANSITION_TYPE_NONE, },
};
void
XmppChatroomModuleImpl::FireEnteredStatus(const XmlElement* presence,
XmppChatroomEnteredStatus status) {
if (chatroom_handler_) {
std::unique_ptr<XmppPresence> xmpp_presence(XmppPresence::Create());
xmpp_presence->set_raw_xml(presence);
chatroom_handler_->ChatroomEnteredStatus(this, xmpp_presence.get(), status);
}
}
void
XmppChatroomModuleImpl::FireExitStatus(XmppChatroomExitedStatus status) {
if (chatroom_handler_)
chatroom_handler_->ChatroomExitedStatus(this, status);
}
void
XmppChatroomModuleImpl::FireMessageReceived(const XmlElement& message) {
if (chatroom_handler_)
chatroom_handler_->MessageReceived(this, message);
}
void
XmppChatroomModuleImpl::FireMemberEntered(const XmppChatroomMember* entered_member) {
if (chatroom_handler_)
chatroom_handler_->MemberEntered(this, entered_member);
}
void
XmppChatroomModuleImpl::FireMemberChanged(
const XmppChatroomMember* changed_member) {
if (chatroom_handler_)
chatroom_handler_->MemberChanged(this, changed_member);
}
void
XmppChatroomModuleImpl::FireMemberExited(const XmppChatroomMember* exited_member) {
if (chatroom_handler_)
chatroom_handler_->MemberExited(this, exited_member);
}
XmppReturnStatus
XmppChatroomModuleImpl::ServerChangedOtherPresence(const XmlElement&
presence_element) {
XmppReturnStatus xmpp_status = XMPP_RETURN_OK;
std::unique_ptr<XmppPresence> presence(XmppPresence::Create());
IFR(presence->set_raw_xml(&presence_element));
JidMemberMap::iterator pos = chatroom_jid_members_.find(presence->jid());
if (pos == chatroom_jid_members_.end()) {
if (presence->available() == XMPP_PRESENCE_AVAILABLE) {
XmppChatroomMemberImpl* member = new XmppChatroomMemberImpl();
member->SetPresence(presence.get());
chatroom_jid_members_.insert(std::make_pair(member->member_jid(), member));
chatroom_jid_members_version_++;
FireMemberEntered(member);
}
} else {
XmppChatroomMemberImpl* member = pos->second;
if (presence->available() == XMPP_PRESENCE_AVAILABLE) {
member->SetPresence(presence.get());
chatroom_jid_members_version_++;
FireMemberChanged(member);
}
else if (presence->available() == XMPP_PRESENCE_UNAVAILABLE) {
member->SetPresence(presence.get());
chatroom_jid_members_.erase(pos);
chatroom_jid_members_version_++;
FireMemberExited(member);
delete member;
}
}
return xmpp_status;
}
XmppReturnStatus
XmppChatroomModuleImpl::ClientChangeMyPresence(XmppChatroomState new_state) {
return ChangePresence(new_state, NULL, false);
}
XmppReturnStatus
XmppChatroomModuleImpl::ServerChangeMyPresence(const XmlElement& presence) {
XmppChatroomState new_state;
if (presence.HasAttr(QN_TYPE) == false) {
new_state = XMPP_CHATROOM_STATE_IN_ROOM;
} else {
new_state = XMPP_CHATROOM_STATE_NOT_IN_ROOM;
}
return ChangePresence(new_state, &presence, true);
}
XmppReturnStatus
XmppChatroomModuleImpl::ChangePresence(XmppChatroomState new_state,
const XmlElement* presence,
bool isServer) {
RTC_UNUSED(presence);
XmppChatroomState old_state = chatroom_state_;
// do nothing if state hasn't changed
if (old_state == new_state)
return XMPP_RETURN_OK;
// find the right transition description
StateTransitionDescription* transition_desc = NULL;
for (size_t i = 0; i < arraysize(Transitions); i++) {
if (Transitions[i].old_state == old_state &&
Transitions[i].new_state == new_state) {
transition_desc = &Transitions[i];
break;
}
}
if (transition_desc == NULL) {
ASSERT(0);
return XMPP_RETURN_BADSTATE;
}
// we assert for any invalid transition states, and we'll
if (isServer) {
// $TODO send original stanza back to server and log an error?
// Disable the assert because of b/6133072
// ASSERT(transition_desc->is_valid_server_transition);
if (!transition_desc->is_valid_server_transition) {
return XMPP_RETURN_BADSTATE;
}
} else {
if (transition_desc->is_valid_client_transition == false) {
ASSERT(0);
return XMPP_RETURN_BADARGUMENT;
}
}
// set the new state and then fire any notifications to the handler
chatroom_state_ = new_state;
switch (transition_desc->transition_type) {
case TRANSITION_TYPE_ENTER_SUCCESS:
FireEnteredStatus(presence, XMPP_CHATROOM_ENTERED_SUCCESS);
break;
case TRANSITION_TYPE_ENTER_FAILURE:
FireEnteredStatus(presence, GetEnterFailureFromXml(presence));
break;
case TRANSITION_TYPE_EXIT_INVOLUNTARILY:
FireExitStatus(GetExitFailureFromXml(presence));
break;
case TRANSITION_TYPE_EXIT_VOLUNTARILY:
FireExitStatus(XMPP_CHATROOM_EXITED_REQUESTED);
break;
case TRANSITION_TYPE_NONE:
break;
}
return XMPP_RETURN_OK;
}
XmppChatroomEnteredStatus
XmppChatroomModuleImpl::GetEnterFailureFromXml(const XmlElement* presence) {
XmppChatroomEnteredStatus status = XMPP_CHATROOM_ENTERED_FAILURE_UNSPECIFIED;
const XmlElement* error = presence->FirstNamed(QN_ERROR);
if (error != NULL && error->HasAttr(QN_CODE)) {
int code = atoi(error->Attr(QN_CODE).c_str());
switch (code) {
case 401: status = XMPP_CHATROOM_ENTERED_FAILURE_PASSWORD_REQUIRED; break;
case 403: {
status = XMPP_CHATROOM_ENTERED_FAILURE_MEMBER_BANNED;
if (error->FirstNamed(QN_GOOGLE_SESSION_BLOCKED)) {
status = XMPP_CHATROOM_ENTERED_FAILURE_MEMBER_BLOCKED;
} else if (error->FirstNamed(QN_GOOGLE_SESSION_BLOCKING)) {
status = XMPP_CHATROOM_ENTERED_FAILURE_MEMBER_BLOCKING;
}
break;
}
case 405: status = XMPP_CHATROOM_ENTERED_FAILURE_ROOM_LOCKED; break;
case 406: status = XMPP_CHATROOM_ENTERED_FAILURE_OUTDATED_CLIENT; break;
case 407: status = XMPP_CHATROOM_ENTERED_FAILURE_NOT_A_MEMBER; break;
case 409: status = XMPP_CHATROOM_ENTERED_FAILURE_NICKNAME_CONFLICT; break;
// http://xmpp.org/extensions/xep-0045.html#enter-maxusers
case 503: status = XMPP_CHATROOM_ENTERED_FAILURE_MAX_USERS; break;
}
}
return status;
}
XmppChatroomExitedStatus
XmppChatroomModuleImpl::GetExitFailureFromXml(const XmlElement* presence) {
XmppChatroomExitedStatus status = XMPP_CHATROOM_EXITED_UNSPECIFIED;
const XmlElement* muc_user = presence->FirstNamed(QN_MUC_USER_X);
if (muc_user != NULL) {
const XmlElement* user_status = muc_user->FirstNamed(QN_MUC_USER_STATUS);
if (user_status != NULL && user_status->HasAttr(QN_CODE)) {
int code = atoi(user_status->Attr(QN_CODE).c_str());
switch (code) {
case 307: status = XMPP_CHATROOM_EXITED_KICKED; break;
case 322: status = XMPP_CHATROOM_EXITED_NOT_A_MEMBER; break;
case 332: status = XMPP_CHATROOM_EXITED_SYSTEM_SHUTDOWN; break;
}
}
}
return status;
}
XmppReturnStatus
XmppChatroomMemberImpl::SetPresence(const XmppPresence* presence) {
ASSERT(presence != NULL);
// copy presence
presence_.reset(XmppPresence::Create());
presence_->set_raw_xml(presence->raw_xml());
return XMPP_RETURN_OK;
}
const Jid
XmppChatroomMemberImpl::member_jid() const {
return presence_->jid();
}
const Jid
XmppChatroomMemberImpl::full_jid() const {
return Jid("");
}
const std::string
XmppChatroomMemberImpl::name() const {
return member_jid().resource();
}
const XmppPresence*
XmppChatroomMemberImpl::presence() const {
return presence_.get();
}
// XmppChatroomMemberEnumeratorImpl --------------------------------------
XmppChatroomMemberEnumeratorImpl::XmppChatroomMemberEnumeratorImpl(
XmppChatroomModuleImpl::JidMemberMap* map, int* map_version) {
map_ = map;
map_version_ = map_version;
map_version_created_ = *map_version_;
iterator_ = map->begin();
before_beginning_ = true;
}
XmppChatroomMember*
XmppChatroomMemberEnumeratorImpl::current() {
if (IsValid() == false) {
return NULL;
} else if (IsBeforeBeginning() || IsAfterEnd()) {
return NULL;
} else {
return iterator_->second;
}
}
bool
XmppChatroomMemberEnumeratorImpl::Prev() {
if (IsValid() == false) {
return false;
} else if (IsBeforeBeginning()) {
return false;
} else if (iterator_ == map_->begin()) {
before_beginning_ = true;
return false;
} else {
iterator_--;
return current() != NULL;
}
}
bool
XmppChatroomMemberEnumeratorImpl::Next() {
if (IsValid() == false) {
return false;
} else if (IsBeforeBeginning()) {
before_beginning_ = false;
iterator_ = map_->begin();
return current() != NULL;
} else if (IsAfterEnd()) {
return false;
} else {
iterator_++;
return current() != NULL;
}
}
bool
XmppChatroomMemberEnumeratorImpl::IsValid() {
return map_version_created_ == *map_version_;
}
bool
XmppChatroomMemberEnumeratorImpl::IsBeforeBeginning() {
return before_beginning_;
}
bool
XmppChatroomMemberEnumeratorImpl::IsAfterEnd() {
return (iterator_ == map_->end());
}
} // namespace buzz

View File

@ -1,613 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/xmpp/constants.h"
#include <string>
#include "webrtc/libjingle/xmllite/qname.h"
#include "webrtc/libjingle/xmllite/xmlconstants.h"
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/libjingle/xmpp/jid.h"
namespace buzz {
// TODO: Remove static objects of complex types, particularly
// Jid and QName.
const char NS_CLIENT[] = "jabber:client";
const char NS_SERVER[] = "jabber:server";
const char NS_STREAM[] = "http://etherx.jabber.org/streams";
const char NS_XSTREAM[] = "urn:ietf:params:xml:ns:xmpp-streams";
const char NS_TLS[] = "urn:ietf:params:xml:ns:xmpp-tls";
const char NS_SASL[] = "urn:ietf:params:xml:ns:xmpp-sasl";
const char NS_BIND[] = "urn:ietf:params:xml:ns:xmpp-bind";
const char NS_DIALBACK[] = "jabber:server:dialback";
const char NS_SESSION[] = "urn:ietf:params:xml:ns:xmpp-session";
const char NS_STANZA[] = "urn:ietf:params:xml:ns:xmpp-stanzas";
const char NS_PRIVACY[] = "jabber:iq:privacy";
const char NS_ROSTER[] = "jabber:iq:roster";
const char NS_VCARD[] = "vcard-temp";
const char NS_AVATAR_HASH[] = "google:avatar";
const char NS_VCARD_UPDATE[] = "vcard-temp:x:update";
const char STR_CLIENT[] = "client";
const char STR_SERVER[] = "server";
const char STR_STREAM[] = "stream";
const char STR_GET[] = "get";
const char STR_SET[] = "set";
const char STR_RESULT[] = "result";
const char STR_ERROR[] = "error";
const char STR_FORM[] = "form";
const char STR_SUBMIT[] = "submit";
const char STR_TEXT_SINGLE[] = "text-single";
const char STR_LIST_SINGLE[] = "list-single";
const char STR_LIST_MULTI[] = "list-multi";
const char STR_HIDDEN[] = "hidden";
const char STR_FORM_TYPE[] = "FORM_TYPE";
const char STR_FROM[] = "from";
const char STR_TO[] = "to";
const char STR_BOTH[] = "both";
const char STR_REMOVE[] = "remove";
const char STR_TRUE[] = "true";
const char STR_TYPE[] = "type";
const char STR_NAME[] = "name";
const char STR_ID[] = "id";
const char STR_JID[] = "jid";
const char STR_SUBSCRIPTION[] = "subscription";
const char STR_ASK[] = "ask";
const char STR_X[] = "x";
const char STR_GOOGLE_COM[] = "google.com";
const char STR_GMAIL_COM[] = "gmail.com";
const char STR_GOOGLEMAIL_COM[] = "googlemail.com";
const char STR_DEFAULT_DOMAIN[] = "default.talk.google.com";
const char STR_TALK_GOOGLE_COM[] = "talk.google.com";
const char STR_TALKX_L_GOOGLE_COM[] = "talkx.l.google.com";
const char STR_XMPP_GOOGLE_COM[] = "xmpp.google.com";
const char STR_XMPPX_L_GOOGLE_COM[] = "xmppx.l.google.com";
#ifdef FEATURE_ENABLE_VOICEMAIL
const char STR_VOICEMAIL[] = "voicemail";
const char STR_OUTGOINGVOICEMAIL[] = "outgoingvoicemail";
#endif
const char STR_UNAVAILABLE[] = "unavailable";
const char NS_PING[] = "urn:xmpp:ping";
const StaticQName QN_PING = { NS_PING, "ping" };
const char NS_MUC_UNIQUE[] = "http://jabber.org/protocol/muc#unique";
const StaticQName QN_MUC_UNIQUE_QUERY = { NS_MUC_UNIQUE, "unique" };
const StaticQName QN_HANGOUT_ID = { STR_EMPTY, "hangout-id" };
const char STR_GOOGLE_MUC_LOOKUP_JID[] = "lookup.groupchat.google.com";
const char STR_MUC_ROOMCONFIG_ROOMNAME[] = "muc#roomconfig_roomname";
const char STR_MUC_ROOMCONFIG_FEATURES[] = "muc#roomconfig_features";
const char STR_MUC_ROOM_FEATURE_ENTERPRISE[] = "muc_enterprise";
const char STR_MUC_ROOMCONFIG[] = "http://jabber.org/protocol/muc#roomconfig";
const char STR_MUC_ROOM_FEATURE_HANGOUT[] = "muc_es";
const char STR_MUC_ROOM_FEATURE_HANGOUT_LITE[] = "muc_lite";
const char STR_MUC_ROOM_FEATURE_BROADCAST[] = "broadcast";
const char STR_MUC_ROOM_FEATURE_MULTI_USER_VC[] = "muc_muvc";
const char STR_MUC_ROOM_FEATURE_RECORDABLE[] = "recordable";
const char STR_MUC_ROOM_FEATURE_CUSTOM_RECORDING[] = "custom_recording";
const char STR_MUC_ROOM_OWNER_PROFILE_ID[] = "muc#roominfo_owner_profile_id";
const char STR_MUC_ROOM_FEATURE_ABUSE_RECORDABLE[] = "abuse_recordable";
const char STR_ID_TYPE_CONVERSATION[] = "conversation";
const char NS_GOOGLE_MUC_HANGOUT[] = "google:muc#hangout";
const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITE =
{ NS_GOOGLE_MUC_HANGOUT, "invite" };
const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITE_TYPE =
{ NS_GOOGLE_MUC_HANGOUT, "invite-type" };
const StaticQName QN_ATTR_CREATE_ACTIVITY =
{ STR_EMPTY, "create-activity" };
const StaticQName QN_GOOGLE_MUC_HANGOUT_PUBLIC =
{ NS_GOOGLE_MUC_HANGOUT, "public" };
const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITEE =
{ NS_GOOGLE_MUC_HANGOUT, "invitee" };
const StaticQName QN_GOOGLE_MUC_HANGOUT_NOTIFICATION_STATUS =
{ NS_GOOGLE_MUC_HANGOUT, "notification-status" };
const StaticQName QN_GOOGLE_MUC_HANGOUT_NOTIFICATION_TYPE = {
NS_GOOGLE_MUC_HANGOUT, "notification-type" };
const StaticQName QN_GOOGLE_MUC_HANGOUT_HANGOUT_START_CONTEXT = {
NS_GOOGLE_MUC_HANGOUT, "hangout-start-context" };
const StaticQName QN_GOOGLE_MUC_HANGOUT_CONVERSATION_ID = {
NS_GOOGLE_MUC_HANGOUT, "conversation-id" };
const StaticQName QN_STREAM_STREAM = { NS_STREAM, STR_STREAM };
const StaticQName QN_STREAM_FEATURES = { NS_STREAM, "features" };
const StaticQName QN_STREAM_ERROR = { NS_STREAM, "error" };
const StaticQName QN_XSTREAM_BAD_FORMAT = { NS_XSTREAM, "bad-format" };
const StaticQName QN_XSTREAM_BAD_NAMESPACE_PREFIX =
{ NS_XSTREAM, "bad-namespace-prefix" };
const StaticQName QN_XSTREAM_CONFLICT = { NS_XSTREAM, "conflict" };
const StaticQName QN_XSTREAM_CONNECTION_TIMEOUT =
{ NS_XSTREAM, "connection-timeout" };
const StaticQName QN_XSTREAM_HOST_GONE = { NS_XSTREAM, "host-gone" };
const StaticQName QN_XSTREAM_HOST_UNKNOWN = { NS_XSTREAM, "host-unknown" };
const StaticQName QN_XSTREAM_IMPROPER_ADDRESSIING =
{ NS_XSTREAM, "improper-addressing" };
const StaticQName QN_XSTREAM_INTERNAL_SERVER_ERROR =
{ NS_XSTREAM, "internal-server-error" };
const StaticQName QN_XSTREAM_INVALID_FROM = { NS_XSTREAM, "invalid-from" };
const StaticQName QN_XSTREAM_INVALID_ID = { NS_XSTREAM, "invalid-id" };
const StaticQName QN_XSTREAM_INVALID_NAMESPACE =
{ NS_XSTREAM, "invalid-namespace" };
const StaticQName QN_XSTREAM_INVALID_XML = { NS_XSTREAM, "invalid-xml" };
const StaticQName QN_XSTREAM_NOT_AUTHORIZED = { NS_XSTREAM, "not-authorized" };
const StaticQName QN_XSTREAM_POLICY_VIOLATION =
{ NS_XSTREAM, "policy-violation" };
const StaticQName QN_XSTREAM_REMOTE_CONNECTION_FAILED =
{ NS_XSTREAM, "remote-connection-failed" };
const StaticQName QN_XSTREAM_RESOURCE_CONSTRAINT =
{ NS_XSTREAM, "resource-constraint" };
const StaticQName QN_XSTREAM_RESTRICTED_XML = { NS_XSTREAM, "restricted-xml" };
const StaticQName QN_XSTREAM_SEE_OTHER_HOST = { NS_XSTREAM, "see-other-host" };
const StaticQName QN_XSTREAM_SYSTEM_SHUTDOWN =
{ NS_XSTREAM, "system-shutdown" };
const StaticQName QN_XSTREAM_UNDEFINED_CONDITION =
{ NS_XSTREAM, "undefined-condition" };
const StaticQName QN_XSTREAM_UNSUPPORTED_ENCODING =
{ NS_XSTREAM, "unsupported-encoding" };
const StaticQName QN_XSTREAM_UNSUPPORTED_STANZA_TYPE =
{ NS_XSTREAM, "unsupported-stanza-type" };
const StaticQName QN_XSTREAM_UNSUPPORTED_VERSION =
{ NS_XSTREAM, "unsupported-version" };
const StaticQName QN_XSTREAM_XML_NOT_WELL_FORMED =
{ NS_XSTREAM, "xml-not-well-formed" };
const StaticQName QN_XSTREAM_TEXT = { NS_XSTREAM, "text" };
const StaticQName QN_TLS_STARTTLS = { NS_TLS, "starttls" };
const StaticQName QN_TLS_REQUIRED = { NS_TLS, "required" };
const StaticQName QN_TLS_PROCEED = { NS_TLS, "proceed" };
const StaticQName QN_TLS_FAILURE = { NS_TLS, "failure" };
const StaticQName QN_SASL_MECHANISMS = { NS_SASL, "mechanisms" };
const StaticQName QN_SASL_MECHANISM = { NS_SASL, "mechanism" };
const StaticQName QN_SASL_AUTH = { NS_SASL, "auth" };
const StaticQName QN_SASL_CHALLENGE = { NS_SASL, "challenge" };
const StaticQName QN_SASL_RESPONSE = { NS_SASL, "response" };
const StaticQName QN_SASL_ABORT = { NS_SASL, "abort" };
const StaticQName QN_SASL_SUCCESS = { NS_SASL, "success" };
const StaticQName QN_SASL_FAILURE = { NS_SASL, "failure" };
const StaticQName QN_SASL_ABORTED = { NS_SASL, "aborted" };
const StaticQName QN_SASL_INCORRECT_ENCODING =
{ NS_SASL, "incorrect-encoding" };
const StaticQName QN_SASL_INVALID_AUTHZID = { NS_SASL, "invalid-authzid" };
const StaticQName QN_SASL_INVALID_MECHANISM = { NS_SASL, "invalid-mechanism" };
const StaticQName QN_SASL_MECHANISM_TOO_WEAK =
{ NS_SASL, "mechanism-too-weak" };
const StaticQName QN_SASL_NOT_AUTHORIZED = { NS_SASL, "not-authorized" };
const StaticQName QN_SASL_TEMPORARY_AUTH_FAILURE =
{ NS_SASL, "temporary-auth-failure" };
// These are non-standard.
const char NS_GOOGLE_AUTH_PROTOCOL[] =
"http://www.google.com/talk/protocol/auth";
const StaticQName QN_GOOGLE_AUTH_CLIENT_USES_FULL_BIND_RESULT =
{ NS_GOOGLE_AUTH_PROTOCOL, "client-uses-full-bind-result" };
const StaticQName QN_GOOGLE_ALLOW_NON_GOOGLE_ID_XMPP_LOGIN =
{ NS_GOOGLE_AUTH_PROTOCOL, "allow-non-google-login" };
const StaticQName QN_GOOGLE_AUTH_SERVICE =
{ NS_GOOGLE_AUTH_PROTOCOL, "service" };
const StaticQName QN_DIALBACK_RESULT = { NS_DIALBACK, "result" };
const StaticQName QN_DIALBACK_VERIFY = { NS_DIALBACK, "verify" };
const StaticQName QN_STANZA_BAD_REQUEST = { NS_STANZA, "bad-request" };
const StaticQName QN_STANZA_CONFLICT = { NS_STANZA, "conflict" };
const StaticQName QN_STANZA_FEATURE_NOT_IMPLEMENTED =
{ NS_STANZA, "feature-not-implemented" };
const StaticQName QN_STANZA_FORBIDDEN = { NS_STANZA, "forbidden" };
const StaticQName QN_STANZA_GONE = { NS_STANZA, "gone" };
const StaticQName QN_STANZA_INTERNAL_SERVER_ERROR =
{ NS_STANZA, "internal-server-error" };
const StaticQName QN_STANZA_ITEM_NOT_FOUND = { NS_STANZA, "item-not-found" };
const StaticQName QN_STANZA_JID_MALFORMED = { NS_STANZA, "jid-malformed" };
const StaticQName QN_STANZA_NOT_ACCEPTABLE = { NS_STANZA, "not-acceptable" };
const StaticQName QN_STANZA_NOT_ALLOWED = { NS_STANZA, "not-allowed" };
const StaticQName QN_STANZA_PAYMENT_REQUIRED =
{ NS_STANZA, "payment-required" };
const StaticQName QN_STANZA_RECIPIENT_UNAVAILABLE =
{ NS_STANZA, "recipient-unavailable" };
const StaticQName QN_STANZA_REDIRECT = { NS_STANZA, "redirect" };
const StaticQName QN_STANZA_REGISTRATION_REQUIRED =
{ NS_STANZA, "registration-required" };
const StaticQName QN_STANZA_REMOTE_SERVER_NOT_FOUND =
{ NS_STANZA, "remote-server-not-found" };
const StaticQName QN_STANZA_REMOTE_SERVER_TIMEOUT =
{ NS_STANZA, "remote-server-timeout" };
const StaticQName QN_STANZA_RESOURCE_CONSTRAINT =
{ NS_STANZA, "resource-constraint" };
const StaticQName QN_STANZA_SERVICE_UNAVAILABLE =
{ NS_STANZA, "service-unavailable" };
const StaticQName QN_STANZA_SUBSCRIPTION_REQUIRED =
{ NS_STANZA, "subscription-required" };
const StaticQName QN_STANZA_UNDEFINED_CONDITION =
{ NS_STANZA, "undefined-condition" };
const StaticQName QN_STANZA_UNEXPECTED_REQUEST =
{ NS_STANZA, "unexpected-request" };
const StaticQName QN_STANZA_TEXT = { NS_STANZA, "text" };
const StaticQName QN_BIND_BIND = { NS_BIND, "bind" };
const StaticQName QN_BIND_RESOURCE = { NS_BIND, "resource" };
const StaticQName QN_BIND_JID = { NS_BIND, "jid" };
const StaticQName QN_MESSAGE = { NS_CLIENT, "message" };
const StaticQName QN_BODY = { NS_CLIENT, "body" };
const StaticQName QN_SUBJECT = { NS_CLIENT, "subject" };
const StaticQName QN_THREAD = { NS_CLIENT, "thread" };
const StaticQName QN_PRESENCE = { NS_CLIENT, "presence" };
const StaticQName QN_SHOW = { NS_CLIENT, "show" };
const StaticQName QN_STATUS = { NS_CLIENT, "status" };
const StaticQName QN_LANG = { NS_CLIENT, "lang" };
const StaticQName QN_PRIORITY = { NS_CLIENT, "priority" };
const StaticQName QN_IQ = { NS_CLIENT, "iq" };
const StaticQName QN_ERROR = { NS_CLIENT, "error" };
const StaticQName QN_SERVER_MESSAGE = { NS_SERVER, "message" };
const StaticQName QN_SERVER_BODY = { NS_SERVER, "body" };
const StaticQName QN_SERVER_SUBJECT = { NS_SERVER, "subject" };
const StaticQName QN_SERVER_THREAD = { NS_SERVER, "thread" };
const StaticQName QN_SERVER_PRESENCE = { NS_SERVER, "presence" };
const StaticQName QN_SERVER_SHOW = { NS_SERVER, "show" };
const StaticQName QN_SERVER_STATUS = { NS_SERVER, "status" };
const StaticQName QN_SERVER_LANG = { NS_SERVER, "lang" };
const StaticQName QN_SERVER_PRIORITY = { NS_SERVER, "priority" };
const StaticQName QN_SERVER_IQ = { NS_SERVER, "iq" };
const StaticQName QN_SERVER_ERROR = { NS_SERVER, "error" };
const StaticQName QN_SESSION_SESSION = { NS_SESSION, "session" };
const StaticQName QN_PRIVACY_QUERY = { NS_PRIVACY, "query" };
const StaticQName QN_PRIVACY_ACTIVE = { NS_PRIVACY, "active" };
const StaticQName QN_PRIVACY_DEFAULT = { NS_PRIVACY, "default" };
const StaticQName QN_PRIVACY_LIST = { NS_PRIVACY, "list" };
const StaticQName QN_PRIVACY_ITEM = { NS_PRIVACY, "item" };
const StaticQName QN_PRIVACY_IQ = { NS_PRIVACY, "iq" };
const StaticQName QN_PRIVACY_MESSAGE = { NS_PRIVACY, "message" };
const StaticQName QN_PRIVACY_PRESENCE_IN = { NS_PRIVACY, "presence-in" };
const StaticQName QN_PRIVACY_PRESENCE_OUT = { NS_PRIVACY, "presence-out" };
const StaticQName QN_ROSTER_QUERY = { NS_ROSTER, "query" };
const StaticQName QN_ROSTER_ITEM = { NS_ROSTER, "item" };
const StaticQName QN_ROSTER_GROUP = { NS_ROSTER, "group" };
const StaticQName QN_VCARD = { NS_VCARD, "vCard" };
const StaticQName QN_VCARD_FN = { NS_VCARD, "FN" };
const StaticQName QN_VCARD_PHOTO = { NS_VCARD, "PHOTO" };
const StaticQName QN_VCARD_PHOTO_BINVAL = { NS_VCARD, "BINVAL" };
const StaticQName QN_VCARD_AVATAR_HASH = { NS_AVATAR_HASH, "hash" };
const StaticQName QN_VCARD_AVATAR_HASH_MODIFIED =
{ NS_AVATAR_HASH, "modified" };
const StaticQName QN_NAME = { STR_EMPTY, "name" };
const StaticQName QN_AFFILIATION = { STR_EMPTY, "affiliation" };
const StaticQName QN_ROLE = { STR_EMPTY, "role" };
#if defined(FEATURE_ENABLE_PSTN)
const StaticQName QN_VCARD_TEL = { NS_VCARD, "TEL" };
const StaticQName QN_VCARD_VOICE = { NS_VCARD, "VOICE" };
const StaticQName QN_VCARD_HOME = { NS_VCARD, "HOME" };
const StaticQName QN_VCARD_WORK = { NS_VCARD, "WORK" };
const StaticQName QN_VCARD_CELL = { NS_VCARD, "CELL" };
const StaticQName QN_VCARD_NUMBER = { NS_VCARD, "NUMBER" };
#endif
const StaticQName QN_XML_LANG = { NS_XML, "lang" };
const StaticQName QN_ENCODING = { STR_EMPTY, STR_ENCODING };
const StaticQName QN_VERSION = { STR_EMPTY, STR_VERSION };
const StaticQName QN_TO = { STR_EMPTY, "to" };
const StaticQName QN_FROM = { STR_EMPTY, "from" };
const StaticQName QN_TYPE = { STR_EMPTY, "type" };
const StaticQName QN_ID = { STR_EMPTY, "id" };
const StaticQName QN_CODE = { STR_EMPTY, "code" };
const StaticQName QN_VALUE = { STR_EMPTY, "value" };
const StaticQName QN_ACTION = { STR_EMPTY, "action" };
const StaticQName QN_ORDER = { STR_EMPTY, "order" };
const StaticQName QN_MECHANISM = { STR_EMPTY, "mechanism" };
const StaticQName QN_ASK = { STR_EMPTY, "ask" };
const StaticQName QN_JID = { STR_EMPTY, "jid" };
const StaticQName QN_NICK = { STR_EMPTY, "nick" };
const StaticQName QN_SUBSCRIPTION = { STR_EMPTY, "subscription" };
const StaticQName QN_TITLE1 = { STR_EMPTY, "title1" };
const StaticQName QN_TITLE2 = { STR_EMPTY, "title2" };
const StaticQName QN_XMLNS_CLIENT = { NS_XMLNS, STR_CLIENT };
const StaticQName QN_XMLNS_SERVER = { NS_XMLNS, STR_SERVER };
const StaticQName QN_XMLNS_STREAM = { NS_XMLNS, STR_STREAM };
// Presence
const char STR_SHOW_AWAY[] = "away";
const char STR_SHOW_CHAT[] = "chat";
const char STR_SHOW_DND[] = "dnd";
const char STR_SHOW_XA[] = "xa";
const char STR_SHOW_OFFLINE[] = "offline";
const char NS_GOOGLE_PSTN_CONFERENCE[] = "http://www.google.com/pstn-conference";
const StaticQName QN_GOOGLE_PSTN_CONFERENCE_STATUS = { NS_GOOGLE_PSTN_CONFERENCE, "status" };
const StaticQName QN_ATTR_STATUS = { STR_EMPTY, "status" };
// Presence connection status
const char STR_PSTN_CONFERENCE_STATUS_CONNECTING[] = "connecting";
const char STR_PSTN_CONFERENCE_STATUS_JOINING[] = "joining";
const char STR_PSTN_CONFERENCE_STATUS_CONNECTED[] = "connected";
const char STR_PSTN_CONFERENCE_STATUS_HANGUP[] = "hangup";
// Subscription
const char STR_SUBSCRIBE[] = "subscribe";
const char STR_SUBSCRIBED[] = "subscribed";
const char STR_UNSUBSCRIBE[] = "unsubscribe";
const char STR_UNSUBSCRIBED[] = "unsubscribed";
// Google Invite
const char NS_GOOGLE_SUBSCRIBE[] = "google:subscribe";
const StaticQName QN_INVITATION = { NS_GOOGLE_SUBSCRIBE, "invitation" };
const StaticQName QN_INVITE_NAME = { NS_GOOGLE_SUBSCRIBE, "name" };
const StaticQName QN_INVITE_SUBJECT = { NS_GOOGLE_SUBSCRIBE, "subject" };
const StaticQName QN_INVITE_MESSAGE = { NS_GOOGLE_SUBSCRIBE, "body" };
// Kick
const char NS_GOOGLE_MUC_ADMIN[] = "google:muc#admin";
const StaticQName QN_GOOGLE_MUC_ADMIN_QUERY = { NS_GOOGLE_MUC_ADMIN, "query" };
const StaticQName QN_GOOGLE_MUC_ADMIN_QUERY_ITEM =
{ NS_GOOGLE_MUC_ADMIN, "item" };
const StaticQName QN_GOOGLE_MUC_ADMIN_QUERY_ITEM_REASON =
{ NS_GOOGLE_MUC_ADMIN, "reason" };
// PubSub: http://xmpp.org/extensions/xep-0060.html
const char NS_PUBSUB[] = "http://jabber.org/protocol/pubsub";
const StaticQName QN_PUBSUB = { NS_PUBSUB, "pubsub" };
const StaticQName QN_PUBSUB_ITEMS = { NS_PUBSUB, "items" };
const StaticQName QN_PUBSUB_ITEM = { NS_PUBSUB, "item" };
const StaticQName QN_PUBSUB_PUBLISH = { NS_PUBSUB, "publish" };
const StaticQName QN_PUBSUB_RETRACT = { NS_PUBSUB, "retract" };
const StaticQName QN_ATTR_PUBLISHER = { STR_EMPTY, "publisher" };
const char NS_PUBSUB_EVENT[] = "http://jabber.org/protocol/pubsub#event";
const StaticQName QN_NODE = { STR_EMPTY, "node" };
const StaticQName QN_PUBSUB_EVENT = { NS_PUBSUB_EVENT, "event" };
const StaticQName QN_PUBSUB_EVENT_ITEMS = { NS_PUBSUB_EVENT, "items" };
const StaticQName QN_PUBSUB_EVENT_ITEM = { NS_PUBSUB_EVENT, "item" };
const StaticQName QN_PUBSUB_EVENT_RETRACT = { NS_PUBSUB_EVENT, "retract" };
const StaticQName QN_NOTIFY = { STR_EMPTY, "notify" };
const char NS_PRESENTER[] = "google:presenter";
const StaticQName QN_PRESENTER_PRESENTER = { NS_PRESENTER, "presenter" };
const StaticQName QN_PRESENTER_PRESENTATION_ITEM =
{ NS_PRESENTER, "presentation-item" };
const StaticQName QN_PRESENTER_PRESENTATION_TYPE =
{ NS_PRESENTER, "presentation-type" };
const StaticQName QN_PRESENTER_PRESENTATION_ID =
{ NS_PRESENTER, "presentation-id" };
// JEP 0030
const StaticQName QN_CATEGORY = { STR_EMPTY, "category" };
const StaticQName QN_VAR = { STR_EMPTY, "var" };
const char NS_DISCO_INFO[] = "http://jabber.org/protocol/disco#info";
const char NS_DISCO_ITEMS[] = "http://jabber.org/protocol/disco#items";
const StaticQName QN_DISCO_INFO_QUERY = { NS_DISCO_INFO, "query" };
const StaticQName QN_DISCO_IDENTITY = { NS_DISCO_INFO, "identity" };
const StaticQName QN_DISCO_FEATURE = { NS_DISCO_INFO, "feature" };
const StaticQName QN_DISCO_ITEMS_QUERY = { NS_DISCO_ITEMS, "query" };
const StaticQName QN_DISCO_ITEM = { NS_DISCO_ITEMS, "item" };
// JEP 0020
const char NS_FEATURE[] = "http://jabber.org/protocol/feature-neg";
const StaticQName QN_FEATURE_FEATURE = { NS_FEATURE, "feature" };
// JEP 0004
const char NS_XDATA[] = "jabber:x:data";
const StaticQName QN_XDATA_X = { NS_XDATA, "x" };
const StaticQName QN_XDATA_INSTRUCTIONS = { NS_XDATA, "instructions" };
const StaticQName QN_XDATA_TITLE = { NS_XDATA, "title" };
const StaticQName QN_XDATA_FIELD = { NS_XDATA, "field" };
const StaticQName QN_XDATA_REPORTED = { NS_XDATA, "reported" };
const StaticQName QN_XDATA_ITEM = { NS_XDATA, "item" };
const StaticQName QN_XDATA_DESC = { NS_XDATA, "desc" };
const StaticQName QN_XDATA_REQUIRED = { NS_XDATA, "required" };
const StaticQName QN_XDATA_VALUE = { NS_XDATA, "value" };
const StaticQName QN_XDATA_OPTION = { NS_XDATA, "option" };
// JEP 0045
const char NS_MUC[] = "http://jabber.org/protocol/muc";
const StaticQName QN_MUC_X = { NS_MUC, "x" };
const StaticQName QN_MUC_ITEM = { NS_MUC, "item" };
const StaticQName QN_MUC_AFFILIATION = { NS_MUC, "affiliation" };
const StaticQName QN_MUC_ROLE = { NS_MUC, "role" };
const char STR_AFFILIATION_NONE[] = "none";
const char STR_ROLE_PARTICIPANT[] = "participant";
const char NS_GOOGLE_SESSION[] = "http://www.google.com/session";
const StaticQName QN_GOOGLE_CIRCLE_ID = { STR_EMPTY, "google-circle-id" };
const StaticQName QN_GOOGLE_USER_ID = { STR_EMPTY, "google-user-id" };
const StaticQName QN_GOOGLE_SESSION_BLOCKED = { NS_GOOGLE_SESSION, "blocked" };
const StaticQName QN_GOOGLE_SESSION_BLOCKING =
{ NS_GOOGLE_SESSION, "blocking" };
const char NS_MUC_OWNER[] = "http://jabber.org/protocol/muc#owner";
const StaticQName QN_MUC_OWNER_QUERY = { NS_MUC_OWNER, "query" };
const char NS_MUC_USER[] = "http://jabber.org/protocol/muc#user";
const StaticQName QN_MUC_USER_CONTINUE = { NS_MUC_USER, "continue" };
const StaticQName QN_MUC_USER_X = { NS_MUC_USER, "x" };
const StaticQName QN_MUC_USER_ITEM = { NS_MUC_USER, "item" };
const StaticQName QN_MUC_USER_STATUS = { NS_MUC_USER, "status" };
const StaticQName QN_MUC_USER_REASON = { NS_MUC_USER, "reason" };
const StaticQName QN_MUC_USER_ABUSE_VIOLATION = { NS_MUC_USER, "abuse-violation" };
// JEP 0055 - Jabber Search
const char NS_SEARCH[] = "jabber:iq:search";
const StaticQName QN_SEARCH_QUERY = { NS_SEARCH, "query" };
const StaticQName QN_SEARCH_ITEM = { NS_SEARCH, "item" };
const StaticQName QN_SEARCH_ROOM_NAME = { NS_SEARCH, "room-name" };
const StaticQName QN_SEARCH_ROOM_DOMAIN = { NS_SEARCH, "room-domain" };
const StaticQName QN_SEARCH_ROOM_JID = { NS_SEARCH, "room-jid" };
const StaticQName QN_SEARCH_HANGOUT_ID = { NS_SEARCH, "hangout-id" };
const StaticQName QN_SEARCH_EXTERNAL_ID = { NS_SEARCH, "external-id" };
// JEP 0115
const char NS_CAPS[] = "http://jabber.org/protocol/caps";
const StaticQName QN_CAPS_C = { NS_CAPS, "c" };
const StaticQName QN_VER = { STR_EMPTY, "ver" };
const StaticQName QN_EXT = { STR_EMPTY, "ext" };
// JEP 0153
const char kNSVCard[] = "vcard-temp:x:update";
const StaticQName kQnVCardX = { kNSVCard, "x" };
const StaticQName kQnVCardPhoto = { kNSVCard, "photo" };
// JEP 0172 User Nickname
const char NS_NICKNAME[] = "http://jabber.org/protocol/nick";
const StaticQName QN_NICKNAME = { NS_NICKNAME, "nick" };
// JEP 0085 chat state
const char NS_CHATSTATE[] = "http://jabber.org/protocol/chatstates";
const StaticQName QN_CS_ACTIVE = { NS_CHATSTATE, "active" };
const StaticQName QN_CS_COMPOSING = { NS_CHATSTATE, "composing" };
const StaticQName QN_CS_PAUSED = { NS_CHATSTATE, "paused" };
const StaticQName QN_CS_INACTIVE = { NS_CHATSTATE, "inactive" };
const StaticQName QN_CS_GONE = { NS_CHATSTATE, "gone" };
// JEP 0091 Delayed Delivery
const char kNSDelay[] = "jabber:x:delay";
const StaticQName kQnDelayX = { kNSDelay, "x" };
const StaticQName kQnStamp = { STR_EMPTY, "stamp" };
// Google time stamping (higher resolution)
const char kNSTimestamp[] = "google:timestamp";
const StaticQName kQnTime = { kNSTimestamp, "time" };
const StaticQName kQnMilliseconds = { STR_EMPTY, "ms" };
// Jingle Info
const char NS_JINGLE_INFO[] = "google:jingleinfo";
const StaticQName QN_JINGLE_INFO_QUERY = { NS_JINGLE_INFO, "query" };
const StaticQName QN_JINGLE_INFO_STUN = { NS_JINGLE_INFO, "stun" };
const StaticQName QN_JINGLE_INFO_RELAY = { NS_JINGLE_INFO, "relay" };
const StaticQName QN_JINGLE_INFO_SERVER = { NS_JINGLE_INFO, "server" };
const StaticQName QN_JINGLE_INFO_TOKEN = { NS_JINGLE_INFO, "token" };
const StaticQName QN_JINGLE_INFO_HOST = { STR_EMPTY, "host" };
const StaticQName QN_JINGLE_INFO_TCP = { STR_EMPTY, "tcp" };
const StaticQName QN_JINGLE_INFO_UDP = { STR_EMPTY, "udp" };
const StaticQName QN_JINGLE_INFO_TCPSSL = { STR_EMPTY, "tcpssl" };
// Call Performance Logging
const char NS_GOOGLE_CALLPERF_STATS[] = "google:call-perf-stats";
const StaticQName QN_CALLPERF_STATS =
{ NS_GOOGLE_CALLPERF_STATS, "callPerfStats" };
const StaticQName QN_CALLPERF_SESSIONID = { STR_EMPTY, "sessionId" };
const StaticQName QN_CALLPERF_LOCALUSER = { STR_EMPTY, "localUser" };
const StaticQName QN_CALLPERF_REMOTEUSER = { STR_EMPTY, "remoteUser" };
const StaticQName QN_CALLPERF_STARTTIME = { STR_EMPTY, "startTime" };
const StaticQName QN_CALLPERF_CALL_LENGTH = { STR_EMPTY, "callLength" };
const StaticQName QN_CALLPERF_CALL_ACCEPTED = { STR_EMPTY, "callAccepted" };
const StaticQName QN_CALLPERF_CALL_ERROR_CODE = { STR_EMPTY, "callErrorCode" };
const StaticQName QN_CALLPERF_TERMINATE_CODE = { STR_EMPTY, "terminateCode" };
const StaticQName QN_CALLPERF_DATAPOINT =
{ NS_GOOGLE_CALLPERF_STATS, "dataPoint" };
const StaticQName QN_CALLPERF_DATAPOINT_TIME = { STR_EMPTY, "timeStamp" };
const StaticQName QN_CALLPERF_DATAPOINT_FRACTION_LOST =
{ STR_EMPTY, "fraction_lost" };
const StaticQName QN_CALLPERF_DATAPOINT_CUM_LOST = { STR_EMPTY, "cum_lost" };
const StaticQName QN_CALLPERF_DATAPOINT_EXT_MAX = { STR_EMPTY, "ext_max" };
const StaticQName QN_CALLPERF_DATAPOINT_JITTER = { STR_EMPTY, "jitter" };
const StaticQName QN_CALLPERF_DATAPOINT_RTT = { STR_EMPTY, "RTT" };
const StaticQName QN_CALLPERF_DATAPOINT_BYTES_R =
{ STR_EMPTY, "bytesReceived" };
const StaticQName QN_CALLPERF_DATAPOINT_PACKETS_R =
{ STR_EMPTY, "packetsReceived" };
const StaticQName QN_CALLPERF_DATAPOINT_BYTES_S = { STR_EMPTY, "bytesSent" };
const StaticQName QN_CALLPERF_DATAPOINT_PACKETS_S =
{ STR_EMPTY, "packetsSent" };
const StaticQName QN_CALLPERF_DATAPOINT_PROCESS_CPU =
{ STR_EMPTY, "processCpu" };
const StaticQName QN_CALLPERF_DATAPOINT_SYSTEM_CPU = { STR_EMPTY, "systemCpu" };
const StaticQName QN_CALLPERF_DATAPOINT_CPUS = { STR_EMPTY, "cpus" };
const StaticQName QN_CALLPERF_CONNECTION =
{ NS_GOOGLE_CALLPERF_STATS, "connection" };
const StaticQName QN_CALLPERF_CONNECTION_LOCAL_ADDRESS =
{ STR_EMPTY, "localAddress" };
const StaticQName QN_CALLPERF_CONNECTION_REMOTE_ADDRESS =
{ STR_EMPTY, "remoteAddress" };
const StaticQName QN_CALLPERF_CONNECTION_FLAGS = { STR_EMPTY, "flags" };
const StaticQName QN_CALLPERF_CONNECTION_RTT = { STR_EMPTY, "rtt" };
const StaticQName QN_CALLPERF_CONNECTION_TOTAL_BYTES_S =
{ STR_EMPTY, "totalBytesSent" };
const StaticQName QN_CALLPERF_CONNECTION_BYTES_SECOND_S =
{ STR_EMPTY, "bytesSecondSent" };
const StaticQName QN_CALLPERF_CONNECTION_TOTAL_BYTES_R =
{ STR_EMPTY, "totalBytesRecv" };
const StaticQName QN_CALLPERF_CONNECTION_BYTES_SECOND_R =
{ STR_EMPTY, "bytesSecondRecv" };
const StaticQName QN_CALLPERF_CANDIDATE =
{ NS_GOOGLE_CALLPERF_STATS, "candidate" };
const StaticQName QN_CALLPERF_CANDIDATE_ENDPOINT = { STR_EMPTY, "endpoint" };
const StaticQName QN_CALLPERF_CANDIDATE_PROTOCOL = { STR_EMPTY, "protocol" };
const StaticQName QN_CALLPERF_CANDIDATE_ADDRESS = { STR_EMPTY, "address" };
const StaticQName QN_CALLPERF_MEDIA = { NS_GOOGLE_CALLPERF_STATS, "media" };
const StaticQName QN_CALLPERF_MEDIA_DIRECTION = { STR_EMPTY, "direction" };
const StaticQName QN_CALLPERF_MEDIA_SSRC = { STR_EMPTY, "SSRC" };
const StaticQName QN_CALLPERF_MEDIA_ENERGY = { STR_EMPTY, "energy" };
const StaticQName QN_CALLPERF_MEDIA_FIR = { STR_EMPTY, "fir" };
const StaticQName QN_CALLPERF_MEDIA_NACK = { STR_EMPTY, "nack" };
const StaticQName QN_CALLPERF_MEDIA_FPS = { STR_EMPTY, "fps" };
const StaticQName QN_CALLPERF_MEDIA_FPS_NETWORK = { STR_EMPTY, "fpsNetwork" };
const StaticQName QN_CALLPERF_MEDIA_FPS_DECODED = { STR_EMPTY, "fpsDecoded" };
const StaticQName QN_CALLPERF_MEDIA_JITTER_BUFFER_SIZE =
{ STR_EMPTY, "jitterBufferSize" };
const StaticQName QN_CALLPERF_MEDIA_PREFERRED_JITTER_BUFFER_SIZE =
{ STR_EMPTY, "preferredJitterBufferSize" };
const StaticQName QN_CALLPERF_MEDIA_TOTAL_PLAYOUT_DELAY =
{ STR_EMPTY, "totalPlayoutDelay" };
// Muc invites.
const StaticQName QN_MUC_USER_INVITE = { NS_MUC_USER, "invite" };
// Multiway audio/video.
const char NS_GOOGLE_MUC_USER[] = "google:muc#user";
const StaticQName QN_GOOGLE_MUC_USER_AVAILABLE_MEDIA =
{ NS_GOOGLE_MUC_USER, "available-media" };
const StaticQName QN_GOOGLE_MUC_USER_ENTRY = { NS_GOOGLE_MUC_USER, "entry" };
const StaticQName QN_GOOGLE_MUC_USER_MEDIA = { NS_GOOGLE_MUC_USER, "media" };
const StaticQName QN_GOOGLE_MUC_USER_TYPE = { NS_GOOGLE_MUC_USER, "type" };
const StaticQName QN_GOOGLE_MUC_USER_SRC_ID = { NS_GOOGLE_MUC_USER, "src-id" };
const StaticQName QN_GOOGLE_MUC_USER_STATUS = { NS_GOOGLE_MUC_USER, "status" };
const StaticQName QN_CLIENT_VERSION = { NS_GOOGLE_MUC_USER, "client-version" };
const StaticQName QN_LOCALE = { NS_GOOGLE_MUC_USER, "locale" };
const StaticQName QN_LABEL = { STR_EMPTY, "label" };
const char NS_GOOGLE_MUC_MEDIA[] = "google:muc#media";
const StaticQName QN_GOOGLE_MUC_AUDIO_MUTE =
{ NS_GOOGLE_MUC_MEDIA, "audio-mute" };
const StaticQName QN_GOOGLE_MUC_VIDEO_MUTE =
{ NS_GOOGLE_MUC_MEDIA, "video-mute" };
const StaticQName QN_GOOGLE_MUC_VIDEO_PAUSE =
{ NS_GOOGLE_MUC_MEDIA, "video-pause" };
const StaticQName QN_GOOGLE_MUC_RECORDING =
{ NS_GOOGLE_MUC_MEDIA, "recording" };
const StaticQName QN_GOOGLE_MUC_MEDIA_BLOCK = { NS_GOOGLE_MUC_MEDIA, "block" };
const StaticQName QN_STATE_ATTR = { STR_EMPTY, "state" };
const char AUTH_MECHANISM_GOOGLE_COOKIE[] = "X-GOOGLE-COOKIE";
const char AUTH_MECHANISM_GOOGLE_TOKEN[] = "X-GOOGLE-TOKEN";
const char AUTH_MECHANISM_OAUTH2[] = "X-OAUTH2";
const char AUTH_MECHANISM_PLAIN[] = "PLAIN";
} // namespace buzz

View File

@ -1,551 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_CONSTANTS_H_
#define WEBRTC_LIBJINGLE_XMPP_CONSTANTS_H_
#include <string>
#include "webrtc/libjingle/xmllite/qname.h"
#include "webrtc/libjingle/xmpp/jid.h"
namespace buzz {
extern const char NS_CLIENT[];
extern const char NS_SERVER[];
extern const char NS_STREAM[];
extern const char NS_XSTREAM[];
extern const char NS_TLS[];
extern const char NS_SASL[];
extern const char NS_BIND[];
extern const char NS_DIALBACK[];
extern const char NS_SESSION[];
extern const char NS_STANZA[];
extern const char NS_PRIVACY[];
extern const char NS_ROSTER[];
extern const char NS_VCARD[];
extern const char NS_AVATAR_HASH[];
extern const char NS_VCARD_UPDATE[];
extern const char STR_CLIENT[];
extern const char STR_SERVER[];
extern const char STR_STREAM[];
extern const char STR_GET[];
extern const char STR_SET[];
extern const char STR_RESULT[];
extern const char STR_ERROR[];
extern const char STR_FORM[];
extern const char STR_SUBMIT[];
extern const char STR_TEXT_SINGLE[];
extern const char STR_LIST_SINGLE[];
extern const char STR_LIST_MULTI[];
extern const char STR_HIDDEN[];
extern const char STR_FORM_TYPE[];
extern const char STR_FROM[];
extern const char STR_TO[];
extern const char STR_BOTH[];
extern const char STR_REMOVE[];
extern const char STR_TRUE[];
extern const char STR_TYPE[];
extern const char STR_NAME[];
extern const char STR_ID[];
extern const char STR_JID[];
extern const char STR_SUBSCRIPTION[];
extern const char STR_ASK[];
extern const char STR_X[];
extern const char STR_GOOGLE_COM[];
extern const char STR_GMAIL_COM[];
extern const char STR_GOOGLEMAIL_COM[];
extern const char STR_DEFAULT_DOMAIN[];
extern const char STR_TALK_GOOGLE_COM[];
extern const char STR_TALKX_L_GOOGLE_COM[];
extern const char STR_XMPP_GOOGLE_COM[];
extern const char STR_XMPPX_L_GOOGLE_COM[];
#ifdef FEATURE_ENABLE_VOICEMAIL
extern const char STR_VOICEMAIL[];
extern const char STR_OUTGOINGVOICEMAIL[];
#endif
extern const char STR_UNAVAILABLE[];
extern const char NS_PING[];
extern const StaticQName QN_PING;
extern const char NS_MUC_UNIQUE[];
extern const StaticQName QN_MUC_UNIQUE_QUERY;
extern const StaticQName QN_HANGOUT_ID;
extern const char STR_GOOGLE_MUC_LOOKUP_JID[];
extern const char STR_MUC_ROOMCONFIG_ROOMNAME[];
extern const char STR_MUC_ROOMCONFIG_FEATURES[];
extern const char STR_MUC_ROOM_FEATURE_ENTERPRISE[];
extern const char STR_MUC_ROOMCONFIG[];
extern const char STR_MUC_ROOM_FEATURE_HANGOUT[];
extern const char STR_MUC_ROOM_FEATURE_HANGOUT_LITE[];
extern const char STR_MUC_ROOM_FEATURE_BROADCAST[];
extern const char STR_MUC_ROOM_FEATURE_MULTI_USER_VC[];
extern const char STR_MUC_ROOM_FEATURE_RECORDABLE[];
extern const char STR_MUC_ROOM_FEATURE_CUSTOM_RECORDING[];
extern const char STR_MUC_ROOM_OWNER_PROFILE_ID[];
extern const char STR_MUC_ROOM_FEATURE_ABUSE_RECORDABLE[];
extern const char STR_ID_TYPE_CONVERSATION[];
extern const char NS_GOOGLE_MUC_HANGOUT[];
extern const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITE;
extern const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITE_TYPE;
extern const StaticQName QN_ATTR_CREATE_ACTIVITY;
extern const StaticQName QN_GOOGLE_MUC_HANGOUT_PUBLIC;
extern const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITEE;
extern const StaticQName QN_GOOGLE_MUC_HANGOUT_NOTIFICATION_STATUS;
extern const StaticQName QN_GOOGLE_MUC_HANGOUT_NOTIFICATION_TYPE;
extern const StaticQName QN_GOOGLE_MUC_HANGOUT_HANGOUT_START_CONTEXT;
extern const StaticQName QN_GOOGLE_MUC_HANGOUT_CONVERSATION_ID;
extern const StaticQName QN_STREAM_STREAM;
extern const StaticQName QN_STREAM_FEATURES;
extern const StaticQName QN_STREAM_ERROR;
extern const StaticQName QN_XSTREAM_BAD_FORMAT;
extern const StaticQName QN_XSTREAM_BAD_NAMESPACE_PREFIX;
extern const StaticQName QN_XSTREAM_CONFLICT;
extern const StaticQName QN_XSTREAM_CONNECTION_TIMEOUT;
extern const StaticQName QN_XSTREAM_HOST_GONE;
extern const StaticQName QN_XSTREAM_HOST_UNKNOWN;
extern const StaticQName QN_XSTREAM_IMPROPER_ADDRESSIING;
extern const StaticQName QN_XSTREAM_INTERNAL_SERVER_ERROR;
extern const StaticQName QN_XSTREAM_INVALID_FROM;
extern const StaticQName QN_XSTREAM_INVALID_ID;
extern const StaticQName QN_XSTREAM_INVALID_NAMESPACE;
extern const StaticQName QN_XSTREAM_INVALID_XML;
extern const StaticQName QN_XSTREAM_NOT_AUTHORIZED;
extern const StaticQName QN_XSTREAM_POLICY_VIOLATION;
extern const StaticQName QN_XSTREAM_REMOTE_CONNECTION_FAILED;
extern const StaticQName QN_XSTREAM_RESOURCE_CONSTRAINT;
extern const StaticQName QN_XSTREAM_RESTRICTED_XML;
extern const StaticQName QN_XSTREAM_SEE_OTHER_HOST;
extern const StaticQName QN_XSTREAM_SYSTEM_SHUTDOWN;
extern const StaticQName QN_XSTREAM_UNDEFINED_CONDITION;
extern const StaticQName QN_XSTREAM_UNSUPPORTED_ENCODING;
extern const StaticQName QN_XSTREAM_UNSUPPORTED_STANZA_TYPE;
extern const StaticQName QN_XSTREAM_UNSUPPORTED_VERSION;
extern const StaticQName QN_XSTREAM_XML_NOT_WELL_FORMED;
extern const StaticQName QN_XSTREAM_TEXT;
extern const StaticQName QN_TLS_STARTTLS;
extern const StaticQName QN_TLS_REQUIRED;
extern const StaticQName QN_TLS_PROCEED;
extern const StaticQName QN_TLS_FAILURE;
extern const StaticQName QN_SASL_MECHANISMS;
extern const StaticQName QN_SASL_MECHANISM;
extern const StaticQName QN_SASL_AUTH;
extern const StaticQName QN_SASL_CHALLENGE;
extern const StaticQName QN_SASL_RESPONSE;
extern const StaticQName QN_SASL_ABORT;
extern const StaticQName QN_SASL_SUCCESS;
extern const StaticQName QN_SASL_FAILURE;
extern const StaticQName QN_SASL_ABORTED;
extern const StaticQName QN_SASL_INCORRECT_ENCODING;
extern const StaticQName QN_SASL_INVALID_AUTHZID;
extern const StaticQName QN_SASL_INVALID_MECHANISM;
extern const StaticQName QN_SASL_MECHANISM_TOO_WEAK;
extern const StaticQName QN_SASL_NOT_AUTHORIZED;
extern const StaticQName QN_SASL_TEMPORARY_AUTH_FAILURE;
// These are non-standard.
extern const char NS_GOOGLE_AUTH[];
extern const char NS_GOOGLE_AUTH_PROTOCOL[];
extern const StaticQName QN_GOOGLE_AUTH_CLIENT_USES_FULL_BIND_RESULT;
extern const StaticQName QN_GOOGLE_ALLOW_NON_GOOGLE_ID_XMPP_LOGIN;
extern const StaticQName QN_GOOGLE_AUTH_SERVICE;
extern const StaticQName QN_DIALBACK_RESULT;
extern const StaticQName QN_DIALBACK_VERIFY;
extern const StaticQName QN_STANZA_BAD_REQUEST;
extern const StaticQName QN_STANZA_CONFLICT;
extern const StaticQName QN_STANZA_FEATURE_NOT_IMPLEMENTED;
extern const StaticQName QN_STANZA_FORBIDDEN;
extern const StaticQName QN_STANZA_GONE;
extern const StaticQName QN_STANZA_INTERNAL_SERVER_ERROR;
extern const StaticQName QN_STANZA_ITEM_NOT_FOUND;
extern const StaticQName QN_STANZA_JID_MALFORMED;
extern const StaticQName QN_STANZA_NOT_ACCEPTABLE;
extern const StaticQName QN_STANZA_NOT_ALLOWED;
extern const StaticQName QN_STANZA_PAYMENT_REQUIRED;
extern const StaticQName QN_STANZA_RECIPIENT_UNAVAILABLE;
extern const StaticQName QN_STANZA_REDIRECT;
extern const StaticQName QN_STANZA_REGISTRATION_REQUIRED;
extern const StaticQName QN_STANZA_REMOTE_SERVER_NOT_FOUND;
extern const StaticQName QN_STANZA_REMOTE_SERVER_TIMEOUT;
extern const StaticQName QN_STANZA_RESOURCE_CONSTRAINT;
extern const StaticQName QN_STANZA_SERVICE_UNAVAILABLE;
extern const StaticQName QN_STANZA_SUBSCRIPTION_REQUIRED;
extern const StaticQName QN_STANZA_UNDEFINED_CONDITION;
extern const StaticQName QN_STANZA_UNEXPECTED_REQUEST;
extern const StaticQName QN_STANZA_TEXT;
extern const StaticQName QN_BIND_BIND;
extern const StaticQName QN_BIND_RESOURCE;
extern const StaticQName QN_BIND_JID;
extern const StaticQName QN_MESSAGE;
extern const StaticQName QN_BODY;
extern const StaticQName QN_SUBJECT;
extern const StaticQName QN_THREAD;
extern const StaticQName QN_PRESENCE;
extern const StaticQName QN_SHOW;
extern const StaticQName QN_STATUS;
extern const StaticQName QN_LANG;
extern const StaticQName QN_PRIORITY;
extern const StaticQName QN_IQ;
extern const StaticQName QN_ERROR;
extern const StaticQName QN_SERVER_MESSAGE;
extern const StaticQName QN_SERVER_BODY;
extern const StaticQName QN_SERVER_SUBJECT;
extern const StaticQName QN_SERVER_THREAD;
extern const StaticQName QN_SERVER_PRESENCE;
extern const StaticQName QN_SERVER_SHOW;
extern const StaticQName QN_SERVER_STATUS;
extern const StaticQName QN_SERVER_LANG;
extern const StaticQName QN_SERVER_PRIORITY;
extern const StaticQName QN_SERVER_IQ;
extern const StaticQName QN_SERVER_ERROR;
extern const StaticQName QN_SESSION_SESSION;
extern const StaticQName QN_PRIVACY_QUERY;
extern const StaticQName QN_PRIVACY_ACTIVE;
extern const StaticQName QN_PRIVACY_DEFAULT;
extern const StaticQName QN_PRIVACY_LIST;
extern const StaticQName QN_PRIVACY_ITEM;
extern const StaticQName QN_PRIVACY_IQ;
extern const StaticQName QN_PRIVACY_MESSAGE;
extern const StaticQName QN_PRIVACY_PRESENCE_IN;
extern const StaticQName QN_PRIVACY_PRESENCE_OUT;
extern const StaticQName QN_ROSTER_QUERY;
extern const StaticQName QN_ROSTER_ITEM;
extern const StaticQName QN_ROSTER_GROUP;
extern const StaticQName QN_VCARD;
extern const StaticQName QN_VCARD_FN;
extern const StaticQName QN_VCARD_PHOTO;
extern const StaticQName QN_VCARD_PHOTO_BINVAL;
extern const StaticQName QN_VCARD_AVATAR_HASH;
extern const StaticQName QN_VCARD_AVATAR_HASH_MODIFIED;
#if defined(FEATURE_ENABLE_PSTN)
extern const StaticQName QN_VCARD_TEL;
extern const StaticQName QN_VCARD_VOICE;
extern const StaticQName QN_VCARD_HOME;
extern const StaticQName QN_VCARD_WORK;
extern const StaticQName QN_VCARD_CELL;
extern const StaticQName QN_VCARD_NUMBER;
#endif
#if defined(FEATURE_ENABLE_RICHPROFILES)
extern const StaticQName QN_USER_PROFILE_QUERY;
extern const StaticQName QN_USER_PROFILE_URL;
extern const StaticQName QN_ATOM_FEED;
extern const StaticQName QN_ATOM_ENTRY;
extern const StaticQName QN_ATOM_TITLE;
extern const StaticQName QN_ATOM_ID;
extern const StaticQName QN_ATOM_MODIFIED;
extern const StaticQName QN_ATOM_IMAGE;
extern const StaticQName QN_ATOM_LINK;
extern const StaticQName QN_ATOM_HREF;
#endif
extern const StaticQName QN_XML_LANG;
extern const StaticQName QN_ENCODING;
extern const StaticQName QN_VERSION;
extern const StaticQName QN_TO;
extern const StaticQName QN_FROM;
extern const StaticQName QN_TYPE;
extern const StaticQName QN_ID;
extern const StaticQName QN_CODE;
extern const StaticQName QN_NAME;
extern const StaticQName QN_VALUE;
extern const StaticQName QN_ACTION;
extern const StaticQName QN_ORDER;
extern const StaticQName QN_MECHANISM;
extern const StaticQName QN_ASK;
extern const StaticQName QN_JID;
extern const StaticQName QN_NICK;
extern const StaticQName QN_SUBSCRIPTION;
extern const StaticQName QN_TITLE1;
extern const StaticQName QN_TITLE2;
extern const StaticQName QN_AFFILIATION;
extern const StaticQName QN_ROLE;
extern const StaticQName QN_TIME;
extern const StaticQName QN_XMLNS_CLIENT;
extern const StaticQName QN_XMLNS_SERVER;
extern const StaticQName QN_XMLNS_STREAM;
// Presence
extern const char STR_SHOW_AWAY[];
extern const char STR_SHOW_CHAT[];
extern const char STR_SHOW_DND[];
extern const char STR_SHOW_XA[];
extern const char STR_SHOW_OFFLINE[];
extern const char NS_GOOGLE_PSTN_CONFERENCE[];
extern const StaticQName QN_GOOGLE_PSTN_CONFERENCE_STATUS;
extern const StaticQName QN_ATTR_STATUS;
// Presence connection status
extern const char STR_PSTN_CONFERENCE_STATUS_CONNECTING[];
extern const char STR_PSTN_CONFERENCE_STATUS_JOINING[];
extern const char STR_PSTN_CONFERENCE_STATUS_CONNECTED[];
extern const char STR_PSTN_CONFERENCE_STATUS_HANGUP[];
// Subscription
extern const char STR_SUBSCRIBE[];
extern const char STR_SUBSCRIBED[];
extern const char STR_UNSUBSCRIBE[];
extern const char STR_UNSUBSCRIBED[];
// Google Invite
extern const char NS_GOOGLE_SUBSCRIBE[];
extern const StaticQName QN_INVITATION;
extern const StaticQName QN_INVITE_NAME;
extern const StaticQName QN_INVITE_SUBJECT;
extern const StaticQName QN_INVITE_MESSAGE;
// Kick
extern const char NS_GOOGLE_MUC_ADMIN[];
extern const StaticQName QN_GOOGLE_MUC_ADMIN_QUERY;
extern const StaticQName QN_GOOGLE_MUC_ADMIN_QUERY_ITEM;
extern const StaticQName QN_GOOGLE_MUC_ADMIN_QUERY_ITEM_REASON;
// PubSub: http://xmpp.org/extensions/xep-0060.html
extern const char NS_PUBSUB[];
extern const StaticQName QN_PUBSUB;
extern const StaticQName QN_PUBSUB_ITEMS;
extern const StaticQName QN_PUBSUB_ITEM;
extern const StaticQName QN_PUBSUB_PUBLISH;
extern const StaticQName QN_PUBSUB_RETRACT;
extern const StaticQName QN_ATTR_PUBLISHER;
extern const char NS_PUBSUB_EVENT[];
extern const StaticQName QN_NODE;
extern const StaticQName QN_PUBSUB_EVENT;
extern const StaticQName QN_PUBSUB_EVENT_ITEMS;
extern const StaticQName QN_PUBSUB_EVENT_ITEM;
extern const StaticQName QN_PUBSUB_EVENT_RETRACT;
extern const StaticQName QN_NOTIFY;
extern const char NS_PRESENTER[];
extern const StaticQName QN_PRESENTER_PRESENTER;
extern const StaticQName QN_PRESENTER_PRESENTATION_ITEM;
extern const StaticQName QN_PRESENTER_PRESENTATION_TYPE;
extern const StaticQName QN_PRESENTER_PRESENTATION_ID;
// JEP 0030
extern const StaticQName QN_CATEGORY;
extern const StaticQName QN_VAR;
extern const char NS_DISCO_INFO[];
extern const char NS_DISCO_ITEMS[];
extern const StaticQName QN_DISCO_INFO_QUERY;
extern const StaticQName QN_DISCO_IDENTITY;
extern const StaticQName QN_DISCO_FEATURE;
extern const StaticQName QN_DISCO_ITEMS_QUERY;
extern const StaticQName QN_DISCO_ITEM;
// JEP 0020
extern const char NS_FEATURE[];
extern const StaticQName QN_FEATURE_FEATURE;
// JEP 0004
extern const char NS_XDATA[];
extern const StaticQName QN_XDATA_X;
extern const StaticQName QN_XDATA_INSTRUCTIONS;
extern const StaticQName QN_XDATA_TITLE;
extern const StaticQName QN_XDATA_FIELD;
extern const StaticQName QN_XDATA_REPORTED;
extern const StaticQName QN_XDATA_ITEM;
extern const StaticQName QN_XDATA_DESC;
extern const StaticQName QN_XDATA_REQUIRED;
extern const StaticQName QN_XDATA_VALUE;
extern const StaticQName QN_XDATA_OPTION;
// JEP 0045
extern const char NS_MUC[];
extern const StaticQName QN_MUC_X;
extern const StaticQName QN_MUC_ITEM;
extern const StaticQName QN_MUC_AFFILIATION;
extern const StaticQName QN_MUC_ROLE;
extern const StaticQName QN_CLIENT_VERSION;
extern const StaticQName QN_LOCALE;
extern const char STR_AFFILIATION_NONE[];
extern const char STR_ROLE_PARTICIPANT[];
extern const char NS_GOOGLE_SESSION[];
extern const StaticQName QN_GOOGLE_USER_ID;
extern const StaticQName QN_GOOGLE_CIRCLE_ID;
extern const StaticQName QN_GOOGLE_SESSION_BLOCKED;
extern const StaticQName QN_GOOGLE_SESSION_BLOCKING;
extern const char NS_MUC_OWNER[];
extern const StaticQName QN_MUC_OWNER_QUERY;
extern const char NS_MUC_USER[];
extern const StaticQName QN_MUC_USER_CONTINUE;
extern const StaticQName QN_MUC_USER_X;
extern const StaticQName QN_MUC_USER_ITEM;
extern const StaticQName QN_MUC_USER_STATUS;
extern const StaticQName QN_MUC_USER_REASON;
extern const StaticQName QN_MUC_USER_ABUSE_VIOLATION;
// JEP 0055 - Jabber Search
extern const char NS_SEARCH[];
extern const StaticQName QN_SEARCH_QUERY;
extern const StaticQName QN_SEARCH_ITEM;
extern const StaticQName QN_SEARCH_ROOM_NAME;
extern const StaticQName QN_SEARCH_ROOM_JID;
extern const StaticQName QN_SEARCH_ROOM_DOMAIN;
extern const StaticQName QN_SEARCH_HANGOUT_ID;
extern const StaticQName QN_SEARCH_EXTERNAL_ID;
// JEP 0115
extern const char NS_CAPS[];
extern const StaticQName QN_CAPS_C;
extern const StaticQName QN_VER;
extern const StaticQName QN_EXT;
// Avatar - JEP 0153
extern const char kNSVCard[];
extern const StaticQName kQnVCardX;
extern const StaticQName kQnVCardPhoto;
// JEP 0172 User Nickname
extern const char NS_NICKNAME[];
extern const StaticQName QN_NICKNAME;
// JEP 0085 chat state
extern const char NS_CHATSTATE[];
extern const StaticQName QN_CS_ACTIVE;
extern const StaticQName QN_CS_COMPOSING;
extern const StaticQName QN_CS_PAUSED;
extern const StaticQName QN_CS_INACTIVE;
extern const StaticQName QN_CS_GONE;
// JEP 0091 Delayed Delivery
extern const char kNSDelay[];
extern const StaticQName kQnDelayX;
extern const StaticQName kQnStamp;
// Google time stamping (higher resolution)
extern const char kNSTimestamp[];
extern const StaticQName kQnTime;
extern const StaticQName kQnMilliseconds;
extern const char NS_JINGLE_INFO[];
extern const StaticQName QN_JINGLE_INFO_QUERY;
extern const StaticQName QN_JINGLE_INFO_STUN;
extern const StaticQName QN_JINGLE_INFO_RELAY;
extern const StaticQName QN_JINGLE_INFO_SERVER;
extern const StaticQName QN_JINGLE_INFO_TOKEN;
extern const StaticQName QN_JINGLE_INFO_HOST;
extern const StaticQName QN_JINGLE_INFO_TCP;
extern const StaticQName QN_JINGLE_INFO_UDP;
extern const StaticQName QN_JINGLE_INFO_TCPSSL;
extern const char NS_GOOGLE_CALLPERF_STATS[];
extern const StaticQName QN_CALLPERF_STATS;
extern const StaticQName QN_CALLPERF_SESSIONID;
extern const StaticQName QN_CALLPERF_LOCALUSER;
extern const StaticQName QN_CALLPERF_REMOTEUSER;
extern const StaticQName QN_CALLPERF_STARTTIME;
extern const StaticQName QN_CALLPERF_CALL_LENGTH;
extern const StaticQName QN_CALLPERF_CALL_ACCEPTED;
extern const StaticQName QN_CALLPERF_CALL_ERROR_CODE;
extern const StaticQName QN_CALLPERF_TERMINATE_CODE;
extern const StaticQName QN_CALLPERF_DATAPOINT;
extern const StaticQName QN_CALLPERF_DATAPOINT_TIME;
extern const StaticQName QN_CALLPERF_DATAPOINT_FRACTION_LOST;
extern const StaticQName QN_CALLPERF_DATAPOINT_CUM_LOST;
extern const StaticQName QN_CALLPERF_DATAPOINT_EXT_MAX;
extern const StaticQName QN_CALLPERF_DATAPOINT_JITTER;
extern const StaticQName QN_CALLPERF_DATAPOINT_RTT;
extern const StaticQName QN_CALLPERF_DATAPOINT_BYTES_R;
extern const StaticQName QN_CALLPERF_DATAPOINT_PACKETS_R;
extern const StaticQName QN_CALLPERF_DATAPOINT_BYTES_S;
extern const StaticQName QN_CALLPERF_DATAPOINT_PACKETS_S;
extern const StaticQName QN_CALLPERF_DATAPOINT_PROCESS_CPU;
extern const StaticQName QN_CALLPERF_DATAPOINT_SYSTEM_CPU;
extern const StaticQName QN_CALLPERF_DATAPOINT_CPUS;
extern const StaticQName QN_CALLPERF_CONNECTION;
extern const StaticQName QN_CALLPERF_CONNECTION_LOCAL_ADDRESS;
extern const StaticQName QN_CALLPERF_CONNECTION_REMOTE_ADDRESS;
extern const StaticQName QN_CALLPERF_CONNECTION_FLAGS;
extern const StaticQName QN_CALLPERF_CONNECTION_RTT;
extern const StaticQName QN_CALLPERF_CONNECTION_TOTAL_BYTES_S;
extern const StaticQName QN_CALLPERF_CONNECTION_BYTES_SECOND_S;
extern const StaticQName QN_CALLPERF_CONNECTION_TOTAL_BYTES_R;
extern const StaticQName QN_CALLPERF_CONNECTION_BYTES_SECOND_R;
extern const StaticQName QN_CALLPERF_CANDIDATE;
extern const StaticQName QN_CALLPERF_CANDIDATE_ENDPOINT;
extern const StaticQName QN_CALLPERF_CANDIDATE_PROTOCOL;
extern const StaticQName QN_CALLPERF_CANDIDATE_ADDRESS;
extern const StaticQName QN_CALLPERF_MEDIA;
extern const StaticQName QN_CALLPERF_MEDIA_DIRECTION;
extern const StaticQName QN_CALLPERF_MEDIA_SSRC;
extern const StaticQName QN_CALLPERF_MEDIA_ENERGY;
extern const StaticQName QN_CALLPERF_MEDIA_FIR;
extern const StaticQName QN_CALLPERF_MEDIA_NACK;
extern const StaticQName QN_CALLPERF_MEDIA_FPS;
extern const StaticQName QN_CALLPERF_MEDIA_FPS_NETWORK;
extern const StaticQName QN_CALLPERF_MEDIA_FPS_DECODED;
extern const StaticQName QN_CALLPERF_MEDIA_JITTER_BUFFER_SIZE;
extern const StaticQName QN_CALLPERF_MEDIA_PREFERRED_JITTER_BUFFER_SIZE;
extern const StaticQName QN_CALLPERF_MEDIA_TOTAL_PLAYOUT_DELAY;
// Muc invites.
extern const StaticQName QN_MUC_USER_INVITE;
// Multiway audio/video.
extern const char NS_GOOGLE_MUC_USER[];
extern const StaticQName QN_GOOGLE_MUC_USER_AVAILABLE_MEDIA;
extern const StaticQName QN_GOOGLE_MUC_USER_ENTRY;
extern const StaticQName QN_GOOGLE_MUC_USER_MEDIA;
extern const StaticQName QN_GOOGLE_MUC_USER_TYPE;
extern const StaticQName QN_GOOGLE_MUC_USER_SRC_ID;
extern const StaticQName QN_GOOGLE_MUC_USER_STATUS;
extern const StaticQName QN_LABEL;
extern const char NS_GOOGLE_MUC_MEDIA[];
extern const StaticQName QN_GOOGLE_MUC_AUDIO_MUTE;
extern const StaticQName QN_GOOGLE_MUC_VIDEO_MUTE;
extern const StaticQName QN_GOOGLE_MUC_VIDEO_PAUSE;
extern const StaticQName QN_GOOGLE_MUC_RECORDING;
extern const StaticQName QN_GOOGLE_MUC_MEDIA_BLOCK;
extern const StaticQName QN_STATE_ATTR;
extern const char AUTH_MECHANISM_GOOGLE_COOKIE[];
extern const char AUTH_MECHANISM_GOOGLE_TOKEN[];
extern const char AUTH_MECHANISM_OAUTH2[];
extern const char AUTH_MECHANISM_PLAIN[];
} // namespace buzz
#endif // WEBRTC_LIBJINGLE_XMPP_CONSTANTS_H_

View File

@ -1,61 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/libjingle/xmpp/discoitemsquerytask.h"
#include "webrtc/libjingle/xmpp/xmpptask.h"
namespace buzz {
DiscoItemsQueryTask::DiscoItemsQueryTask(XmppTaskParentInterface* parent,
const Jid& to,
const std::string& node)
: IqTask(parent, STR_GET, to, MakeRequest(node)) {
}
XmlElement* DiscoItemsQueryTask::MakeRequest(const std::string& node) {
XmlElement* element = new XmlElement(QN_DISCO_ITEMS_QUERY, true);
if (!node.empty()) {
element->AddAttr(QN_NODE, node);
}
return element;
}
void DiscoItemsQueryTask::HandleResult(const XmlElement* stanza) {
const XmlElement* query = stanza->FirstNamed(QN_DISCO_ITEMS_QUERY);
if (query) {
std::vector<DiscoItem> items;
for (const buzz::XmlChild* child = query->FirstChild(); child;
child = child->NextChild()) {
DiscoItem item;
const buzz::XmlElement* child_element = child->AsElement();
if (ParseItem(child_element, &item)) {
items.push_back(item);
}
}
SignalResult(items);
} else {
SignalError(this, NULL);
}
}
bool DiscoItemsQueryTask::ParseItem(const XmlElement* element,
DiscoItem* item) {
if (element->HasAttr(QN_JID)) {
return false;
}
item->jid = element->Attr(QN_JID);
item->name = element->Attr(QN_NAME);
item->node = element->Attr(QN_NODE);
return true;
}
} // namespace buzz

View File

@ -1,65 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// Fires a disco items query, such as the following example:
//
// <iq type='get'
// from='foo@gmail.com/asdf'
// to='bar@google.com'
// id='1234'>
// <query xmlns=' http://jabber.org/protocol/disco#items'
// node='blah '/>
// </iq>
//
// Sample response:
//
// <iq type='result'
// from=' hendriks@google.com'
// to='rsturgell@google.com/asdf'
// id='1234'>
// <query xmlns=' http://jabber.org/protocol/disco#items '
// node='blah'>
// <item something='somethingelse'/>
// </query>
// </iq>
#ifndef WEBRTC_LIBJINGLE_XMPP_DISCOITEMSQUERYTASK_H_
#define WEBRTC_LIBJINGLE_XMPP_DISCOITEMSQUERYTASK_H_
#include <string>
#include <vector>
#include "webrtc/libjingle/xmpp/iqtask.h"
namespace buzz {
struct DiscoItem {
std::string jid;
std::string node;
std::string name;
};
class DiscoItemsQueryTask : public IqTask {
public:
DiscoItemsQueryTask(XmppTaskParentInterface* parent,
const Jid& to, const std::string& node);
sigslot::signal1<std::vector<DiscoItem> > SignalResult;
private:
static XmlElement* MakeRequest(const std::string& node);
virtual void HandleResult(const XmlElement* result);
static bool ParseItem(const XmlElement* element, DiscoItem* item);
};
} // namespace buzz
#endif // WEBRTC_LIBJINGLE_XMPP_DISCOITEMSQUERYTASK_H_

View File

@ -1,107 +0,0 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// A fake XmppClient for use in unit tests.
#ifndef WEBRTC_LIBJINGLE_XMPP_FAKEXMPPCLIENT_H_
#define WEBRTC_LIBJINGLE_XMPP_FAKEXMPPCLIENT_H_
#include <algorithm>
#include <string>
#include <vector>
#include "webrtc/libjingle/xmpp/xmpptask.h"
namespace buzz {
class XmlElement;
class FakeXmppClient : public XmppTaskParentInterface,
public XmppClientInterface {
public:
explicit FakeXmppClient(rtc::TaskParent* parent)
: XmppTaskParentInterface(parent) {
}
// As XmppTaskParentInterface
virtual XmppClientInterface* GetClient() {
return this;
}
virtual int ProcessStart() {
return STATE_RESPONSE;
}
// As XmppClientInterface
virtual XmppEngine::State GetState() const {
return XmppEngine::STATE_OPEN;
}
virtual const Jid& jid() const {
return jid_;
}
virtual std::string NextId() {
// Implement if needed for tests.
return "0";
}
virtual XmppReturnStatus SendStanza(const XmlElement* stanza) {
sent_stanzas_.push_back(stanza);
return XMPP_RETURN_OK;
}
const std::vector<const XmlElement*>& sent_stanzas() {
return sent_stanzas_;
}
virtual XmppReturnStatus SendStanzaError(
const XmlElement * pelOriginal,
XmppStanzaError code,
const std::string & text) {
// Implement if needed for tests.
return XMPP_RETURN_OK;
}
virtual void AddXmppTask(XmppTask* task,
XmppEngine::HandlerLevel level) {
tasks_.push_back(task);
}
virtual void RemoveXmppTask(XmppTask* task) {
std::remove(tasks_.begin(), tasks_.end(), task);
}
// As FakeXmppClient
void set_jid(const Jid& jid) {
jid_ = jid;
}
// Takes ownership of stanza.
void HandleStanza(XmlElement* stanza) {
for (std::vector<XmppTask*>::iterator task = tasks_.begin();
task != tasks_.end(); ++task) {
if ((*task)->HandleStanza(stanza)) {
delete stanza;
return;
}
}
delete stanza;
}
private:
Jid jid_;
std::vector<XmppTask*> tasks_;
std::vector<const XmlElement*> sent_stanzas_;
};
} // namespace buzz
#endif // WEBRTC_LIBJINGLE_XMPP_FAKEXMPPCLIENT_H_

View File

@ -1,400 +0,0 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/xmpp/hangoutpubsubclient.h"
#include "webrtc/libjingle/xmllite/qname.h"
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/libjingle/xmpp/jid.h"
#include "webrtc/base/logging.h"
// Gives a high-level API for MUC call PubSub needs such as
// presenter state, recording state, mute state, and remote mute.
namespace buzz {
namespace {
const char kPresenting[] = "s";
const char kNotPresenting[] = "o";
} // namespace
// A simple serialiazer where presence of item => true, lack of item
// => false.
class BoolStateSerializer : public PubSubStateSerializer<bool> {
virtual XmlElement* Write(const QName& state_name, const bool& state) {
if (!state) {
return NULL;
}
return new XmlElement(state_name, true);
}
virtual void Parse(const XmlElement* state_elem, bool *state_out) {
*state_out = state_elem != NULL;
}
};
class PresenterStateClient : public PubSubStateClient<bool> {
public:
PresenterStateClient(const std::string& publisher_nick,
PubSubClient* client,
const QName& state_name,
bool default_state)
: PubSubStateClient<bool>(
publisher_nick, client, state_name, default_state,
new PublishedNickKeySerializer(), NULL) {
}
virtual void Publish(const std::string& published_nick,
const bool& state,
std::string* task_id_out) {
XmlElement* presenter_elem = new XmlElement(QN_PRESENTER_PRESENTER, true);
presenter_elem->AddAttr(QN_NICK, published_nick);
XmlElement* presentation_item_elem =
new XmlElement(QN_PRESENTER_PRESENTATION_ITEM, false);
const std::string& presentation_type = state ? kPresenting : kNotPresenting;
presentation_item_elem->AddAttr(
QN_PRESENTER_PRESENTATION_TYPE, presentation_type);
// The Presenter state is kind of dumb in that it doesn't always use
// retracts. It relies on setting the "type" to a special value.
std::string itemid = published_nick;
std::vector<XmlElement*> children;
children.push_back(presenter_elem);
children.push_back(presentation_item_elem);
client()->PublishItem(itemid, children, task_id_out);
}
protected:
virtual bool ParseStateItem(const PubSubItem& item,
StateItemInfo* info_out,
bool* state_out) {
const XmlElement* presenter_elem =
item.elem->FirstNamed(QN_PRESENTER_PRESENTER);
const XmlElement* presentation_item_elem =
item.elem->FirstNamed(QN_PRESENTER_PRESENTATION_ITEM);
if (presentation_item_elem == NULL || presenter_elem == NULL) {
return false;
}
info_out->publisher_nick =
client()->GetPublisherNickFromPubSubItem(item.elem);
info_out->published_nick = presenter_elem->Attr(QN_NICK);
*state_out = (presentation_item_elem->Attr(
QN_PRESENTER_PRESENTATION_TYPE) != kNotPresenting);
return true;
}
virtual bool StatesEqual(const bool& state1, const bool& state2) {
// Make every item trigger an event, even if state doesn't change.
return false;
}
};
HangoutPubSubClient::HangoutPubSubClient(XmppTaskParentInterface* parent,
const Jid& mucjid,
const std::string& nick)
: mucjid_(mucjid),
nick_(nick) {
presenter_client_.reset(new PubSubClient(parent, mucjid, NS_PRESENTER));
presenter_client_->SignalRequestError.connect(
this, &HangoutPubSubClient::OnPresenterRequestError);
media_client_.reset(new PubSubClient(parent, mucjid, NS_GOOGLE_MUC_MEDIA));
media_client_->SignalRequestError.connect(
this, &HangoutPubSubClient::OnMediaRequestError);
presenter_state_client_.reset(new PresenterStateClient(
nick_, presenter_client_.get(), QN_PRESENTER_PRESENTER, false));
presenter_state_client_->SignalStateChange.connect(
this, &HangoutPubSubClient::OnPresenterStateChange);
presenter_state_client_->SignalPublishResult.connect(
this, &HangoutPubSubClient::OnPresenterPublishResult);
presenter_state_client_->SignalPublishError.connect(
this, &HangoutPubSubClient::OnPresenterPublishError);
audio_mute_state_client_.reset(new PubSubStateClient<bool>(
nick_, media_client_.get(), QN_GOOGLE_MUC_AUDIO_MUTE, false,
new PublishedNickKeySerializer(), new BoolStateSerializer()));
// Can't just repeat because we need to watch for remote mutes.
audio_mute_state_client_->SignalStateChange.connect(
this, &HangoutPubSubClient::OnAudioMuteStateChange);
audio_mute_state_client_->SignalPublishResult.connect(
this, &HangoutPubSubClient::OnAudioMutePublishResult);
audio_mute_state_client_->SignalPublishError.connect(
this, &HangoutPubSubClient::OnAudioMutePublishError);
video_mute_state_client_.reset(new PubSubStateClient<bool>(
nick_, media_client_.get(), QN_GOOGLE_MUC_VIDEO_MUTE, false,
new PublishedNickKeySerializer(), new BoolStateSerializer()));
// Can't just repeat because we need to watch for remote mutes.
video_mute_state_client_->SignalStateChange.connect(
this, &HangoutPubSubClient::OnVideoMuteStateChange);
video_mute_state_client_->SignalPublishResult.connect(
this, &HangoutPubSubClient::OnVideoMutePublishResult);
video_mute_state_client_->SignalPublishError.connect(
this, &HangoutPubSubClient::OnVideoMutePublishError);
video_pause_state_client_.reset(new PubSubStateClient<bool>(
nick_, media_client_.get(), QN_GOOGLE_MUC_VIDEO_PAUSE, false,
new PublishedNickKeySerializer(), new BoolStateSerializer()));
video_pause_state_client_->SignalStateChange.connect(
this, &HangoutPubSubClient::OnVideoPauseStateChange);
video_pause_state_client_->SignalPublishResult.connect(
this, &HangoutPubSubClient::OnVideoPausePublishResult);
video_pause_state_client_->SignalPublishError.connect(
this, &HangoutPubSubClient::OnVideoPausePublishError);
recording_state_client_.reset(new PubSubStateClient<bool>(
nick_, media_client_.get(), QN_GOOGLE_MUC_RECORDING, false,
new PublishedNickKeySerializer(), new BoolStateSerializer()));
recording_state_client_->SignalStateChange.connect(
this, &HangoutPubSubClient::OnRecordingStateChange);
recording_state_client_->SignalPublishResult.connect(
this, &HangoutPubSubClient::OnRecordingPublishResult);
recording_state_client_->SignalPublishError.connect(
this, &HangoutPubSubClient::OnRecordingPublishError);
media_block_state_client_.reset(new PubSubStateClient<bool>(
nick_, media_client_.get(), QN_GOOGLE_MUC_MEDIA_BLOCK, false,
new PublisherAndPublishedNicksKeySerializer(),
new BoolStateSerializer()));
media_block_state_client_->SignalStateChange.connect(
this, &HangoutPubSubClient::OnMediaBlockStateChange);
media_block_state_client_->SignalPublishResult.connect(
this, &HangoutPubSubClient::OnMediaBlockPublishResult);
media_block_state_client_->SignalPublishError.connect(
this, &HangoutPubSubClient::OnMediaBlockPublishError);
}
HangoutPubSubClient::~HangoutPubSubClient() {
}
void HangoutPubSubClient::RequestAll() {
presenter_client_->RequestItems();
media_client_->RequestItems();
}
void HangoutPubSubClient::OnPresenterRequestError(
PubSubClient* client, const XmlElement* stanza) {
SignalRequestError(client->node(), stanza);
}
void HangoutPubSubClient::OnMediaRequestError(
PubSubClient* client, const XmlElement* stanza) {
SignalRequestError(client->node(), stanza);
}
void HangoutPubSubClient::PublishPresenterState(
bool presenting, std::string* task_id_out) {
presenter_state_client_->Publish(nick_, presenting, task_id_out);
}
void HangoutPubSubClient::PublishAudioMuteState(
bool muted, std::string* task_id_out) {
audio_mute_state_client_->Publish(nick_, muted, task_id_out);
}
void HangoutPubSubClient::PublishVideoMuteState(
bool muted, std::string* task_id_out) {
video_mute_state_client_->Publish(nick_, muted, task_id_out);
}
void HangoutPubSubClient::PublishVideoPauseState(
bool paused, std::string* task_id_out) {
video_pause_state_client_->Publish(nick_, paused, task_id_out);
}
void HangoutPubSubClient::PublishRecordingState(
bool recording, std::string* task_id_out) {
recording_state_client_->Publish(nick_, recording, task_id_out);
}
// Remote mute is accomplished by setting another client's mute state.
void HangoutPubSubClient::RemoteMute(
const std::string& mutee_nick, std::string* task_id_out) {
audio_mute_state_client_->Publish(mutee_nick, true, task_id_out);
}
// Block media is accomplished by setting another client's block
// state, kind of like remote mute.
void HangoutPubSubClient::BlockMedia(
const std::string& blockee_nick, std::string* task_id_out) {
media_block_state_client_->Publish(blockee_nick, true, task_id_out);
}
void HangoutPubSubClient::OnPresenterStateChange(
const PubSubStateChange<bool>& change) {
SignalPresenterStateChange(
change.published_nick, change.old_state, change.new_state);
}
void HangoutPubSubClient::OnPresenterPublishResult(
const std::string& task_id, const XmlElement* item) {
SignalPublishPresenterResult(task_id);
}
void HangoutPubSubClient::OnPresenterPublishError(
const std::string& task_id, const XmlElement* item,
const XmlElement* stanza) {
SignalPublishPresenterError(task_id, stanza);
}
// Since a remote mute is accomplished by another client setting our
// mute state, if our state changes to muted, we should mute ourselves.
// Note that remote un-muting is disallowed by the RoomServer.
void HangoutPubSubClient::OnAudioMuteStateChange(
const PubSubStateChange<bool>& change) {
bool was_muted = change.old_state;
bool is_muted = change.new_state;
bool remote_action = (!change.publisher_nick.empty() &&
(change.publisher_nick != change.published_nick));
if (remote_action) {
const std::string& mutee_nick = change.published_nick;
const std::string& muter_nick = change.publisher_nick;
if (!is_muted) {
// The server should prevent remote un-mute.
LOG(LS_WARNING) << muter_nick << " remote unmuted " << mutee_nick;
return;
}
bool should_mute_locally = (mutee_nick == nick_);
SignalRemoteMute(mutee_nick, muter_nick, should_mute_locally);
}
SignalAudioMuteStateChange(change.published_nick, was_muted, is_muted);
}
const std::string GetAudioMuteNickFromItem(const XmlElement* item) {
if (item != NULL) {
const XmlElement* audio_mute_state =
item->FirstNamed(QN_GOOGLE_MUC_AUDIO_MUTE);
if (audio_mute_state != NULL) {
return audio_mute_state->Attr(QN_NICK);
}
}
return std::string();
}
const std::string GetBlockeeNickFromItem(const XmlElement* item) {
if (item != NULL) {
const XmlElement* media_block_state =
item->FirstNamed(QN_GOOGLE_MUC_MEDIA_BLOCK);
if (media_block_state != NULL) {
return media_block_state->Attr(QN_NICK);
}
}
return std::string();
}
void HangoutPubSubClient::OnAudioMutePublishResult(
const std::string& task_id, const XmlElement* item) {
const std::string& mutee_nick = GetAudioMuteNickFromItem(item);
if (mutee_nick != nick_) {
SignalRemoteMuteResult(task_id, mutee_nick);
} else {
SignalPublishAudioMuteResult(task_id);
}
}
void HangoutPubSubClient::OnAudioMutePublishError(
const std::string& task_id, const XmlElement* item,
const XmlElement* stanza) {
const std::string& mutee_nick = GetAudioMuteNickFromItem(item);
if (mutee_nick != nick_) {
SignalRemoteMuteError(task_id, mutee_nick, stanza);
} else {
SignalPublishAudioMuteError(task_id, stanza);
}
}
void HangoutPubSubClient::OnVideoMuteStateChange(
const PubSubStateChange<bool>& change) {
SignalVideoMuteStateChange(
change.published_nick, change.old_state, change.new_state);
}
void HangoutPubSubClient::OnVideoMutePublishResult(
const std::string& task_id, const XmlElement* item) {
SignalPublishVideoMuteResult(task_id);
}
void HangoutPubSubClient::OnVideoMutePublishError(
const std::string& task_id, const XmlElement* item,
const XmlElement* stanza) {
SignalPublishVideoMuteError(task_id, stanza);
}
void HangoutPubSubClient::OnVideoPauseStateChange(
const PubSubStateChange<bool>& change) {
SignalVideoPauseStateChange(
change.published_nick, change.old_state, change.new_state);
}
void HangoutPubSubClient::OnVideoPausePublishResult(
const std::string& task_id, const XmlElement* item) {
SignalPublishVideoPauseResult(task_id);
}
void HangoutPubSubClient::OnVideoPausePublishError(
const std::string& task_id, const XmlElement* item,
const XmlElement* stanza) {
SignalPublishVideoPauseError(task_id, stanza);
}
void HangoutPubSubClient::OnRecordingStateChange(
const PubSubStateChange<bool>& change) {
SignalRecordingStateChange(
change.published_nick, change.old_state, change.new_state);
}
void HangoutPubSubClient::OnRecordingPublishResult(
const std::string& task_id, const XmlElement* item) {
SignalPublishRecordingResult(task_id);
}
void HangoutPubSubClient::OnRecordingPublishError(
const std::string& task_id, const XmlElement* item,
const XmlElement* stanza) {
SignalPublishRecordingError(task_id, stanza);
}
void HangoutPubSubClient::OnMediaBlockStateChange(
const PubSubStateChange<bool>& change) {
const std::string& blockee_nick = change.published_nick;
const std::string& blocker_nick = change.publisher_nick;
bool was_blockee = change.old_state;
bool is_blockee = change.new_state;
if (!was_blockee && is_blockee) {
SignalMediaBlock(blockee_nick, blocker_nick);
}
// TODO: Should we bother signaling unblock? Currently
// it isn't allowed, but it might happen when a participant leaves
// the room and the item is retracted.
}
void HangoutPubSubClient::OnMediaBlockPublishResult(
const std::string& task_id, const XmlElement* item) {
const std::string& blockee_nick = GetBlockeeNickFromItem(item);
SignalMediaBlockResult(task_id, blockee_nick);
}
void HangoutPubSubClient::OnMediaBlockPublishError(
const std::string& task_id, const XmlElement* item,
const XmlElement* stanza) {
const std::string& blockee_nick = GetBlockeeNickFromItem(item);
SignalMediaBlockError(task_id, blockee_nick, stanza);
}
} // namespace buzz

View File

@ -1,178 +0,0 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_HANGOUTPUBSUBCLIENT_H_
#define WEBRTC_LIBJINGLE_XMPP_HANGOUTPUBSUBCLIENT_H_
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "webrtc/libjingle/xmpp/jid.h"
#include "webrtc/libjingle/xmpp/pubsubclient.h"
#include "webrtc/libjingle/xmpp/pubsubstateclient.h"
#include "webrtc/base/sigslot.h"
#include "webrtc/base/sigslotrepeater.h"
// Gives a high-level API for MUC call PubSub needs such as
// presenter state, recording state, mute state, and remote mute.
namespace buzz {
class Jid;
class XmlElement;
class XmppTaskParentInterface;
// A client tied to a specific MUC jid and local nick. Provides ways
// to get updates and publish state and events. Must call
// RequestAll() to start getting updates.
class HangoutPubSubClient : public sigslot::has_slots<> {
public:
HangoutPubSubClient(XmppTaskParentInterface* parent,
const Jid& mucjid,
const std::string& nick);
~HangoutPubSubClient();
const Jid& mucjid() const { return mucjid_; }
const std::string& nick() const { return nick_; }
// Requests all of the different states and subscribes for updates.
// Responses and updates will be signalled via the various signals.
void RequestAll();
// Signal (nick, was_presenting, is_presenting)
sigslot::signal3<const std::string&, bool, bool> SignalPresenterStateChange;
// Signal (nick, was_muted, is_muted)
sigslot::signal3<const std::string&, bool, bool> SignalAudioMuteStateChange;
// Signal (nick, was_muted, is_muted)
sigslot::signal3<const std::string&, bool, bool> SignalVideoMuteStateChange;
// Signal (nick, was_paused, is_paused)
sigslot::signal3<const std::string&, bool, bool> SignalVideoPauseStateChange;
// Signal (nick, was_recording, is_recording)
sigslot::signal3<const std::string&, bool, bool> SignalRecordingStateChange;
// Signal (mutee_nick, muter_nick, should_mute_locally)
sigslot::signal3<const std::string&,
const std::string&,
bool> SignalRemoteMute;
// Signal (blockee_nick, blocker_nick)
sigslot::signal2<const std::string&, const std::string&> SignalMediaBlock;
// Signal (node, error stanza)
sigslot::signal2<const std::string&, const XmlElement*> SignalRequestError;
// On each of these, provide a task_id_out to get the task_id, which
// can be correlated to the error and result signals.
void PublishPresenterState(
bool presenting, std::string* task_id_out = NULL);
void PublishAudioMuteState(
bool muted, std::string* task_id_out = NULL);
void PublishVideoMuteState(
bool muted, std::string* task_id_out = NULL);
void PublishVideoPauseState(
bool paused, std::string* task_id_out = NULL);
void PublishRecordingState(
bool recording, std::string* task_id_out = NULL);
void RemoteMute(
const std::string& mutee_nick, std::string* task_id_out = NULL);
void BlockMedia(
const std::string& blockee_nick, std::string* task_id_out = NULL);
// Signal task_id
sigslot::signal1<const std::string&> SignalPublishAudioMuteResult;
sigslot::signal1<const std::string&> SignalPublishVideoMuteResult;
sigslot::signal1<const std::string&> SignalPublishVideoPauseResult;
sigslot::signal1<const std::string&> SignalPublishPresenterResult;
sigslot::signal1<const std::string&> SignalPublishRecordingResult;
// Signal (task_id, mutee_nick)
sigslot::signal2<const std::string&,
const std::string&> SignalRemoteMuteResult;
// Signal (task_id, blockee_nick)
sigslot::signal2<const std::string&,
const std::string&> SignalMediaBlockResult;
// Signal (task_id, error stanza)
sigslot::signal2<const std::string&,
const XmlElement*> SignalPublishAudioMuteError;
sigslot::signal2<const std::string&,
const XmlElement*> SignalPublishVideoMuteError;
sigslot::signal2<const std::string&,
const XmlElement*> SignalPublishVideoPauseError;
sigslot::signal2<const std::string&,
const XmlElement*> SignalPublishPresenterError;
sigslot::signal2<const std::string&,
const XmlElement*> SignalPublishRecordingError;
sigslot::signal2<const std::string&,
const XmlElement*> SignalPublishMediaBlockError;
// Signal (task_id, mutee_nick, error stanza)
sigslot::signal3<const std::string&,
const std::string&,
const XmlElement*> SignalRemoteMuteError;
// Signal (task_id, blockee_nick, error stanza)
sigslot::signal3<const std::string&,
const std::string&,
const XmlElement*> SignalMediaBlockError;
private:
void OnPresenterRequestError(PubSubClient* client,
const XmlElement* stanza);
void OnMediaRequestError(PubSubClient* client,
const XmlElement* stanza);
void OnPresenterStateChange(const PubSubStateChange<bool>& change);
void OnPresenterPublishResult(const std::string& task_id,
const XmlElement* item);
void OnPresenterPublishError(const std::string& task_id,
const XmlElement* item,
const XmlElement* stanza);
void OnAudioMuteStateChange(const PubSubStateChange<bool>& change);
void OnAudioMutePublishResult(const std::string& task_id,
const XmlElement* item);
void OnAudioMutePublishError(const std::string& task_id,
const XmlElement* item,
const XmlElement* stanza);
void OnVideoMuteStateChange(const PubSubStateChange<bool>& change);
void OnVideoMutePublishResult(const std::string& task_id,
const XmlElement* item);
void OnVideoMutePublishError(const std::string& task_id,
const XmlElement* item,
const XmlElement* stanza);
void OnVideoPauseStateChange(const PubSubStateChange<bool>& change);
void OnVideoPausePublishResult(const std::string& task_id,
const XmlElement* item);
void OnVideoPausePublishError(const std::string& task_id,
const XmlElement* item,
const XmlElement* stanza);
void OnRecordingStateChange(const PubSubStateChange<bool>& change);
void OnRecordingPublishResult(const std::string& task_id,
const XmlElement* item);
void OnRecordingPublishError(const std::string& task_id,
const XmlElement* item,
const XmlElement* stanza);
void OnMediaBlockStateChange(const PubSubStateChange<bool>& change);
void OnMediaBlockPublishResult(const std::string& task_id,
const XmlElement* item);
void OnMediaBlockPublishError(const std::string& task_id,
const XmlElement* item,
const XmlElement* stanza);
Jid mucjid_;
std::string nick_;
std::unique_ptr<PubSubClient> media_client_;
std::unique_ptr<PubSubClient> presenter_client_;
std::unique_ptr<PubSubStateClient<bool> > presenter_state_client_;
std::unique_ptr<PubSubStateClient<bool> > audio_mute_state_client_;
std::unique_ptr<PubSubStateClient<bool> > video_mute_state_client_;
std::unique_ptr<PubSubStateClient<bool> > video_pause_state_client_;
std::unique_ptr<PubSubStateClient<bool> > recording_state_client_;
std::unique_ptr<PubSubStateClient<bool> > media_block_state_client_;
};
} // namespace buzz
#endif // WEBRTC_LIBJINGLE_XMPP_HANGOUTPUBSUBCLIENT_H_

View File

@ -1,754 +0,0 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <memory>
#include <string>
#include "webrtc/libjingle/xmllite/qname.h"
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/libjingle/xmpp/fakexmppclient.h"
#include "webrtc/libjingle/xmpp/hangoutpubsubclient.h"
#include "webrtc/libjingle/xmpp/jid.h"
#include "webrtc/base/faketaskrunner.h"
#include "webrtc/base/gunit.h"
#include "webrtc/base/sigslot.h"
class TestHangoutPubSubListener : public sigslot::has_slots<> {
public:
TestHangoutPubSubListener() :
request_error_count(0),
publish_audio_mute_error_count(0),
publish_video_mute_error_count(0),
publish_video_pause_error_count(0),
publish_presenter_error_count(0),
publish_recording_error_count(0),
remote_mute_error_count(0) {
}
void OnPresenterStateChange(
const std::string& nick, bool was_presenting, bool is_presenting) {
last_presenter_nick = nick;
last_was_presenting = was_presenting;
last_is_presenting = is_presenting;
}
void OnAudioMuteStateChange(
const std::string& nick, bool was_muted, bool is_muted) {
last_audio_muted_nick = nick;
last_was_audio_muted = was_muted;
last_is_audio_muted = is_muted;
}
void OnVideoMuteStateChange(
const std::string& nick, bool was_muted, bool is_muted) {
last_video_muted_nick = nick;
last_was_video_muted = was_muted;
last_is_video_muted = is_muted;
}
void OnVideoPauseStateChange(
const std::string& nick, bool was_paused, bool is_paused) {
last_video_paused_nick = nick;
last_was_video_paused = was_paused;
last_is_video_paused = is_paused;
}
void OnRecordingStateChange(
const std::string& nick, bool was_recording, bool is_recording) {
last_recording_nick = nick;
last_was_recording = was_recording;
last_is_recording = is_recording;
}
void OnRemoteMute(
const std::string& mutee_nick,
const std::string& muter_nick,
bool should_mute_locally) {
last_mutee_nick = mutee_nick;
last_muter_nick = muter_nick;
last_should_mute = should_mute_locally;
}
void OnMediaBlock(
const std::string& blockee_nick,
const std::string& blocker_nick) {
last_blockee_nick = blockee_nick;
last_blocker_nick = blocker_nick;
}
void OnRequestError(const std::string& node, const buzz::XmlElement* stanza) {
++request_error_count;
request_error_node = node;
}
void OnPublishAudioMuteError(const std::string& task_id,
const buzz::XmlElement* stanza) {
++publish_audio_mute_error_count;
error_task_id = task_id;
}
void OnPublishVideoMuteError(const std::string& task_id,
const buzz::XmlElement* stanza) {
++publish_video_mute_error_count;
error_task_id = task_id;
}
void OnPublishVideoPauseError(const std::string& task_id,
const buzz::XmlElement* stanza) {
++publish_video_pause_error_count;
error_task_id = task_id;
}
void OnPublishPresenterError(const std::string& task_id,
const buzz::XmlElement* stanza) {
++publish_presenter_error_count;
error_task_id = task_id;
}
void OnPublishRecordingError(const std::string& task_id,
const buzz::XmlElement* stanza) {
++publish_recording_error_count;
error_task_id = task_id;
}
void OnRemoteMuteResult(const std::string& task_id,
const std::string& mutee_nick) {
result_task_id = task_id;
remote_mute_mutee_nick = mutee_nick;
}
void OnRemoteMuteError(const std::string& task_id,
const std::string& mutee_nick,
const buzz::XmlElement* stanza) {
++remote_mute_error_count;
error_task_id = task_id;
remote_mute_mutee_nick = mutee_nick;
}
void OnMediaBlockResult(const std::string& task_id,
const std::string& blockee_nick) {
result_task_id = task_id;
media_blockee_nick = blockee_nick;
}
void OnMediaBlockError(const std::string& task_id,
const std::string& blockee_nick,
const buzz::XmlElement* stanza) {
++media_block_error_count;
error_task_id = task_id;
media_blockee_nick = blockee_nick;
}
std::string last_presenter_nick;
bool last_is_presenting;
bool last_was_presenting;
std::string last_audio_muted_nick;
bool last_is_audio_muted;
bool last_was_audio_muted;
std::string last_video_muted_nick;
bool last_is_video_muted;
bool last_was_video_muted;
std::string last_video_paused_nick;
bool last_is_video_paused;
bool last_was_video_paused;
std::string last_recording_nick;
bool last_is_recording;
bool last_was_recording;
std::string last_mutee_nick;
std::string last_muter_nick;
bool last_should_mute;
std::string last_blockee_nick;
std::string last_blocker_nick;
int request_error_count;
std::string request_error_node;
int publish_audio_mute_error_count;
int publish_video_mute_error_count;
int publish_video_pause_error_count;
int publish_presenter_error_count;
int publish_recording_error_count;
int remote_mute_error_count;
std::string result_task_id;
std::string error_task_id;
std::string remote_mute_mutee_nick;
int media_block_error_count;
std::string media_blockee_nick;
};
class HangoutPubSubClientTest : public testing::Test {
public:
HangoutPubSubClientTest() :
pubsubjid("room@domain.com"),
nick("me") {
runner.reset(new rtc::FakeTaskRunner());
xmpp_client = new buzz::FakeXmppClient(runner.get());
client.reset(new buzz::HangoutPubSubClient(xmpp_client, pubsubjid, nick));
listener.reset(new TestHangoutPubSubListener());
client->SignalPresenterStateChange.connect(
listener.get(), &TestHangoutPubSubListener::OnPresenterStateChange);
client->SignalAudioMuteStateChange.connect(
listener.get(), &TestHangoutPubSubListener::OnAudioMuteStateChange);
client->SignalVideoMuteStateChange.connect(
listener.get(), &TestHangoutPubSubListener::OnVideoMuteStateChange);
client->SignalVideoPauseStateChange.connect(
listener.get(), &TestHangoutPubSubListener::OnVideoPauseStateChange);
client->SignalRecordingStateChange.connect(
listener.get(), &TestHangoutPubSubListener::OnRecordingStateChange);
client->SignalRemoteMute.connect(
listener.get(), &TestHangoutPubSubListener::OnRemoteMute);
client->SignalMediaBlock.connect(
listener.get(), &TestHangoutPubSubListener::OnMediaBlock);
client->SignalRequestError.connect(
listener.get(), &TestHangoutPubSubListener::OnRequestError);
client->SignalPublishAudioMuteError.connect(
listener.get(), &TestHangoutPubSubListener::OnPublishAudioMuteError);
client->SignalPublishVideoMuteError.connect(
listener.get(), &TestHangoutPubSubListener::OnPublishVideoMuteError);
client->SignalPublishVideoPauseError.connect(
listener.get(), &TestHangoutPubSubListener::OnPublishVideoPauseError);
client->SignalPublishPresenterError.connect(
listener.get(), &TestHangoutPubSubListener::OnPublishPresenterError);
client->SignalPublishRecordingError.connect(
listener.get(), &TestHangoutPubSubListener::OnPublishRecordingError);
client->SignalRemoteMuteResult.connect(
listener.get(), &TestHangoutPubSubListener::OnRemoteMuteResult);
client->SignalRemoteMuteError.connect(
listener.get(), &TestHangoutPubSubListener::OnRemoteMuteError);
client->SignalMediaBlockResult.connect(
listener.get(), &TestHangoutPubSubListener::OnMediaBlockResult);
client->SignalMediaBlockError.connect(
listener.get(), &TestHangoutPubSubListener::OnMediaBlockError);
}
std::unique_ptr<rtc::FakeTaskRunner> runner;
// xmpp_client deleted by deleting runner.
buzz::FakeXmppClient* xmpp_client;
std::unique_ptr<buzz::HangoutPubSubClient> client;
std::unique_ptr<TestHangoutPubSubListener> listener;
buzz::Jid pubsubjid;
std::string nick;
};
TEST_F(HangoutPubSubClientTest, TestRequest) {
ASSERT_EQ(0U, xmpp_client->sent_stanzas().size());
client->RequestAll();
std::string expected_presenter_request =
"<cli:iq type=\"get\" to=\"room@domain.com\" id=\"0\" "
"xmlns:cli=\"jabber:client\">"
"<pub:pubsub xmlns:pub=\"http://jabber.org/protocol/pubsub\">"
"<pub:items node=\"google:presenter\"/>"
"</pub:pubsub>"
"</cli:iq>";
std::string expected_media_request =
"<cli:iq type=\"get\" to=\"room@domain.com\" id=\"0\" "
"xmlns:cli=\"jabber:client\">"
"<pub:pubsub xmlns:pub=\"http://jabber.org/protocol/pubsub\">"
"<pub:items node=\"google:muc#media\"/>"
"</pub:pubsub>"
"</cli:iq>";
ASSERT_EQ(2U, xmpp_client->sent_stanzas().size());
EXPECT_EQ(expected_presenter_request, xmpp_client->sent_stanzas()[0]->Str());
EXPECT_EQ(expected_media_request, xmpp_client->sent_stanzas()[1]->Str());
std::string presenter_response =
"<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'>"
" <pubsub xmlns='http://jabber.org/protocol/pubsub'>"
" <items node='google:presenter'>"
" <item id='12344'>"
" <presenter xmlns='google:presenter' nick='presenting-nick2'/>"
" <pre:presentation-item xmlns:pre='google:presenter'"
" pre:presentation-type='s'/>"
" </item>"
" <item id='12345'>"
" <presenter xmlns='google:presenter' nick='presenting-nick'/>"
" <pre:presentation-item xmlns:pre='google:presenter'"
" pre:presentation-type='o'/>"
" </item>"
// Some clients are "bad" in that they'll jam multiple states in
// all at once. We have to deal with it.
" <item id='12346'>"
" <presenter xmlns='google:presenter' nick='presenting-nick'/>"
" <pre:presentation-item xmlns:pre='google:presenter'"
" pre:presentation-type='s'/>"
" </item>"
" </items>"
" </pubsub>"
"</iq>";
xmpp_client->HandleStanza(buzz::XmlElement::ForStr(presenter_response));
EXPECT_EQ("presenting-nick", listener->last_presenter_nick);
EXPECT_FALSE(listener->last_was_presenting);
EXPECT_TRUE(listener->last_is_presenting);
std::string media_response =
"<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'>"
" <pubsub xmlns='http://jabber.org/protocol/pubsub'>"
" <items node='google:muc#media'>"
" <item id='audio-mute:muted-nick'>"
" <audio-mute nick='muted-nick' xmlns='google:muc#media'/>"
" </item>"
" <item id='video-mute:video-muted-nick'>"
" <video-mute nick='video-muted-nick' xmlns='google:muc#media'/>"
" </item>"
" <item id='video-pause:video-paused-nick'>"
" <video-pause nick='video-paused-nick' xmlns='google:muc#media'/>"
" </item>"
" <item id='recording:recording-nick'>"
" <recording nick='recording-nick' xmlns='google:muc#media'/>"
" </item>"
" </items>"
" </pubsub>"
"</iq>";
xmpp_client->HandleStanza(buzz::XmlElement::ForStr(media_response));
EXPECT_EQ("muted-nick", listener->last_audio_muted_nick);
EXPECT_FALSE(listener->last_was_audio_muted);
EXPECT_TRUE(listener->last_is_audio_muted);
EXPECT_EQ("video-muted-nick", listener->last_video_muted_nick);
EXPECT_FALSE(listener->last_was_video_muted);
EXPECT_TRUE(listener->last_is_video_muted);
EXPECT_EQ("video-paused-nick", listener->last_video_paused_nick);
EXPECT_FALSE(listener->last_was_video_paused);
EXPECT_TRUE(listener->last_is_video_paused);
EXPECT_EQ("recording-nick", listener->last_recording_nick);
EXPECT_FALSE(listener->last_was_recording);
EXPECT_TRUE(listener->last_is_recording);
std::string incoming_presenter_resets_message =
"<message xmlns='jabber:client' from='room@domain.com'>"
" <event xmlns='http://jabber.org/protocol/pubsub#event'>"
" <items node='google:presenter'>"
" <item id='12348'>"
" <presenter xmlns='google:presenter' nick='presenting-nick'/>"
" <pre:presentation-item xmlns:pre='google:presenter'"
" pre:presentation-type='o'/>"
" </item>"
" </items>"
" </event>"
"</message>";
xmpp_client->HandleStanza(
buzz::XmlElement::ForStr(incoming_presenter_resets_message));
EXPECT_EQ("presenting-nick", listener->last_presenter_nick);
//EXPECT_TRUE(listener->last_was_presenting);
EXPECT_FALSE(listener->last_is_presenting);
std::string incoming_presenter_retracts_message =
"<message xmlns='jabber:client' from='room@domain.com'>"
" <event xmlns='http://jabber.org/protocol/pubsub#event'>"
" <items node='google:presenter'>"
" <retract id='12344'/>"
" </items>"
" </event>"
"</message>";
xmpp_client->HandleStanza(
buzz::XmlElement::ForStr(incoming_presenter_retracts_message));
EXPECT_EQ("presenting-nick2", listener->last_presenter_nick);
EXPECT_TRUE(listener->last_was_presenting);
EXPECT_FALSE(listener->last_is_presenting);
std::string incoming_media_retracts_message =
"<message xmlns='jabber:client' from='room@domain.com'>"
" <event xmlns='http://jabber.org/protocol/pubsub#event'>"
" <items node='google:muc#media'>"
" <item id='audio-mute:muted-nick'>"
" </item>"
" <retract id='video-mute:video-muted-nick'/>"
" <retract id='video-pause:video-paused-nick'/>"
" <retract id='recording:recording-nick'/>"
" </items>"
" </event>"
"</message>";
xmpp_client->HandleStanza(
buzz::XmlElement::ForStr(incoming_media_retracts_message));
EXPECT_EQ("muted-nick", listener->last_audio_muted_nick);
EXPECT_TRUE(listener->last_was_audio_muted);
EXPECT_FALSE(listener->last_is_audio_muted);
EXPECT_EQ("video-paused-nick", listener->last_video_paused_nick);
EXPECT_TRUE(listener->last_was_video_paused);
EXPECT_FALSE(listener->last_is_video_paused);
EXPECT_EQ("recording-nick", listener->last_recording_nick);
EXPECT_TRUE(listener->last_was_recording);
EXPECT_FALSE(listener->last_is_recording);
std::string incoming_presenter_changes_message =
"<message xmlns='jabber:client' from='room@domain.com'>"
" <event xmlns='http://jabber.org/protocol/pubsub#event'>"
" <items node='google:presenter'>"
" <item id='presenting-nick2'>"
" <presenter xmlns='google:presenter' nick='presenting-nick2'/>"
" <pre:presentation-item xmlns:pre='google:presenter'"
" pre:presentation-type='s'/>"
" </item>"
" </items>"
" </event>"
"</message>";
xmpp_client->HandleStanza(
buzz::XmlElement::ForStr(incoming_presenter_changes_message));
EXPECT_EQ("presenting-nick2", listener->last_presenter_nick);
EXPECT_FALSE(listener->last_was_presenting);
EXPECT_TRUE(listener->last_is_presenting);
xmpp_client->HandleStanza(
buzz::XmlElement::ForStr(incoming_presenter_changes_message));
EXPECT_EQ("presenting-nick2", listener->last_presenter_nick);
EXPECT_TRUE(listener->last_was_presenting);
EXPECT_TRUE(listener->last_is_presenting);
std::string incoming_media_changes_message =
"<message xmlns='jabber:client' from='room@domain.com'>"
" <event xmlns='http://jabber.org/protocol/pubsub#event'>"
" <items node='google:muc#media'>"
" <item id='audio-mute:muted-nick2'>"
" <audio-mute nick='muted-nick2' xmlns='google:muc#media'/>"
" </item>"
" <item id='video-pause:video-paused-nick2'>"
" <video-pause nick='video-paused-nick2' xmlns='google:muc#media'/>"
" </item>"
" <item id='recording:recording-nick2'>"
" <recording nick='recording-nick2' xmlns='google:muc#media'/>"
" </item>"
" </items>"
" </event>"
"</message>";
xmpp_client->HandleStanza(
buzz::XmlElement::ForStr(incoming_media_changes_message));
EXPECT_EQ("muted-nick2", listener->last_audio_muted_nick);
EXPECT_FALSE(listener->last_was_audio_muted);
EXPECT_TRUE(listener->last_is_audio_muted);
EXPECT_EQ("video-paused-nick2", listener->last_video_paused_nick);
EXPECT_FALSE(listener->last_was_video_paused);
EXPECT_TRUE(listener->last_is_video_paused);
EXPECT_EQ("recording-nick2", listener->last_recording_nick);
EXPECT_FALSE(listener->last_was_recording);
EXPECT_TRUE(listener->last_is_recording);
std::string incoming_remote_mute_message =
"<message xmlns='jabber:client' from='room@domain.com'>"
" <event xmlns='http://jabber.org/protocol/pubsub#event'>"
" <items node='google:muc#media'>"
" <item id='audio-mute:mutee' publisher='room@domain.com/muter'>"
" <audio-mute nick='mutee' xmlns='google:muc#media'/>"
" </item>"
" </items>"
" </event>"
"</message>";
listener->last_is_audio_muted = false;
xmpp_client->HandleStanza(
buzz::XmlElement::ForStr(incoming_remote_mute_message));
EXPECT_EQ("mutee", listener->last_mutee_nick);
EXPECT_EQ("muter", listener->last_muter_nick);
EXPECT_FALSE(listener->last_should_mute);
EXPECT_EQ("mutee", listener->last_audio_muted_nick);
EXPECT_TRUE(listener->last_is_audio_muted);
std::string incoming_remote_mute_me_message =
"<message xmlns='jabber:client' from='room@domain.com'>"
" <event xmlns='http://jabber.org/protocol/pubsub#event'>"
" <items node='google:muc#media'>"
" <item id='audio-mute:me' publisher='room@domain.com/muter'>"
" <audio-mute nick='me' xmlns='google:muc#media'/>"
" </item>"
" </items>"
" </event>"
"</message>";
listener->last_is_audio_muted = false;
xmpp_client->HandleStanza(
buzz::XmlElement::ForStr(incoming_remote_mute_me_message));
EXPECT_EQ("me", listener->last_mutee_nick);
EXPECT_EQ("muter", listener->last_muter_nick);
EXPECT_TRUE(listener->last_should_mute);
EXPECT_EQ("me", listener->last_audio_muted_nick);
EXPECT_TRUE(listener->last_is_audio_muted);
std::string incoming_media_block_message =
"<message xmlns='jabber:client' from='room@domain.com'>"
" <event xmlns='http://jabber.org/protocol/pubsub#event'>"
" <items node='google:muc#media'>"
" <item id='block:blocker:blockee'"
" publisher='room@domain.com/blocker'>"
" <block nick='blockee' xmlns='google:muc#media'/>"
" </item>"
" </items>"
" </event>"
"</message>";
xmpp_client->HandleStanza(
buzz::XmlElement::ForStr(incoming_media_block_message));
EXPECT_EQ("blockee", listener->last_blockee_nick);
EXPECT_EQ("blocker", listener->last_blocker_nick);
}
TEST_F(HangoutPubSubClientTest, TestRequestError) {
client->RequestAll();
std::string result_iq =
"<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'>"
" <error type='auth'>"
" <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>"
" </error>"
"</iq>";
xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
EXPECT_EQ(1, listener->request_error_count);
EXPECT_EQ("google:presenter", listener->request_error_node);
}
TEST_F(HangoutPubSubClientTest, TestPublish) {
client->PublishPresenterState(true);
std::string expected_presenter_iq =
"<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" "
"xmlns:cli=\"jabber:client\">"
"<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">"
"<publish node=\"google:presenter\">"
"<item id=\"me\">"
"<presenter xmlns=\"google:presenter\""
" nick=\"me\"/>"
"<pre:presentation-item"
" pre:presentation-type=\"s\" xmlns:pre=\"google:presenter\"/>"
"</item>"
"</publish>"
"</pubsub>"
"</cli:iq>";
ASSERT_EQ(1U, xmpp_client->sent_stanzas().size());
EXPECT_EQ(expected_presenter_iq,
xmpp_client->sent_stanzas()[0]->Str());
client->PublishAudioMuteState(true);
std::string expected_audio_mute_iq =
"<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" "
"xmlns:cli=\"jabber:client\">"
"<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">"
"<publish node=\"google:muc#media\">"
"<item id=\"audio-mute:me\">"
"<audio-mute xmlns=\"google:muc#media\" nick=\"me\"/>"
"</item>"
"</publish>"
"</pubsub>"
"</cli:iq>";
ASSERT_EQ(2U, xmpp_client->sent_stanzas().size());
EXPECT_EQ(expected_audio_mute_iq, xmpp_client->sent_stanzas()[1]->Str());
client->PublishVideoPauseState(true);
std::string expected_video_pause_iq =
"<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" "
"xmlns:cli=\"jabber:client\">"
"<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">"
"<publish node=\"google:muc#media\">"
"<item id=\"video-pause:me\">"
"<video-pause xmlns=\"google:muc#media\" nick=\"me\"/>"
"</item>"
"</publish>"
"</pubsub>"
"</cli:iq>";
ASSERT_EQ(3U, xmpp_client->sent_stanzas().size());
EXPECT_EQ(expected_video_pause_iq, xmpp_client->sent_stanzas()[2]->Str());
client->PublishRecordingState(true);
std::string expected_recording_iq =
"<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" "
"xmlns:cli=\"jabber:client\">"
"<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">"
"<publish node=\"google:muc#media\">"
"<item id=\"recording:me\">"
"<recording xmlns=\"google:muc#media\" nick=\"me\"/>"
"</item>"
"</publish>"
"</pubsub>"
"</cli:iq>";
ASSERT_EQ(4U, xmpp_client->sent_stanzas().size());
EXPECT_EQ(expected_recording_iq, xmpp_client->sent_stanzas()[3]->Str());
client->RemoteMute("mutee");
std::string expected_remote_mute_iq =
"<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" "
"xmlns:cli=\"jabber:client\">"
"<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">"
"<publish node=\"google:muc#media\">"
"<item id=\"audio-mute:mutee\">"
"<audio-mute xmlns=\"google:muc#media\" nick=\"mutee\"/>"
"</item>"
"</publish>"
"</pubsub>"
"</cli:iq>";
ASSERT_EQ(5U, xmpp_client->sent_stanzas().size());
EXPECT_EQ(expected_remote_mute_iq, xmpp_client->sent_stanzas()[4]->Str());
client->PublishPresenterState(false);
std::string expected_presenter_retract_iq =
"<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" "
"xmlns:cli=\"jabber:client\">"
"<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">"
"<publish node=\"google:presenter\">"
"<item id=\"me\">"
"<presenter xmlns=\"google:presenter\""
" nick=\"me\"/>"
"<pre:presentation-item"
" pre:presentation-type=\"o\" xmlns:pre=\"google:presenter\"/>"
"</item>"
"</publish>"
"</pubsub>"
"</cli:iq>";
ASSERT_EQ(6U, xmpp_client->sent_stanzas().size());
EXPECT_EQ(expected_presenter_retract_iq,
xmpp_client->sent_stanzas()[5]->Str());
client->PublishAudioMuteState(false);
std::string expected_audio_mute_retract_iq =
"<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" "
"xmlns:cli=\"jabber:client\">"
"<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">"
"<retract node=\"google:muc#media\" notify=\"true\">"
"<item id=\"audio-mute:me\"/>"
"</retract>"
"</pubsub>"
"</cli:iq>";
ASSERT_EQ(7U, xmpp_client->sent_stanzas().size());
EXPECT_EQ(expected_audio_mute_retract_iq,
xmpp_client->sent_stanzas()[6]->Str());
client->PublishVideoPauseState(false);
std::string expected_video_pause_retract_iq =
"<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" "
"xmlns:cli=\"jabber:client\">"
"<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">"
"<retract node=\"google:muc#media\" notify=\"true\">"
"<item id=\"video-pause:me\"/>"
"</retract>"
"</pubsub>"
"</cli:iq>";
ASSERT_EQ(8U, xmpp_client->sent_stanzas().size());
EXPECT_EQ(expected_video_pause_retract_iq,
xmpp_client->sent_stanzas()[7]->Str());
client->BlockMedia("blockee");
std::string expected_media_block_iq =
"<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" "
"xmlns:cli=\"jabber:client\">"
"<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">"
"<publish node=\"google:muc#media\">"
"<item id=\"block:me:blockee\">"
"<block xmlns=\"google:muc#media\" nick=\"blockee\"/>"
"</item>"
"</publish>"
"</pubsub>"
"</cli:iq>";
ASSERT_EQ(9U, xmpp_client->sent_stanzas().size());
EXPECT_EQ(expected_media_block_iq, xmpp_client->sent_stanzas()[8]->Str());
}
TEST_F(HangoutPubSubClientTest, TestPublishPresenterError) {
std::string result_iq =
"<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'/>";
client->PublishPresenterState(true);
xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
EXPECT_EQ(1, listener->publish_presenter_error_count);
EXPECT_EQ("0", listener->error_task_id);
}
TEST_F(HangoutPubSubClientTest, TestPublishAudioMuteError) {
std::string result_iq =
"<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'/>";
client->PublishAudioMuteState(true);
xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
EXPECT_EQ(1, listener->publish_audio_mute_error_count);
EXPECT_EQ("0", listener->error_task_id);
}
TEST_F(HangoutPubSubClientTest, TestPublishVideoPauseError) {
std::string result_iq =
"<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'/>";
client->PublishVideoPauseState(true);
xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
EXPECT_EQ(1, listener->publish_video_pause_error_count);
EXPECT_EQ("0", listener->error_task_id);
}
TEST_F(HangoutPubSubClientTest, TestPublishRecordingError) {
std::string result_iq =
"<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'/>";
client->PublishRecordingState(true);
xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
EXPECT_EQ(1, listener->publish_recording_error_count);
EXPECT_EQ("0", listener->error_task_id);
}
TEST_F(HangoutPubSubClientTest, TestPublishRemoteMuteResult) {
std::string result_iq =
"<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'/>";
client->RemoteMute("joe");
xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
EXPECT_EQ("joe", listener->remote_mute_mutee_nick);
EXPECT_EQ("0", listener->result_task_id);
}
TEST_F(HangoutPubSubClientTest, TestRemoteMuteError) {
std::string result_iq =
"<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'/>";
client->RemoteMute("joe");
xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
EXPECT_EQ(1, listener->remote_mute_error_count);
EXPECT_EQ("joe", listener->remote_mute_mutee_nick);
EXPECT_EQ("0", listener->error_task_id);
}
TEST_F(HangoutPubSubClientTest, TestPublishMediaBlockResult) {
std::string result_iq =
"<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'/>";
client->BlockMedia("joe");
xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
EXPECT_EQ("joe", listener->media_blockee_nick);
EXPECT_EQ("0", listener->result_task_id);
}
TEST_F(HangoutPubSubClientTest, TestMediaBlockError) {
std::string result_iq =
"<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'/>";
client->BlockMedia("joe");
xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
EXPECT_EQ(1, listener->remote_mute_error_count);
EXPECT_EQ("joe", listener->media_blockee_nick);
EXPECT_EQ("0", listener->error_task_id);
}

View File

@ -1,69 +0,0 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/xmpp/iqtask.h"
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/libjingle/xmpp/xmppclient.h"
namespace buzz {
static const int kDefaultIqTimeoutSecs = 15;
IqTask::IqTask(XmppTaskParentInterface* parent,
const std::string& verb,
const buzz::Jid& to,
buzz::XmlElement* el)
: buzz::XmppTask(parent, buzz::XmppEngine::HL_SINGLE),
to_(to),
stanza_(MakeIq(verb, to_, task_id())) {
stanza_->AddElement(el);
set_timeout_seconds(kDefaultIqTimeoutSecs);
}
int IqTask::ProcessStart() {
buzz::XmppReturnStatus ret = SendStanza(stanza_.get());
// TODO: HandleError(NULL) if SendStanza fails?
return (ret == buzz::XMPP_RETURN_OK) ? STATE_RESPONSE : STATE_ERROR;
}
bool IqTask::HandleStanza(const buzz::XmlElement* stanza) {
if (!MatchResponseIq(stanza, to_, task_id()))
return false;
if (stanza->Attr(buzz::QN_TYPE) != buzz::STR_RESULT &&
stanza->Attr(buzz::QN_TYPE) != buzz::STR_ERROR) {
return false;
}
QueueStanza(stanza);
return true;
}
int IqTask::ProcessResponse() {
const buzz::XmlElement* stanza = NextStanza();
if (stanza == NULL)
return STATE_BLOCKED;
bool success = (stanza->Attr(buzz::QN_TYPE) == buzz::STR_RESULT);
if (success) {
HandleResult(stanza);
} else {
SignalError(this, stanza->FirstNamed(QN_ERROR));
}
return STATE_DONE;
}
int IqTask::OnTimeout() {
SignalError(this, NULL);
return XmppTask::OnTimeout();
}
} // namespace buzz

View File

@ -1,49 +0,0 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_IQTASK_H_
#define WEBRTC_LIBJINGLE_XMPP_IQTASK_H_
#include <memory>
#include <string>
#include "webrtc/libjingle/xmpp/xmppengine.h"
#include "webrtc/libjingle/xmpp/xmpptask.h"
namespace buzz {
class IqTask : public XmppTask {
public:
IqTask(XmppTaskParentInterface* parent,
const std::string& verb, const Jid& to,
XmlElement* el);
virtual ~IqTask() {}
const XmlElement* stanza() const { return stanza_.get(); }
sigslot::signal2<IqTask*,
const XmlElement*> SignalError;
protected:
virtual void HandleResult(const XmlElement* element) = 0;
private:
virtual int ProcessStart();
virtual bool HandleStanza(const XmlElement* stanza);
virtual int ProcessResponse();
virtual int OnTimeout();
Jid to_;
std::unique_ptr<XmlElement> stanza_;
};
} // namespace buzz
#endif // WEBRTC_LIBJINGLE_XMPP_IQTASK_H_

View File

@ -1,379 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/xmpp/jid.h"
#include <ctype.h>
#include <algorithm>
#include <string>
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/base/common.h"
#include "webrtc/base/logging.h"
namespace buzz {
Jid::Jid() {
}
Jid::Jid(const std::string& jid_string) {
if (jid_string.empty())
return;
// First find the slash and slice off that part
size_t slash = jid_string.find('/');
resource_name_ = (slash == std::string::npos ? STR_EMPTY :
jid_string.substr(slash + 1));
// Now look for the node
size_t at = jid_string.find('@');
size_t domain_begin;
if (at < slash && at != std::string::npos) {
node_name_ = jid_string.substr(0, at);
domain_begin = at + 1;
} else {
domain_begin = 0;
}
// Now take what is left as the domain
size_t domain_length = (slash == std::string::npos) ?
(jid_string.length() - domain_begin) : (slash - domain_begin);
domain_name_ = jid_string.substr(domain_begin, domain_length);
ValidateOrReset();
}
Jid::Jid(const std::string& node_name,
const std::string& domain_name,
const std::string& resource_name)
: node_name_(node_name),
domain_name_(domain_name),
resource_name_(resource_name) {
ValidateOrReset();
}
void Jid::ValidateOrReset() {
bool valid_node;
bool valid_domain;
bool valid_resource;
node_name_ = PrepNode(node_name_, &valid_node);
domain_name_ = PrepDomain(domain_name_, &valid_domain);
resource_name_ = PrepResource(resource_name_, &valid_resource);
if (!valid_node || !valid_domain || !valid_resource) {
node_name_.clear();
domain_name_.clear();
resource_name_.clear();
}
}
std::string Jid::Str() const {
if (!IsValid())
return STR_EMPTY;
std::string ret;
if (!node_name_.empty())
ret = node_name_ + "@";
ASSERT(domain_name_ != STR_EMPTY);
ret += domain_name_;
if (!resource_name_.empty())
ret += "/" + resource_name_;
return ret;
}
Jid::~Jid() {
}
bool Jid::IsEmpty() const {
return (node_name_.empty() && domain_name_.empty() &&
resource_name_.empty());
}
bool Jid::IsValid() const {
return !domain_name_.empty();
}
bool Jid::IsBare() const {
if (IsEmpty()) {
LOG(LS_VERBOSE) << "Warning: Calling IsBare() on the empty jid.";
return true;
}
return IsValid() && resource_name_.empty();
}
bool Jid::IsFull() const {
return IsValid() && !resource_name_.empty();
}
Jid Jid::BareJid() const {
if (!IsValid())
return Jid();
if (!IsFull())
return *this;
return Jid(node_name_, domain_name_, STR_EMPTY);
}
bool Jid::BareEquals(const Jid& other) const {
return other.node_name_ == node_name_ &&
other.domain_name_ == domain_name_;
}
void Jid::CopyFrom(const Jid& jid) {
this->node_name_ = jid.node_name_;
this->domain_name_ = jid.domain_name_;
this->resource_name_ = jid.resource_name_;
}
bool Jid::operator==(const Jid& other) const {
return other.node_name_ == node_name_ &&
other.domain_name_ == domain_name_ &&
other.resource_name_ == resource_name_;
}
int Jid::Compare(const Jid& other) const {
int compare_result;
compare_result = node_name_.compare(other.node_name_);
if (0 != compare_result)
return compare_result;
compare_result = domain_name_.compare(other.domain_name_);
if (0 != compare_result)
return compare_result;
compare_result = resource_name_.compare(other.resource_name_);
return compare_result;
}
// --- JID parsing code: ---
// Checks and normalizes the node part of a JID.
std::string Jid::PrepNode(const std::string& node, bool* valid) {
*valid = false;
std::string result;
for (std::string::const_iterator i = node.begin(); i < node.end(); ++i) {
bool char_valid = true;
unsigned char ch = *i;
if (ch <= 0x7F) {
result += PrepNodeAscii(ch, &char_valid);
}
else {
// TODO: implement the correct stringprep protocol for these
result += tolower(ch);
}
if (!char_valid) {
return STR_EMPTY;
}
}
if (result.length() > 1023) {
return STR_EMPTY;
}
*valid = true;
return result;
}
// Returns the appropriate mapping for an ASCII character in a node.
char Jid::PrepNodeAscii(char ch, bool* valid) {
*valid = true;
switch (ch) {
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
case 'V': case 'W': case 'X': case 'Y': case 'Z':
return (char)(ch + ('a' - 'A'));
case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05:
case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B:
case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x10: case 0x11:
case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
case ' ': case '&': case '/': case ':': case '<': case '>': case '@':
case '\"': case '\'':
case 0x7F:
*valid = false;
return 0;
default:
return ch;
}
}
// Checks and normalizes the resource part of a JID.
std::string Jid::PrepResource(const std::string& resource, bool* valid) {
*valid = false;
std::string result;
for (std::string::const_iterator i = resource.begin();
i < resource.end(); ++i) {
bool char_valid = true;
unsigned char ch = *i;
if (ch <= 0x7F) {
result += PrepResourceAscii(ch, &char_valid);
}
else {
// TODO: implement the correct stringprep protocol for these
result += ch;
}
}
if (result.length() > 1023) {
return STR_EMPTY;
}
*valid = true;
return result;
}
// Returns the appropriate mapping for an ASCII character in a resource.
char Jid::PrepResourceAscii(char ch, bool* valid) {
*valid = true;
switch (ch) {
case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05:
case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B:
case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x10: case 0x11:
case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
case 0x7F:
*valid = false;
return 0;
default:
return ch;
}
}
// Checks and normalizes the domain part of a JID.
std::string Jid::PrepDomain(const std::string& domain, bool* valid) {
*valid = false;
std::string result;
// TODO: if the domain contains a ':', then we should parse it
// as an IPv6 address rather than giving an error about illegal domain.
PrepDomain(domain, &result, valid);
if (!*valid) {
return STR_EMPTY;
}
if (result.length() > 1023) {
return STR_EMPTY;
}
*valid = true;
return result;
}
// Checks and normalizes an IDNA domain.
void Jid::PrepDomain(const std::string& domain, std::string* buf, bool* valid) {
*valid = false;
std::string::const_iterator last = domain.begin();
for (std::string::const_iterator i = domain.begin(); i < domain.end(); ++i) {
bool label_valid = true;
char ch = *i;
switch (ch) {
case 0x002E:
#if 0 // FIX: This isn't UTF-8-aware.
case 0x3002:
case 0xFF0E:
case 0xFF61:
#endif
PrepDomainLabel(last, i, buf, &label_valid);
*buf += '.';
last = i + 1;
break;
}
if (!label_valid) {
return;
}
}
PrepDomainLabel(last, domain.end(), buf, valid);
}
// Checks and normalizes a domain label.
void Jid::PrepDomainLabel(
std::string::const_iterator start, std::string::const_iterator end,
std::string* buf, bool* valid) {
*valid = false;
int start_len = static_cast<int>(buf->length());
for (std::string::const_iterator i = start; i < end; ++i) {
bool char_valid = true;
unsigned char ch = *i;
if (ch <= 0x7F) {
*buf += PrepDomainLabelAscii(ch, &char_valid);
}
else {
// TODO: implement ToASCII for these
*buf += ch;
}
if (!char_valid) {
return;
}
}
int count = static_cast<int>(buf->length() - start_len);
if (count == 0) {
return;
}
else if (count > 63) {
return;
}
// Is this check needed? See comment in PrepDomainLabelAscii.
if ((*buf)[start_len] == '-') {
return;
}
if ((*buf)[buf->length() - 1] == '-') {
return;
}
*valid = true;
}
// Returns the appropriate mapping for an ASCII character in a domain label.
char Jid::PrepDomainLabelAscii(char ch, bool* valid) {
*valid = true;
// TODO: A literal reading of the spec seems to say that we do
// not need to check for these illegal characters (an "internationalized
// domain label" runs ToASCII with UseSTD3... set to false). But that
// can't be right. We should at least be checking that there are no '/'
// or '@' characters in the domain. Perhaps we should see what others
// do in this case.
switch (ch) {
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
case 'V': case 'W': case 'X': case 'Y': case 'Z':
return (char)(ch + ('a' - 'A'));
case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05:
case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B:
case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x10: case 0x11:
case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D:
case 0x1E: case 0x1F: case 0x20: case 0x21: case 0x22: case 0x23:
case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29:
case 0x2A: case 0x2B: case 0x2C: case 0x2E: case 0x2F: case 0x3A:
case 0x3B: case 0x3C: case 0x3D: case 0x3E: case 0x3F: case 0x40:
case 0x5B: case 0x5C: case 0x5D: case 0x5E: case 0x5F: case 0x60:
case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F:
*valid = false;
return 0;
default:
return ch;
}
}
} // namespace buzz

View File

@ -1,80 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_JID_H_
#define WEBRTC_LIBJINGLE_XMPP_JID_H_
#include <string>
#include "webrtc/libjingle/xmllite/xmlconstants.h"
namespace buzz {
// The Jid class encapsulates and provides parsing help for Jids. A Jid
// consists of three parts: the node, the domain and the resource, e.g.:
//
// node@domain/resource
//
// The node and resource are both optional. A valid jid is defined to have
// a domain. A bare jid is defined to not have a resource and a full jid
// *does* have a resource.
class Jid {
public:
explicit Jid();
explicit Jid(const std::string& jid_string);
explicit Jid(const std::string& node_name,
const std::string& domain_name,
const std::string& resource_name);
~Jid();
const std::string & node() const { return node_name_; }
const std::string & domain() const { return domain_name_; }
const std::string & resource() const { return resource_name_; }
std::string Str() const;
Jid BareJid() const;
bool IsEmpty() const;
bool IsValid() const;
bool IsBare() const;
bool IsFull() const;
bool BareEquals(const Jid& other) const;
void CopyFrom(const Jid& jid);
bool operator==(const Jid& other) const;
bool operator!=(const Jid& other) const { return !operator==(other); }
bool operator<(const Jid& other) const { return Compare(other) < 0; };
bool operator>(const Jid& other) const { return Compare(other) > 0; };
int Compare(const Jid & other) const;
private:
void ValidateOrReset();
static std::string PrepNode(const std::string& node, bool* valid);
static char PrepNodeAscii(char ch, bool* valid);
static std::string PrepResource(const std::string& start, bool* valid);
static char PrepResourceAscii(char ch, bool* valid);
static std::string PrepDomain(const std::string& domain, bool* valid);
static void PrepDomain(const std::string& domain,
std::string* buf, bool* valid);
static void PrepDomainLabel(
std::string::const_iterator start, std::string::const_iterator end,
std::string* buf, bool* valid);
static char PrepDomainLabelAscii(char ch, bool *valid);
std::string node_name_;
std::string domain_name_;
std::string resource_name_;
};
}
#endif // WEBRTC_LIBJINGLE_XMPP_JID_H_

View File

@ -1,122 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/xmpp/jid.h"
#include "webrtc/base/gunit.h"
using buzz::Jid;
TEST(JidTest, TestDomain) {
Jid jid("dude");
EXPECT_EQ("", jid.node());
EXPECT_EQ("dude", jid.domain());
EXPECT_EQ("", jid.resource());
EXPECT_EQ("dude", jid.Str());
EXPECT_EQ("dude", jid.BareJid().Str());
EXPECT_TRUE(jid.IsValid());
EXPECT_TRUE(jid.IsBare());
EXPECT_FALSE(jid.IsFull());
}
TEST(JidTest, TestNodeDomain) {
Jid jid("walter@dude");
EXPECT_EQ("walter", jid.node());
EXPECT_EQ("dude", jid.domain());
EXPECT_EQ("", jid.resource());
EXPECT_EQ("walter@dude", jid.Str());
EXPECT_EQ("walter@dude", jid.BareJid().Str());
EXPECT_TRUE(jid.IsValid());
EXPECT_TRUE(jid.IsBare());
EXPECT_FALSE(jid.IsFull());
}
TEST(JidTest, TestDomainResource) {
Jid jid("dude/bowlingalley");
EXPECT_EQ("", jid.node());
EXPECT_EQ("dude", jid.domain());
EXPECT_EQ("bowlingalley", jid.resource());
EXPECT_EQ("dude/bowlingalley", jid.Str());
EXPECT_EQ("dude", jid.BareJid().Str());
EXPECT_TRUE(jid.IsValid());
EXPECT_FALSE(jid.IsBare());
EXPECT_TRUE(jid.IsFull());
}
TEST(JidTest, TestNodeDomainResource) {
Jid jid("walter@dude/bowlingalley");
EXPECT_EQ("walter", jid.node());
EXPECT_EQ("dude", jid.domain());
EXPECT_EQ("bowlingalley", jid.resource());
EXPECT_EQ("walter@dude/bowlingalley", jid.Str());
EXPECT_EQ("walter@dude", jid.BareJid().Str());
EXPECT_TRUE(jid.IsValid());
EXPECT_FALSE(jid.IsBare());
EXPECT_TRUE(jid.IsFull());
}
TEST(JidTest, TestNode) {
Jid jid("walter@");
EXPECT_EQ("", jid.node());
EXPECT_EQ("", jid.domain());
EXPECT_EQ("", jid.resource());
EXPECT_EQ("", jid.Str());
EXPECT_EQ("", jid.BareJid().Str());
EXPECT_FALSE(jid.IsValid());
EXPECT_TRUE(jid.IsBare());
EXPECT_FALSE(jid.IsFull());
}
TEST(JidTest, TestResource) {
Jid jid("/bowlingalley");
EXPECT_EQ("", jid.node());
EXPECT_EQ("", jid.domain());
EXPECT_EQ("", jid.resource());
EXPECT_EQ("", jid.Str());
EXPECT_EQ("", jid.BareJid().Str());
EXPECT_FALSE(jid.IsValid());
EXPECT_TRUE(jid.IsBare());
EXPECT_FALSE(jid.IsFull());
}
TEST(JidTest, TestNodeResource) {
Jid jid("walter@/bowlingalley");
EXPECT_EQ("", jid.node());
EXPECT_EQ("", jid.domain());
EXPECT_EQ("", jid.resource());
EXPECT_EQ("", jid.Str());
EXPECT_EQ("", jid.BareJid().Str());
EXPECT_FALSE(jid.IsValid());
EXPECT_TRUE(jid.IsBare());
EXPECT_FALSE(jid.IsFull());
}
TEST(JidTest, TestFunky) {
Jid jid("bowling@muchat/walter@dude");
EXPECT_EQ("bowling", jid.node());
EXPECT_EQ("muchat", jid.domain());
EXPECT_EQ("walter@dude", jid.resource());
EXPECT_EQ("bowling@muchat/walter@dude", jid.Str());
EXPECT_EQ("bowling@muchat", jid.BareJid().Str());
EXPECT_TRUE(jid.IsValid());
EXPECT_FALSE(jid.IsBare());
EXPECT_TRUE(jid.IsFull());
}
TEST(JidTest, TestFunky2) {
Jid jid("muchat/walter@dude");
EXPECT_EQ("", jid.node());
EXPECT_EQ("muchat", jid.domain());
EXPECT_EQ("walter@dude", jid.resource());
EXPECT_EQ("muchat/walter@dude", jid.Str());
EXPECT_EQ("muchat", jid.BareJid().Str());
EXPECT_TRUE(jid.IsValid());
EXPECT_FALSE(jid.IsBare());
EXPECT_TRUE(jid.IsFull());
}

View File

@ -1,35 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_MODULE_H_
#define WEBRTC_LIBJINGLE_XMPP_MODULE_H_
#include "webrtc/libjingle/xmpp/xmppengine.h"
namespace buzz {
class XmppEngine;
//! This is the base class for extension modules.
//! An engine is registered with the module and the module then hooks the
//! appropriate parts of the engine to implement that set of features. It is
//! important to unregister modules before destructing the engine.
class XmppModule {
public:
virtual ~XmppModule() {}
//! Register the engine with the module. Only one engine can be associated
//! with a module at a time. This method will return an error if there is
//! already an engine registered.
virtual XmppReturnStatus RegisterEngine(XmppEngine* engine) = 0;
};
}
#endif // WEBRTC_LIBJINGLE_XMPP_MODULE_H_

View File

@ -1,48 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/xmpp/moduleimpl.h"
#include "webrtc/base/common.h"
namespace buzz {
XmppModuleImpl::XmppModuleImpl() :
engine_(NULL),
stanza_handler_(this) {
}
XmppModuleImpl::~XmppModuleImpl()
{
if (engine_ != NULL) {
engine_->RemoveStanzaHandler(&stanza_handler_);
engine_ = NULL;
}
}
XmppReturnStatus
XmppModuleImpl::RegisterEngine(XmppEngine* engine)
{
if (NULL == engine || NULL != engine_)
return XMPP_RETURN_BADARGUMENT;
engine->AddStanzaHandler(&stanza_handler_);
engine_ = engine;
return XMPP_RETURN_OK;
}
XmppEngine*
XmppModuleImpl::engine() {
ASSERT(NULL != engine_);
return engine_;
}
}

View File

@ -1,76 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_MODULEIMPL_H_
#define WEBRTC_LIBJINGLE_XMPP_MODULEIMPL_H_
#include "webrtc/libjingle/xmpp/module.h"
#include "webrtc/libjingle/xmpp/xmppengine.h"
namespace buzz {
//! This is the base implementation class for extension modules.
//! An engine is registered with the module and the module then hooks the
//! appropriate parts of the engine to implement that set of features. It is
//! important to unregister modules before destructing the engine.
class XmppModuleImpl {
protected:
XmppModuleImpl();
virtual ~XmppModuleImpl();
//! Register the engine with the module. Only one engine can be associated
//! with a module at a time. This method will return an error if there is
//! already an engine registered.
XmppReturnStatus RegisterEngine(XmppEngine* engine);
//! Gets the engine that this module is attached to.
XmppEngine* engine();
//! Process the given stanza.
//! The module must return true if it has handled the stanza.
//! A false return value causes the stanza to be passed on to
//! the next registered handler.
virtual bool HandleStanza(const XmlElement *) { return false; };
private:
//! The ModuleSessionHelper nested class allows the Module
//! to hook into and get stanzas and events from the engine.
class ModuleStanzaHandler : public XmppStanzaHandler {
friend class XmppModuleImpl;
ModuleStanzaHandler(XmppModuleImpl* module) :
module_(module) {
}
bool HandleStanza(const XmlElement* stanza) {
return module_->HandleStanza(stanza);
}
XmppModuleImpl* module_;
};
friend class ModuleStanzaHandler;
XmppEngine* engine_;
ModuleStanzaHandler stanza_handler_;
};
// This macro will implement the XmppModule interface for a class
// that derives from both XmppModuleImpl and XmppModule
#define IMPLEMENT_XMPPMODULE \
XmppReturnStatus RegisterEngine(XmppEngine* engine) { \
return XmppModuleImpl::RegisterEngine(engine); \
}
}
#endif // WEBRTC_LIBJINGLE_XMPP_MODULEIMPL_H_

View File

@ -1,73 +0,0 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <string>
#include <vector>
#include "webrtc/libjingle/xmpp/mucroomconfigtask.h"
#include "webrtc/libjingle/xmpp/constants.h"
namespace buzz {
MucRoomConfigTask::MucRoomConfigTask(
XmppTaskParentInterface* parent,
const Jid& room_jid,
const std::string& room_name,
const std::vector<std::string>& room_features)
: IqTask(parent, STR_SET, room_jid,
MakeRequest(room_name, room_features)),
room_jid_(room_jid) {
}
XmlElement* MucRoomConfigTask::MakeRequest(
const std::string& room_name,
const std::vector<std::string>& room_features) {
buzz::XmlElement* owner_query = new
buzz::XmlElement(buzz::QN_MUC_OWNER_QUERY, true);
buzz::XmlElement* x_form = new buzz::XmlElement(buzz::QN_XDATA_X, true);
x_form->SetAttr(buzz::QN_TYPE, buzz::STR_FORM);
buzz::XmlElement* roomname_field =
new buzz::XmlElement(buzz::QN_XDATA_FIELD, false);
roomname_field->SetAttr(buzz::QN_VAR, buzz::STR_MUC_ROOMCONFIG_ROOMNAME);
roomname_field->SetAttr(buzz::QN_TYPE, buzz::STR_TEXT_SINGLE);
buzz::XmlElement* roomname_value =
new buzz::XmlElement(buzz::QN_XDATA_VALUE, false);
roomname_value->SetBodyText(room_name);
roomname_field->AddElement(roomname_value);
x_form->AddElement(roomname_field);
buzz::XmlElement* features_field =
new buzz::XmlElement(buzz::QN_XDATA_FIELD, false);
features_field->SetAttr(buzz::QN_VAR, buzz::STR_MUC_ROOMCONFIG_FEATURES);
features_field->SetAttr(buzz::QN_TYPE, buzz::STR_LIST_MULTI);
for (std::vector<std::string>::const_iterator feature = room_features.begin();
feature != room_features.end(); ++feature) {
buzz::XmlElement* features_value =
new buzz::XmlElement(buzz::QN_XDATA_VALUE, false);
features_value->SetBodyText(*feature);
features_field->AddElement(features_value);
}
x_form->AddElement(features_field);
owner_query->AddElement(x_form);
return owner_query;
}
void MucRoomConfigTask::HandleResult(const XmlElement* element) {
SignalResult(this);
}
} // namespace buzz

View File

@ -1,47 +0,0 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_MUCROOMCONFIGTASK_H_
#define WEBRTC_LIBJINGLE_XMPP_MUCROOMCONFIGTASK_H_
#include <string>
#include "webrtc/libjingle/xmpp/iqtask.h"
namespace buzz {
// This task configures the muc room for document sharing and other enterprise
// specific goodies.
class MucRoomConfigTask : public IqTask {
public:
MucRoomConfigTask(XmppTaskParentInterface* parent,
const Jid& room_jid,
const std::string& room_name,
const std::vector<std::string>& room_features);
// Room configuration does not return any reasonable error
// values. The First config request configures the room, subseqent
// ones are just ignored by server and server returns empty
// response.
sigslot::signal1<MucRoomConfigTask*> SignalResult;
const Jid& room_jid() const { return room_jid_; }
protected:
virtual void HandleResult(const XmlElement* stanza);
private:
static XmlElement* MakeRequest(const std::string& room_name,
const std::vector<std::string>& room_features);
Jid room_jid_;
};
} // namespace buzz
#endif // WEBRTC_LIBJINGLE_XMPP_MUCROOMCONFIGTASK_H_

View File

@ -1,127 +0,0 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <string>
#include <vector>
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/libjingle/xmpp/fakexmppclient.h"
#include "webrtc/libjingle/xmpp/mucroomconfigtask.h"
#include "webrtc/base/faketaskrunner.h"
#include "webrtc/base/gunit.h"
#include "webrtc/base/sigslot.h"
class MucRoomConfigListener : public sigslot::has_slots<> {
public:
MucRoomConfigListener() : result_count(0), error_count(0) {}
void OnResult(buzz::MucRoomConfigTask*) {
++result_count;
}
void OnError(buzz::IqTask* task,
const buzz::XmlElement* error) {
++error_count;
}
int result_count;
int error_count;
};
class MucRoomConfigTaskTest : public testing::Test {
public:
MucRoomConfigTaskTest() :
room_jid("muc-jid-ponies@domain.com"),
room_name("ponies") {
}
virtual void SetUp() {
runner = new rtc::FakeTaskRunner();
xmpp_client = new buzz::FakeXmppClient(runner);
listener = new MucRoomConfigListener();
}
virtual void TearDown() {
delete listener;
// delete xmpp_client; Deleted by deleting runner.
delete runner;
}
rtc::FakeTaskRunner* runner;
buzz::FakeXmppClient* xmpp_client;
MucRoomConfigListener* listener;
buzz::Jid room_jid;
std::string room_name;
};
TEST_F(MucRoomConfigTaskTest, TestConfigEnterprise) {
ASSERT_EQ(0U, xmpp_client->sent_stanzas().size());
std::vector<std::string> room_features;
room_features.push_back("feature1");
room_features.push_back("feature2");
buzz::MucRoomConfigTask* task = new buzz::MucRoomConfigTask(
xmpp_client, room_jid, "ponies", room_features);
EXPECT_EQ(room_jid, task->room_jid());
task->SignalResult.connect(listener, &MucRoomConfigListener::OnResult);
task->Start();
std::string expected_iq =
"<cli:iq type=\"set\" to=\"muc-jid-ponies@domain.com\" id=\"0\" "
"xmlns:cli=\"jabber:client\">"
"<query xmlns=\"http://jabber.org/protocol/muc#owner\">"
"<x xmlns=\"jabber:x:data\" type=\"form\">"
"<field var=\"muc#roomconfig_roomname\" type=\"text-single\">"
"<value>ponies</value>"
"</field>"
"<field var=\"muc#roomconfig_features\" type=\"list-multi\">"
"<value>feature1</value>"
"<value>feature2</value>"
"</field>"
"</x>"
"</query>"
"</cli:iq>";
ASSERT_EQ(1U, xmpp_client->sent_stanzas().size());
EXPECT_EQ(expected_iq, xmpp_client->sent_stanzas()[0]->Str());
EXPECT_EQ(0, listener->result_count);
EXPECT_EQ(0, listener->error_count);
std::string response_iq =
"<iq xmlns='jabber:client' id='0' type='result'"
" from='muc-jid-ponies@domain.com'>"
"</iq>";
xmpp_client->HandleStanza(buzz::XmlElement::ForStr(response_iq));
EXPECT_EQ(1, listener->result_count);
EXPECT_EQ(0, listener->error_count);
}
TEST_F(MucRoomConfigTaskTest, TestError) {
std::vector<std::string> room_features;
buzz::MucRoomConfigTask* task = new buzz::MucRoomConfigTask(
xmpp_client, room_jid, "ponies", room_features);
task->SignalError.connect(listener, &MucRoomConfigListener::OnError);
task->Start();
std::string error_iq =
"<iq xmlns='jabber:client' id='0' type='error'"
" from='muc-jid-ponies@domain.com'>"
"</iq>";
xmpp_client->HandleStanza(buzz::XmlElement::ForStr(error_iq));
EXPECT_EQ(0, listener->result_count);
EXPECT_EQ(1, listener->error_count);
}

View File

@ -1,66 +0,0 @@
/*
* Copyright 2012 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/xmpp/mucroomdiscoverytask.h"
#include "webrtc/libjingle/xmpp/constants.h"
namespace buzz {
MucRoomDiscoveryTask::MucRoomDiscoveryTask(
XmppTaskParentInterface* parent,
const Jid& room_jid)
: IqTask(parent, STR_GET, room_jid,
new buzz::XmlElement(buzz::QN_DISCO_INFO_QUERY)) {
}
void MucRoomDiscoveryTask::HandleResult(const XmlElement* stanza) {
const XmlElement* query = stanza->FirstNamed(QN_DISCO_INFO_QUERY);
if (query == NULL) {
SignalError(this, NULL);
return;
}
std::set<std::string> features;
std::map<std::string, std::string> extended_info;
const XmlElement* identity = query->FirstNamed(QN_DISCO_IDENTITY);
if (identity == NULL || !identity->HasAttr(QN_NAME)) {
SignalResult(this, false, "", "", features, extended_info);
return;
}
const std::string name(identity->Attr(QN_NAME));
// Get the conversation id
const XmlElement* conversation =
identity->FirstNamed(QN_GOOGLE_MUC_HANGOUT_CONVERSATION_ID);
std::string conversation_id;
if (conversation != NULL) {
conversation_id = conversation->BodyText();
}
for (const XmlElement* feature = query->FirstNamed(QN_DISCO_FEATURE);
feature != NULL; feature = feature->NextNamed(QN_DISCO_FEATURE)) {
features.insert(feature->Attr(QN_VAR));
}
const XmlElement* data_x = query->FirstNamed(QN_XDATA_X);
if (data_x != NULL) {
for (const XmlElement* field = data_x->FirstNamed(QN_XDATA_FIELD);
field != NULL; field = field->NextNamed(QN_XDATA_FIELD)) {
const std::string key(field->Attr(QN_VAR));
extended_info[key] = field->Attr(QN_XDATA_VALUE);
}
}
SignalResult(this, true, name, conversation_id, features, extended_info);
}
} // namespace buzz

View File

@ -1,41 +0,0 @@
/*
* Copyright 2012 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_MUCROOMDISCOVERYTASK_H_
#define WEBRTC_LIBJINGLE_XMPP_MUCROOMDISCOVERYTASK_H_
#include <map>
#include <string>
#include "webrtc/libjingle/xmpp/iqtask.h"
namespace buzz {
// This task requests the feature capabilities of the room. It is based on
// XEP-0030, and extended using XEP-0004.
class MucRoomDiscoveryTask : public IqTask {
public:
MucRoomDiscoveryTask(XmppTaskParentInterface* parent,
const Jid& room_jid);
// Signal (exists, name, conversationId, features, extended_info)
sigslot::signal6<MucRoomDiscoveryTask*,
bool,
const std::string&,
const std::string&,
const std::set<std::string>&,
const std::map<std::string, std::string>& > SignalResult;
protected:
virtual void HandleResult(const XmlElement* stanza);
};
} // namespace buzz
#endif // WEBRTC_LIBJINGLE_XMPP_MUCROOMDISCOVERYTASK_H_

View File

@ -1,145 +0,0 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <string>
#include <vector>
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/libjingle/xmpp/fakexmppclient.h"
#include "webrtc/libjingle/xmpp/mucroomdiscoverytask.h"
#include "webrtc/base/faketaskrunner.h"
#include "webrtc/base/gunit.h"
#include "webrtc/base/sigslot.h"
class MucRoomDiscoveryListener : public sigslot::has_slots<> {
public:
MucRoomDiscoveryListener() : error_count(0) {}
void OnResult(buzz::MucRoomDiscoveryTask* task,
bool exists,
const std::string& name,
const std::string& conversation_id,
const std::set<std::string>& features,
const std::map<std::string, std::string>& extended_info) {
last_exists = exists;
last_name = name;
last_conversation_id = conversation_id;
last_features = features;
last_extended_info = extended_info;
}
void OnError(buzz::IqTask* task,
const buzz::XmlElement* error) {
++error_count;
}
bool last_exists;
std::string last_name;
std::string last_conversation_id;
std::set<std::string> last_features;
std::map<std::string, std::string> last_extended_info;
int error_count;
};
class MucRoomDiscoveryTaskTest : public testing::Test {
public:
MucRoomDiscoveryTaskTest() :
room_jid("muc-jid-ponies@domain.com"),
room_name("ponies"),
conversation_id("test_conversation_id") {
}
virtual void SetUp() {
runner = new rtc::FakeTaskRunner();
xmpp_client = new buzz::FakeXmppClient(runner);
listener = new MucRoomDiscoveryListener();
}
virtual void TearDown() {
delete listener;
// delete xmpp_client; Deleted by deleting runner.
delete runner;
}
rtc::FakeTaskRunner* runner;
buzz::FakeXmppClient* xmpp_client;
MucRoomDiscoveryListener* listener;
buzz::Jid room_jid;
std::string room_name;
std::string conversation_id;
};
TEST_F(MucRoomDiscoveryTaskTest, TestDiscovery) {
ASSERT_EQ(0U, xmpp_client->sent_stanzas().size());
buzz::MucRoomDiscoveryTask* task = new buzz::MucRoomDiscoveryTask(
xmpp_client, room_jid);
task->SignalResult.connect(listener, &MucRoomDiscoveryListener::OnResult);
task->Start();
std::string expected_iq =
"<cli:iq type=\"get\" to=\"muc-jid-ponies@domain.com\" id=\"0\" "
"xmlns:cli=\"jabber:client\">"
"<info:query xmlns:info=\"http://jabber.org/protocol/disco#info\"/>"
"</cli:iq>";
ASSERT_EQ(1U, xmpp_client->sent_stanzas().size());
EXPECT_EQ(expected_iq, xmpp_client->sent_stanzas()[0]->Str());
EXPECT_EQ("", listener->last_name);
EXPECT_EQ("", listener->last_conversation_id);
std::string response_iq =
"<iq xmlns='jabber:client'"
" from='muc-jid-ponies@domain.com' id='0' type='result'>"
" <info:query xmlns:info='http://jabber.org/protocol/disco#info'>"
" <info:identity name='ponies'>"
" <han:conversation-id xmlns:han='google:muc#hangout'>"
"test_conversation_id</han:conversation-id>"
" </info:identity>"
" <info:feature var='feature1'/>"
" <info:feature var='feature2'/>"
" <data:x xmlns:data='jabber:x:data'>"
" <data:field var='var1' data:value='value1' />"
" <data:field var='var2' data:value='value2' />"
" </data:x>"
" </info:query>"
"</iq>";
xmpp_client->HandleStanza(buzz::XmlElement::ForStr(response_iq));
EXPECT_EQ(true, listener->last_exists);
EXPECT_EQ(room_name, listener->last_name);
EXPECT_EQ(conversation_id, listener->last_conversation_id);
EXPECT_EQ(2U, listener->last_features.size());
EXPECT_EQ(1U, listener->last_features.count("feature1"));
EXPECT_EQ(2U, listener->last_extended_info.size());
EXPECT_EQ("value1", listener->last_extended_info["var1"]);
EXPECT_EQ(0, listener->error_count);
}
TEST_F(MucRoomDiscoveryTaskTest, TestMissingName) {
buzz::MucRoomDiscoveryTask* task = new buzz::MucRoomDiscoveryTask(
xmpp_client, room_jid);
task->SignalError.connect(listener, &MucRoomDiscoveryListener::OnError);
task->Start();
std::string error_iq =
"<iq xmlns='jabber:client'"
" from='muc-jid-ponies@domain.com' id='0' type='result'>"
" <info:query xmlns:info='http://jabber.org/protocol/disco#info'>"
" <info:identity />"
" </info:query>"
"</iq>";
EXPECT_EQ(0, listener->error_count);
xmpp_client->HandleStanza(buzz::XmlElement::ForStr(error_iq));
EXPECT_EQ(0, listener->error_count);
}

View File

@ -1,158 +0,0 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/xmpp/mucroomlookuptask.h"
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/base/logging.h"
namespace buzz {
MucRoomLookupTask*
MucRoomLookupTask::CreateLookupTaskForRoomName(XmppTaskParentInterface* parent,
const Jid& lookup_server_jid,
const std::string& room_name,
const std::string& room_domain) {
return new MucRoomLookupTask(parent, lookup_server_jid,
MakeNameQuery(room_name, room_domain));
}
MucRoomLookupTask*
MucRoomLookupTask::CreateLookupTaskForRoomJid(XmppTaskParentInterface* parent,
const Jid& lookup_server_jid,
const Jid& room_jid) {
return new MucRoomLookupTask(parent, lookup_server_jid,
MakeJidQuery(room_jid));
}
MucRoomLookupTask*
MucRoomLookupTask::CreateLookupTaskForHangoutId(XmppTaskParentInterface* parent,
const Jid& lookup_server_jid,
const std::string& hangout_id) {
return new MucRoomLookupTask(parent, lookup_server_jid,
MakeHangoutIdQuery(hangout_id));
}
MucRoomLookupTask*
MucRoomLookupTask::CreateLookupTaskForExternalId(
XmppTaskParentInterface* parent,
const Jid& lookup_server_jid,
const std::string& external_id,
const std::string& type) {
return new MucRoomLookupTask(parent, lookup_server_jid,
MakeExternalIdQuery(external_id, type));
}
MucRoomLookupTask::MucRoomLookupTask(XmppTaskParentInterface* parent,
const Jid& lookup_server_jid,
XmlElement* query)
: IqTask(parent, STR_SET, lookup_server_jid, query) {
}
XmlElement* MucRoomLookupTask::MakeNameQuery(
const std::string& room_name, const std::string& room_domain) {
XmlElement* name_elem = new XmlElement(QN_SEARCH_ROOM_NAME, false);
name_elem->SetBodyText(room_name);
XmlElement* domain_elem = new XmlElement(QN_SEARCH_ROOM_DOMAIN, false);
domain_elem->SetBodyText(room_domain);
XmlElement* query = new XmlElement(QN_SEARCH_QUERY, true);
query->AddElement(name_elem);
query->AddElement(domain_elem);
return query;
}
XmlElement* MucRoomLookupTask::MakeJidQuery(const Jid& room_jid) {
XmlElement* jid_elem = new XmlElement(QN_SEARCH_ROOM_JID);
jid_elem->SetBodyText(room_jid.Str());
XmlElement* query = new XmlElement(QN_SEARCH_QUERY);
query->AddElement(jid_elem);
return query;
}
XmlElement* MucRoomLookupTask::MakeExternalIdQuery(
const std::string& external_id, const std::string& type) {
XmlElement* external_id_elem = new XmlElement(QN_SEARCH_EXTERNAL_ID);
external_id_elem->SetAttr(QN_TYPE, type);
external_id_elem->SetBodyText(external_id);
XmlElement* query = new XmlElement(QN_SEARCH_QUERY);
query->AddElement(external_id_elem);
return query;
}
// Construct a stanza to lookup the muc jid for a given hangout id. eg:
//
// <query xmlns="jabber:iq:search">
// <hangout-id>0b48ad092c893a53b7bfc87422caf38e93978798e</hangout-id>
// </query>
XmlElement* MucRoomLookupTask::MakeHangoutIdQuery(
const std::string& hangout_id) {
XmlElement* hangout_id_elem = new XmlElement(QN_SEARCH_HANGOUT_ID, false);
hangout_id_elem->SetBodyText(hangout_id);
XmlElement* query = new XmlElement(QN_SEARCH_QUERY, true);
query->AddElement(hangout_id_elem);
return query;
}
// Handle a response like the following:
//
// <query xmlns="jabber:iq:search">
// <item jid="muvc-private-chat-guid@groupchat.google.com">
// <room-name>0b48ad092c893a53b7bfc87422caf38e93978798e</room-name>
// <room-domain>hangout.google.com</room-domain>
// </item>
// </query>
void MucRoomLookupTask::HandleResult(const XmlElement* stanza) {
const XmlElement* query_elem = stanza->FirstNamed(QN_SEARCH_QUERY);
if (query_elem == NULL) {
SignalError(this, stanza);
return;
}
const XmlElement* item_elem = query_elem->FirstNamed(QN_SEARCH_ITEM);
if (item_elem == NULL) {
SignalError(this, stanza);
return;
}
MucRoomInfo room;
room.jid = Jid(item_elem->Attr(buzz::QN_JID));
if (!room.jid.IsValid()) {
SignalError(this, stanza);
return;
}
const XmlElement* room_name_elem =
item_elem->FirstNamed(QN_SEARCH_ROOM_NAME);
if (room_name_elem != NULL) {
room.name = room_name_elem->BodyText();
}
const XmlElement* room_domain_elem =
item_elem->FirstNamed(QN_SEARCH_ROOM_DOMAIN);
if (room_domain_elem != NULL) {
room.domain = room_domain_elem->BodyText();
}
const XmlElement* hangout_id_elem =
item_elem->FirstNamed(QN_SEARCH_HANGOUT_ID);
if (hangout_id_elem != NULL) {
room.hangout_id = hangout_id_elem->BodyText();
}
SignalResult(this, room);
}
} // namespace buzz

View File

@ -1,76 +0,0 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_MUCROOMLOOKUPTASK_H_
#define WEBRTC_LIBJINGLE_XMPP_MUCROOMLOOKUPTASK_H_
#include <string>
#include "webrtc/libjingle/xmpp/iqtask.h"
namespace buzz {
struct MucRoomInfo {
Jid jid;
std::string name;
std::string domain;
std::string hangout_id;
std::string full_name() const {
return name + "@" + domain;
}
};
class MucRoomLookupTask : public IqTask {
public:
enum IdType {
ID_TYPE_CONVERSATION,
ID_TYPE_HANGOUT
};
static MucRoomLookupTask*
CreateLookupTaskForRoomName(XmppTaskParentInterface* parent,
const Jid& lookup_server_jid,
const std::string& room_name,
const std::string& room_domain);
static MucRoomLookupTask*
CreateLookupTaskForRoomJid(XmppTaskParentInterface* parent,
const Jid& lookup_server_jid,
const Jid& room_jid);
static MucRoomLookupTask*
CreateLookupTaskForHangoutId(XmppTaskParentInterface* parent,
const Jid& lookup_server_jid,
const std::string& hangout_id);
static MucRoomLookupTask*
CreateLookupTaskForExternalId(XmppTaskParentInterface* parent,
const Jid& lookup_server_jid,
const std::string& external_id,
const std::string& type);
sigslot::signal2<MucRoomLookupTask*,
const MucRoomInfo&> SignalResult;
protected:
virtual void HandleResult(const XmlElement* element);
private:
MucRoomLookupTask(XmppTaskParentInterface* parent,
const Jid& lookup_server_jid,
XmlElement* query);
static XmlElement* MakeNameQuery(const std::string& room_name,
const std::string& room_domain);
static XmlElement* MakeJidQuery(const Jid& room_jid);
static XmlElement* MakeHangoutIdQuery(const std::string& hangout_id);
static XmlElement* MakeExternalIdQuery(const std::string& external_id,
const std::string& type);
};
} // namespace buzz
#endif // WEBRTC_LIBJINGLE_XMPP_MUCROOMLOOKUPTASK_H_

View File

@ -1,187 +0,0 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <string>
#include <vector>
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/libjingle/xmpp/fakexmppclient.h"
#include "webrtc/libjingle/xmpp/mucroomlookuptask.h"
#include "webrtc/base/faketaskrunner.h"
#include "webrtc/base/gunit.h"
#include "webrtc/base/sigslot.h"
class MucRoomLookupListener : public sigslot::has_slots<> {
public:
MucRoomLookupListener() : error_count(0) {}
void OnResult(buzz::MucRoomLookupTask* task,
const buzz::MucRoomInfo& room) {
last_room = room;
}
void OnError(buzz::IqTask* task,
const buzz::XmlElement* error) {
++error_count;
}
buzz::MucRoomInfo last_room;
int error_count;
};
class MucRoomLookupTaskTest : public testing::Test {
public:
MucRoomLookupTaskTest() :
lookup_server_jid("lookup@domain.com"),
room_jid("muc-jid-ponies@domain.com"),
room_name("ponies"),
room_domain("domain.com"),
room_full_name("ponies@domain.com"),
hangout_id("some_hangout_id") {
}
virtual void SetUp() {
runner = new rtc::FakeTaskRunner();
xmpp_client = new buzz::FakeXmppClient(runner);
listener = new MucRoomLookupListener();
}
virtual void TearDown() {
delete listener;
// delete xmpp_client; Deleted by deleting runner.
delete runner;
}
rtc::FakeTaskRunner* runner;
buzz::FakeXmppClient* xmpp_client;
MucRoomLookupListener* listener;
buzz::Jid lookup_server_jid;
buzz::Jid room_jid;
std::string room_name;
std::string room_domain;
std::string room_full_name;
std::string hangout_id;
};
TEST_F(MucRoomLookupTaskTest, TestLookupName) {
ASSERT_EQ(0U, xmpp_client->sent_stanzas().size());
buzz::MucRoomLookupTask* task =
buzz::MucRoomLookupTask::CreateLookupTaskForRoomName(
xmpp_client, lookup_server_jid, room_name, room_domain);
task->SignalResult.connect(listener, &MucRoomLookupListener::OnResult);
task->Start();
std::string expected_iq =
"<cli:iq type=\"set\" to=\"lookup@domain.com\" id=\"0\" "
"xmlns:cli=\"jabber:client\">"
"<query xmlns=\"jabber:iq:search\">"
"<room-name>ponies</room-name>"
"<room-domain>domain.com</room-domain>"
"</query>"
"</cli:iq>";
ASSERT_EQ(1U, xmpp_client->sent_stanzas().size());
EXPECT_EQ(expected_iq, xmpp_client->sent_stanzas()[0]->Str());
EXPECT_EQ("", listener->last_room.name);
std::string response_iq =
"<iq xmlns='jabber:client' from='lookup@domain.com' id='0' type='result'>"
" <query xmlns='jabber:iq:search'>"
" <item jid='muc-jid-ponies@domain.com'>"
" <room-name>ponies</room-name>"
" <room-domain>domain.com</room-domain>"
" </item>"
" </query>"
"</iq>";
xmpp_client->HandleStanza(buzz::XmlElement::ForStr(response_iq));
EXPECT_EQ(room_name, listener->last_room.name);
EXPECT_EQ(room_domain, listener->last_room.domain);
EXPECT_EQ(room_jid, listener->last_room.jid);
EXPECT_EQ(room_full_name, listener->last_room.full_name());
EXPECT_EQ(0, listener->error_count);
}
TEST_F(MucRoomLookupTaskTest, TestLookupHangoutId) {
ASSERT_EQ(0U, xmpp_client->sent_stanzas().size());
buzz::MucRoomLookupTask* task = buzz::MucRoomLookupTask::CreateLookupTaskForHangoutId(
xmpp_client, lookup_server_jid, hangout_id);
task->SignalResult.connect(listener, &MucRoomLookupListener::OnResult);
task->Start();
std::string expected_iq =
"<cli:iq type=\"set\" to=\"lookup@domain.com\" id=\"0\" "
"xmlns:cli=\"jabber:client\">"
"<query xmlns=\"jabber:iq:search\">"
"<hangout-id>some_hangout_id</hangout-id>"
"</query>"
"</cli:iq>";
ASSERT_EQ(1U, xmpp_client->sent_stanzas().size());
EXPECT_EQ(expected_iq, xmpp_client->sent_stanzas()[0]->Str());
EXPECT_EQ("", listener->last_room.name);
std::string response_iq =
"<iq xmlns='jabber:client' from='lookup@domain.com' id='0' type='result'>"
" <query xmlns='jabber:iq:search'>"
" <item jid='muc-jid-ponies@domain.com'>"
" <room-name>some_hangout_id</room-name>"
" <room-domain>domain.com</room-domain>"
" </item>"
" </query>"
"</iq>";
xmpp_client->HandleStanza(buzz::XmlElement::ForStr(response_iq));
EXPECT_EQ(hangout_id, listener->last_room.name);
EXPECT_EQ(room_domain, listener->last_room.domain);
EXPECT_EQ(room_jid, listener->last_room.jid);
EXPECT_EQ(0, listener->error_count);
}
TEST_F(MucRoomLookupTaskTest, TestError) {
buzz::MucRoomLookupTask* task = buzz::MucRoomLookupTask::CreateLookupTaskForRoomName(
xmpp_client, lookup_server_jid, room_name, room_domain);
task->SignalError.connect(listener, &MucRoomLookupListener::OnError);
task->Start();
std::string error_iq =
"<iq xmlns='jabber:client' id='0' type='error'"
" from='lookup@domain.com'>"
"</iq>";
EXPECT_EQ(0, listener->error_count);
xmpp_client->HandleStanza(buzz::XmlElement::ForStr(error_iq));
EXPECT_EQ(1, listener->error_count);
}
TEST_F(MucRoomLookupTaskTest, TestBadJid) {
buzz::MucRoomLookupTask* task = buzz::MucRoomLookupTask::CreateLookupTaskForRoomName(
xmpp_client, lookup_server_jid, room_name, room_domain);
task->SignalError.connect(listener, &MucRoomLookupListener::OnError);
task->Start();
std::string response_iq =
"<iq xmlns='jabber:client' from='lookup@domain.com' id='0' type='result'>"
" <query xmlns='jabber:iq:search'>"
" <item/>"
" </query>"
"</iq>";
EXPECT_EQ(0, listener->error_count);
xmpp_client->HandleStanza(buzz::XmlElement::ForStr(response_iq));
EXPECT_EQ(1, listener->error_count);
}

View File

@ -1,51 +0,0 @@
/*
* Copyright 2012 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/xmpp/mucroomuniquehangoutidtask.h"
#include "webrtc/libjingle/xmpp/constants.h"
namespace buzz {
MucRoomUniqueHangoutIdTask::MucRoomUniqueHangoutIdTask(XmppTaskParentInterface* parent,
const Jid& lookup_server_jid)
: IqTask(parent, STR_GET, lookup_server_jid, MakeUniqueRequestXml()) {
}
// Construct a stanza to request a unique room id. eg:
//
// <unique hangout-id="true" xmlns="http://jabber.org/protocol/muc#unique"/>
XmlElement* MucRoomUniqueHangoutIdTask::MakeUniqueRequestXml() {
XmlElement* xml = new XmlElement(QN_MUC_UNIQUE_QUERY, false);
xml->SetAttr(QN_HANGOUT_ID, STR_TRUE);
return xml;
}
// Handle a response like the following:
//
// <unique hangout-id="hangout_id"
// xmlns="http://jabber.org/protocol/muc#unique"/>
// muvc-private-chat-guid@groupchat.google.com
// </unique>
void MucRoomUniqueHangoutIdTask::HandleResult(const XmlElement* stanza) {
const XmlElement* unique_elem = stanza->FirstNamed(QN_MUC_UNIQUE_QUERY);
if (unique_elem == NULL ||
!unique_elem->HasAttr(QN_HANGOUT_ID)) {
SignalError(this, stanza);
return;
}
std::string hangout_id = unique_elem->Attr(QN_HANGOUT_ID);
SignalResult(this, hangout_id);
}
} // namespace buzz

View File

@ -1,38 +0,0 @@
/*
* Copyright 2012 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_MUCROOMUNIQUEHANGOUTIDTASK_H_
#define WEBRTC_LIBJINGLE_XMPP_MUCROOMUNIQUEHANGOUTIDTASK_H_
#include "webrtc/libjingle/xmpp/iqtask.h"
namespace buzz {
// Task to request a unique hangout id to be used when starting a hangout.
// The protocol is described in https://docs.google.com/a/google.com/
// document/d/1EFLT6rCYPDVdqQXSQliXwqB3iUkpZJ9B_MNFeOZgN7g/edit
class MucRoomUniqueHangoutIdTask : public buzz::IqTask {
public:
MucRoomUniqueHangoutIdTask(buzz::XmppTaskParentInterface* parent,
const Jid& lookup_server_jid);
// signal(task, hangout_id)
sigslot::signal2<MucRoomUniqueHangoutIdTask*, const std::string&> SignalResult;
protected:
virtual void HandleResult(const buzz::XmlElement* stanza);
private:
static buzz::XmlElement* MakeUniqueRequestXml();
};
} // namespace buzz
#endif // WEBRTC_LIBJINGLE_XMPP_MUCROOMUNIQUEHANGOUTIDTASK_H_

View File

@ -1,99 +0,0 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <string>
#include <vector>
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/libjingle/xmpp/fakexmppclient.h"
#include "webrtc/libjingle/xmpp/mucroomuniquehangoutidtask.h"
#include "webrtc/base/faketaskrunner.h"
#include "webrtc/base/gunit.h"
#include "webrtc/base/sigslot.h"
class MucRoomUniqueHangoutIdListener : public sigslot::has_slots<> {
public:
MucRoomUniqueHangoutIdListener() : error_count(0) {}
void OnResult(buzz::MucRoomUniqueHangoutIdTask* task,
const std::string& hangout_id) {
last_hangout_id = hangout_id;
}
void OnError(buzz::IqTask* task,
const buzz::XmlElement* error) {
++error_count;
}
std::string last_hangout_id;
int error_count;
};
class MucRoomUniqueHangoutIdTaskTest : public testing::Test {
public:
MucRoomUniqueHangoutIdTaskTest() :
lookup_server_jid("lookup@domain.com"),
hangout_id("some_hangout_id") {
}
virtual void SetUp() {
runner = new rtc::FakeTaskRunner();
xmpp_client = new buzz::FakeXmppClient(runner);
listener = new MucRoomUniqueHangoutIdListener();
}
virtual void TearDown() {
delete listener;
// delete xmpp_client; Deleted by deleting runner.
delete runner;
}
rtc::FakeTaskRunner* runner;
buzz::FakeXmppClient* xmpp_client;
MucRoomUniqueHangoutIdListener* listener;
buzz::Jid lookup_server_jid;
std::string hangout_id;
};
TEST_F(MucRoomUniqueHangoutIdTaskTest, Test) {
ASSERT_EQ(0U, xmpp_client->sent_stanzas().size());
buzz::MucRoomUniqueHangoutIdTask* task = new buzz::MucRoomUniqueHangoutIdTask(
xmpp_client, lookup_server_jid);
task->SignalResult.connect(listener, &MucRoomUniqueHangoutIdListener::OnResult);
task->Start();
std::string expected_iq =
"<cli:iq type=\"get\" to=\"lookup@domain.com\" id=\"0\" "
"xmlns:cli=\"jabber:client\">"
"<uni:unique hangout-id=\"true\" "
"xmlns:uni=\"http://jabber.org/protocol/muc#unique\"/>"
"</cli:iq>";
ASSERT_EQ(1U, xmpp_client->sent_stanzas().size());
EXPECT_EQ(expected_iq, xmpp_client->sent_stanzas()[0]->Str());
EXPECT_EQ("", listener->last_hangout_id);
std::string response_iq =
"<iq xmlns='jabber:client' from='lookup@domain.com' id='0' type='result'>"
"<unique hangout-id=\"some_hangout_id\" "
"xmlns=\"http://jabber.org/protocol/muc#unique\">"
"muvc-private-chat-00001234-5678-9abc-def0-123456789abc"
"</unique>"
"</iq>";
xmpp_client->HandleStanza(buzz::XmlElement::ForStr(response_iq));
EXPECT_EQ(hangout_id, listener->last_hangout_id);
EXPECT_EQ(0, listener->error_count);
}

View File

@ -1,93 +0,0 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/xmpp/pingtask.h"
#include <memory>
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/base/logging.h"
namespace buzz {
PingTask::PingTask(buzz::XmppTaskParentInterface* parent,
rtc::MessageQueue* message_queue,
uint32_t ping_period_millis,
uint32_t ping_timeout_millis)
: buzz::XmppTask(parent, buzz::XmppEngine::HL_SINGLE),
message_queue_(message_queue),
ping_period_millis_(ping_period_millis),
ping_timeout_millis_(ping_timeout_millis),
next_ping_time_(0),
ping_response_deadline_(0) {
ASSERT(ping_period_millis >= ping_timeout_millis);
}
bool PingTask::HandleStanza(const buzz::XmlElement* stanza) {
if (!MatchResponseIq(stanza, Jid(STR_EMPTY), task_id())) {
return false;
}
if (stanza->Attr(buzz::QN_TYPE) != buzz::STR_RESULT &&
stanza->Attr(buzz::QN_TYPE) != buzz::STR_ERROR) {
return false;
}
QueueStanza(stanza);
return true;
}
// This task runs indefinitely and remains in either the start or blocked
// states.
int PingTask::ProcessStart() {
if (ping_period_millis_ < ping_timeout_millis_) {
LOG(LS_ERROR) << "ping_period_millis should be >= ping_timeout_millis";
return STATE_ERROR;
}
const buzz::XmlElement* stanza = NextStanza();
if (stanza != NULL) {
// Received a ping response of some sort (don't care what it is).
ping_response_deadline_ = 0;
}
int64_t now = rtc::TimeMillis();
// If the ping timed out, signal.
if (ping_response_deadline_ != 0 && now >= ping_response_deadline_) {
SignalTimeout();
return STATE_ERROR;
}
// Send a ping if it's time.
if (now >= next_ping_time_) {
std::unique_ptr<buzz::XmlElement> stanza(
MakeIq(buzz::STR_GET, Jid(STR_EMPTY), task_id()));
stanza->AddElement(new buzz::XmlElement(QN_PING));
SendStanza(stanza.get());
ping_response_deadline_ = now + ping_timeout_millis_;
next_ping_time_ = now + ping_period_millis_;
// Wake ourselves up when it's time to send another ping or when the ping
// times out (so we can fire a signal).
message_queue_->PostDelayed(RTC_FROM_HERE, ping_timeout_millis_, this);
message_queue_->PostDelayed(RTC_FROM_HERE, ping_period_millis_, this);
}
return STATE_BLOCKED;
}
void PingTask::OnMessage(rtc::Message* msg) {
// Get the task manager to run this task so we can send a ping or signal or
// process a ping response.
Wake();
}
} // namespace buzz

View File

@ -1,55 +0,0 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_PINGTASK_H_
#define WEBRTC_LIBJINGLE_XMPP_PINGTASK_H_
#include "webrtc/libjingle/xmpp/xmpptask.h"
#include "webrtc/base/messagehandler.h"
#include "webrtc/base/messagequeue.h"
namespace buzz {
// Task to periodically send pings to the server to ensure that the network
// connection is valid, implementing XEP-0199.
//
// This is especially useful on cellular networks because:
// 1. It keeps the connections alive through the cellular network's NATs or
// proxies.
// 2. It detects when the server has crashed or any other case in which the
// connection has broken without a fin or reset packet being sent to us.
class PingTask : public buzz::XmppTask, private rtc::MessageHandler {
public:
PingTask(buzz::XmppTaskParentInterface* parent,
rtc::MessageQueue* message_queue,
uint32_t ping_period_millis,
uint32_t ping_timeout_millis);
virtual bool HandleStanza(const buzz::XmlElement* stanza);
virtual int ProcessStart();
// Raised if there is no response to a ping within ping_timeout_millis.
// The task is automatically aborted after a timeout.
sigslot::signal0<> SignalTimeout;
private:
// Implementation of MessageHandler.
virtual void OnMessage(rtc::Message* msg);
rtc::MessageQueue* message_queue_;
uint32_t ping_period_millis_;
uint32_t ping_timeout_millis_;
int64_t next_ping_time_;
int64_t ping_response_deadline_; // 0 if the response has been received
};
} // namespace buzz
#endif // WEBRTC_LIBJINGLE_XMPP_PINGTASK_H_

View File

@ -1,101 +0,0 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <string>
#include <vector>
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/libjingle/xmpp/fakexmppclient.h"
#include "webrtc/libjingle/xmpp/pingtask.h"
#include "webrtc/base/faketaskrunner.h"
#include "webrtc/base/gunit.h"
#include "webrtc/base/sigslot.h"
class PingTaskTest;
class PingXmppClient : public buzz::FakeXmppClient {
public:
PingXmppClient(rtc::TaskParent* parent, PingTaskTest* tst) :
FakeXmppClient(parent), test(tst) {
}
buzz::XmppReturnStatus SendStanza(const buzz::XmlElement* stanza);
private:
PingTaskTest* test;
};
class PingTaskTest : public testing::Test, public sigslot::has_slots<> {
public:
PingTaskTest() : respond_to_pings(true), timed_out(false) {
}
virtual void SetUp() {
runner = new rtc::FakeTaskRunner();
xmpp_client = new PingXmppClient(runner, this);
}
virtual void TearDown() {
// delete xmpp_client; Deleted by deleting runner.
delete runner;
}
void ConnectTimeoutSignal(buzz::PingTask* task) {
task->SignalTimeout.connect(this, &PingTaskTest::OnPingTimeout);
}
void OnPingTimeout() {
timed_out = true;
}
rtc::FakeTaskRunner* runner;
PingXmppClient* xmpp_client;
bool respond_to_pings;
bool timed_out;
};
buzz::XmppReturnStatus PingXmppClient::SendStanza(
const buzz::XmlElement* stanza) {
buzz::XmppReturnStatus result = FakeXmppClient::SendStanza(stanza);
if (test->respond_to_pings && (stanza->FirstNamed(buzz::QN_PING) != NULL)) {
std::string ping_response =
"<iq xmlns=\'jabber:client\' id='0' type='result'/>";
HandleStanza(buzz::XmlElement::ForStr(ping_response));
}
return result;
}
TEST_F(PingTaskTest, TestSuccess) {
uint32_t ping_period_millis = 100;
buzz::PingTask* task = new buzz::PingTask(xmpp_client,
rtc::Thread::Current(),
ping_period_millis, ping_period_millis / 10);
ConnectTimeoutSignal(task);
task->Start();
unsigned int expected_ping_count = 5U;
EXPECT_EQ_WAIT(xmpp_client->sent_stanzas().size(), expected_ping_count,
ping_period_millis * (expected_ping_count + 1));
EXPECT_FALSE(task->IsDone());
EXPECT_FALSE(timed_out);
}
TEST_F(PingTaskTest, TestTimeout) {
respond_to_pings = false;
uint32_t ping_timeout_millis = 200;
buzz::PingTask* task = new buzz::PingTask(xmpp_client,
rtc::Thread::Current(),
ping_timeout_millis * 10, ping_timeout_millis);
ConnectTimeoutSignal(task);
task->Start();
WAIT(false, ping_timeout_millis / 2);
EXPECT_FALSE(timed_out);
EXPECT_TRUE_WAIT(timed_out, ping_timeout_millis * 2);
}

View File

@ -1,64 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_PLAINSASLHANDLER_H_
#define WEBRTC_LIBJINGLE_XMPP_PLAINSASLHANDLER_H_
#include <algorithm>
#include "webrtc/libjingle/xmpp/saslhandler.h"
#include "webrtc/libjingle/xmpp/saslplainmechanism.h"
#include "webrtc/base/cryptstring.h"
namespace buzz {
class PlainSaslHandler : public SaslHandler {
public:
PlainSaslHandler(const Jid & jid, const rtc::CryptString & password,
bool allow_plain) : jid_(jid), password_(password),
allow_plain_(allow_plain) {}
virtual ~PlainSaslHandler() {}
// Should pick the best method according to this handler
// returns the empty string if none are suitable
virtual std::string ChooseBestSaslMechanism(const std::vector<std::string> & mechanisms, bool encrypted) {
if (!encrypted && !allow_plain_) {
return "";
}
std::vector<std::string>::const_iterator it = std::find(mechanisms.begin(), mechanisms.end(), "PLAIN");
if (it == mechanisms.end()) {
return "";
}
else {
return "PLAIN";
}
}
// Creates a SaslMechanism for the given mechanism name (you own it
// once you get it). If not handled, return NULL.
virtual SaslMechanism * CreateSaslMechanism(const std::string & mechanism) {
if (mechanism == "PLAIN") {
return new SaslPlainMechanism(jid_, password_);
}
return NULL;
}
private:
Jid jid_;
rtc::CryptString password_;
bool allow_plain_;
};
}
#endif // WEBRTC_LIBJINGLE_XMPP_PLAINSASLHANDLER_H_

View File

@ -1,141 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <time.h>
#include <sstream>
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/libjingle/xmpp/presenceouttask.h"
#include "webrtc/libjingle/xmpp/xmppclient.h"
#include "webrtc/base/arraysize.h"
#include "webrtc/base/stringencode.h"
namespace buzz {
XmppReturnStatus
PresenceOutTask::Send(const PresenceStatus & s) {
if (GetState() != STATE_INIT && GetState() != STATE_START)
return XMPP_RETURN_BADSTATE;
XmlElement * presence = TranslateStatus(s);
QueueStanza(presence);
delete presence;
return XMPP_RETURN_OK;
}
XmppReturnStatus
PresenceOutTask::SendDirected(const Jid & j, const PresenceStatus & s) {
if (GetState() != STATE_INIT && GetState() != STATE_START)
return XMPP_RETURN_BADSTATE;
XmlElement * presence = TranslateStatus(s);
presence->AddAttr(QN_TO, j.Str());
QueueStanza(presence);
delete presence;
return XMPP_RETURN_OK;
}
XmppReturnStatus PresenceOutTask::SendProbe(const Jid & jid) {
if (GetState() != STATE_INIT && GetState() != STATE_START)
return XMPP_RETURN_BADSTATE;
XmlElement * presence = new XmlElement(QN_PRESENCE);
presence->AddAttr(QN_TO, jid.Str());
presence->AddAttr(QN_TYPE, "probe");
QueueStanza(presence);
delete presence;
return XMPP_RETURN_OK;
}
int
PresenceOutTask::ProcessStart() {
const XmlElement * stanza = NextStanza();
if (stanza == NULL)
return STATE_BLOCKED;
if (SendStanza(stanza) != XMPP_RETURN_OK)
return STATE_ERROR;
return STATE_START;
}
XmlElement *
PresenceOutTask::TranslateStatus(const PresenceStatus & s) {
XmlElement * result = new XmlElement(QN_PRESENCE);
if (!s.available()) {
result->AddAttr(QN_TYPE, STR_UNAVAILABLE);
}
else {
if (s.show() != PresenceStatus::SHOW_ONLINE &&
s.show() != PresenceStatus::SHOW_OFFLINE) {
result->AddElement(new XmlElement(QN_SHOW));
switch (s.show()) {
default:
result->AddText(STR_SHOW_AWAY, 1);
break;
case PresenceStatus::SHOW_XA:
result->AddText(STR_SHOW_XA, 1);
break;
case PresenceStatus::SHOW_DND:
result->AddText(STR_SHOW_DND, 1);
break;
case PresenceStatus::SHOW_CHAT:
result->AddText(STR_SHOW_CHAT, 1);
break;
}
}
result->AddElement(new XmlElement(QN_STATUS));
result->AddText(s.status(), 1);
if (!s.nick().empty()) {
result->AddElement(new XmlElement(QN_NICKNAME));
result->AddText(s.nick(), 1);
}
std::string pri;
rtc::ToString(s.priority(), &pri);
result->AddElement(new XmlElement(QN_PRIORITY));
result->AddText(pri, 1);
if (s.know_capabilities()) {
result->AddElement(new XmlElement(QN_CAPS_C, true));
result->AddAttr(QN_NODE, s.caps_node(), 1);
result->AddAttr(QN_VER, s.version(), 1);
std::string caps;
caps.append(s.voice_capability() ? "voice-v1" : "");
caps.append(s.pmuc_capability() ? " pmuc-v1" : "");
caps.append(s.video_capability() ? " video-v1" : "");
caps.append(s.camera_capability() ? " camera-v1" : "");
result->AddAttr(QN_EXT, caps, 1);
}
// Put the delay mark on the presence according to JEP-0091
{
result->AddElement(new XmlElement(kQnDelayX, true));
// This here is why we *love* the C runtime
time_t current_time_seconds;
time(&current_time_seconds);
struct tm* current_time = gmtime(&current_time_seconds);
char output[256];
strftime(output, arraysize(output), "%Y%m%dT%H:%M:%S", current_time);
result->AddAttr(kQnStamp, output, 1);
}
}
return result;
}
}

View File

@ -1,37 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_PRESENCEOUTTASK_H_
#define WEBRTC_LIBJINGLE_XMPP_PRESENCEOUTTASK_H_
#include "webrtc/libjingle/xmpp/presencestatus.h"
#include "webrtc/libjingle/xmpp/xmppengine.h"
#include "webrtc/libjingle/xmpp/xmpptask.h"
namespace buzz {
class PresenceOutTask : public XmppTask {
public:
explicit PresenceOutTask(XmppTaskParentInterface* parent)
: XmppTask(parent) {}
virtual ~PresenceOutTask() {}
XmppReturnStatus Send(const PresenceStatus & s);
XmppReturnStatus SendDirected(const Jid & j, const PresenceStatus & s);
XmppReturnStatus SendProbe(const Jid& jid);
virtual int ProcessStart();
private:
XmlElement * TranslateStatus(const PresenceStatus & s);
};
}
#endif // WEBRTC_LIBJINGLE_XMPP_PRESENCEOUTTASK_H_

View File

@ -1,141 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/xmpp/presencereceivetask.h"
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/base/stringencode.h"
namespace buzz {
static bool IsUtf8FirstByte(int c) {
return (((c)&0x80)==0) || // is single byte
((unsigned char)((c)-0xc0)<0x3e); // or is lead byte
}
PresenceReceiveTask::PresenceReceiveTask(XmppTaskParentInterface* parent)
: XmppTask(parent, XmppEngine::HL_TYPE) {
}
PresenceReceiveTask::~PresenceReceiveTask() {
Stop();
}
int PresenceReceiveTask::ProcessStart() {
const XmlElement * stanza = NextStanza();
if (stanza == NULL) {
return STATE_BLOCKED;
}
Jid from(stanza->Attr(QN_FROM));
HandlePresence(from, stanza);
return STATE_START;
}
bool PresenceReceiveTask::HandleStanza(const XmlElement * stanza) {
// Verify that this is a presence stanze
if (stanza->Name() != QN_PRESENCE) {
return false; // not sure if this ever happens.
}
// Queue it up
QueueStanza(stanza);
return true;
}
void PresenceReceiveTask::HandlePresence(const Jid& from,
const XmlElement* stanza) {
if (stanza->Attr(QN_TYPE) == STR_ERROR) {
return;
}
PresenceStatus status;
DecodeStatus(from, stanza, &status);
PresenceUpdate(status);
}
void PresenceReceiveTask::DecodeStatus(const Jid& from,
const XmlElement* stanza,
PresenceStatus* presence_status) {
presence_status->set_jid(from);
if (stanza->Attr(QN_TYPE) == STR_UNAVAILABLE) {
presence_status->set_available(false);
} else {
presence_status->set_available(true);
const XmlElement * status_elem = stanza->FirstNamed(QN_STATUS);
if (status_elem != NULL) {
presence_status->set_status(status_elem->BodyText());
// Truncate status messages longer than 300 bytes
if (presence_status->status().length() > 300) {
size_t len = 300;
// Be careful not to split legal utf-8 chars in half
while (!IsUtf8FirstByte(presence_status->status()[len]) && len > 0) {
len -= 1;
}
std::string truncated(presence_status->status(), 0, len);
presence_status->set_status(truncated);
}
}
const XmlElement * priority = stanza->FirstNamed(QN_PRIORITY);
if (priority != NULL) {
int pri;
if (rtc::FromString(priority->BodyText(), &pri)) {
presence_status->set_priority(pri);
}
}
const XmlElement * show = stanza->FirstNamed(QN_SHOW);
if (show == NULL || show->FirstChild() == NULL) {
presence_status->set_show(PresenceStatus::SHOW_ONLINE);
} else if (show->BodyText() == "away") {
presence_status->set_show(PresenceStatus::SHOW_AWAY);
} else if (show->BodyText() == "xa") {
presence_status->set_show(PresenceStatus::SHOW_XA);
} else if (show->BodyText() == "dnd") {
presence_status->set_show(PresenceStatus::SHOW_DND);
} else if (show->BodyText() == "chat") {
presence_status->set_show(PresenceStatus::SHOW_CHAT);
} else {
presence_status->set_show(PresenceStatus::SHOW_ONLINE);
}
const XmlElement * caps = stanza->FirstNamed(QN_CAPS_C);
if (caps != NULL) {
std::string node = caps->Attr(QN_NODE);
std::string ver = caps->Attr(QN_VER);
std::string exts = caps->Attr(QN_EXT);
presence_status->set_know_capabilities(true);
presence_status->set_caps_node(node);
presence_status->set_version(ver);
}
const XmlElement* delay = stanza->FirstNamed(kQnDelayX);
if (delay != NULL) {
// Ideally we would parse this according to the Psuedo ISO-8601 rules
// that are laid out in JEP-0082:
// http://www.jabber.org/jeps/jep-0082.html
std::string stamp = delay->Attr(kQnStamp);
presence_status->set_sent_time(stamp);
}
const XmlElement* nick = stanza->FirstNamed(QN_NICKNAME);
if (nick) {
presence_status->set_nick(nick->BodyText());
}
}
}
} // namespace buzz

View File

@ -1,56 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef THIRD_PARTY_LIBJINGLE_FILES_WEBRTC_LIBJINGLE_XMPP_PRESENCERECEIVETASK_H_
#define THIRD_PARTY_LIBJINGLE_FILES_WEBRTC_LIBJINGLE_XMPP_PRESENCERECEIVETASK_H_
#include "webrtc/base/sigslot.h"
#include "webrtc/libjingle/xmpp/presencestatus.h"
#include "webrtc/libjingle/xmpp/xmpptask.h"
namespace buzz {
// A task to receive presence status callbacks from the XMPP server.
class PresenceReceiveTask : public XmppTask {
public:
// Arguments:
// parent a reference to task interface associated withe the XMPP client.
explicit PresenceReceiveTask(XmppTaskParentInterface* parent);
// Shuts down the thread associated with this task.
virtual ~PresenceReceiveTask();
// Starts pulling queued status messages and dispatching them to the
// PresenceUpdate() callback.
virtual int ProcessStart();
// Slot for presence message callbacks
sigslot::signal1<const PresenceStatus&> PresenceUpdate;
protected:
// Called by the XMPP engine when presence stanzas are received from the
// server.
virtual bool HandleStanza(const XmlElement * stanza);
private:
// Handles presence stanzas by converting the data to PresenceStatus
// objects and passing those along to the SignalStatusUpadate() callback.
void HandlePresence(const Jid& from, const XmlElement * stanza);
// Extracts presence information for the presence stanza sent form the
// server.
static void DecodeStatus(const Jid& from, const XmlElement * stanza,
PresenceStatus* status);
};
} // namespace buzz
#endif // THIRD_PARTY_LIBJINGLE_FILES_WEBRTC_LIBJINGLE_XMPP_PRESENCERECEIVETASK_H_

View File

@ -1,45 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/xmpp/presencestatus.h"
namespace buzz {
PresenceStatus::PresenceStatus()
: pri_(0),
show_(SHOW_NONE),
available_(false),
e_code_(0),
feedback_probation_(false),
know_capabilities_(false),
voice_capability_(false),
pmuc_capability_(false),
video_capability_(false),
camera_capability_(false) {
}
void PresenceStatus::UpdateWith(const PresenceStatus& new_value) {
if (!new_value.know_capabilities()) {
bool k = know_capabilities();
bool p = voice_capability();
std::string node = caps_node();
std::string v = version();
*this = new_value;
set_know_capabilities(k);
set_caps_node(node);
set_voice_capability(p);
set_version(v);
} else {
*this = new_value;
}
}
} // namespace buzz

View File

@ -1,188 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef THIRD_PARTY_LIBJINGLE_FILES_WEBRTC_LIBJINGLE_XMPP_PRESENCESTATUS_H_
#define THIRD_PARTY_LIBJINGLE_FILES_WEBRTC_LIBJINGLE_XMPP_PRESENCESTATUS_H_
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/libjingle/xmpp/jid.h"
namespace buzz {
class PresenceStatus {
public:
PresenceStatus();
~PresenceStatus() {}
// These are arranged in "priority order", i.e., if we see
// two statuses at the same priority but with different Shows,
// we will show the one with the highest show in the following
// order.
enum Show {
SHOW_NONE = 0,
SHOW_OFFLINE = 1,
SHOW_XA = 2,
SHOW_AWAY = 3,
SHOW_DND = 4,
SHOW_ONLINE = 5,
SHOW_CHAT = 6,
};
const Jid& jid() const { return jid_; }
int priority() const { return pri_; }
Show show() const { return show_; }
const std::string& status() const { return status_; }
const std::string& nick() const { return nick_; }
bool available() const { return available_ ; }
int error_code() const { return e_code_; }
const std::string& error_string() const { return e_str_; }
bool know_capabilities() const { return know_capabilities_; }
bool voice_capability() const { return voice_capability_; }
bool pmuc_capability() const { return pmuc_capability_; }
bool video_capability() const { return video_capability_; }
bool camera_capability() const { return camera_capability_; }
const std::string& caps_node() const { return caps_node_; }
const std::string& version() const { return version_; }
bool feedback_probation() const { return feedback_probation_; }
const std::string& sent_time() const { return sent_time_; }
void set_jid(const Jid& jid) { jid_ = jid; }
void set_priority(int pri) { pri_ = pri; }
void set_show(Show show) { show_ = show; }
void set_status(const std::string& status) { status_ = status; }
void set_nick(const std::string& nick) { nick_ = nick; }
void set_available(bool a) { available_ = a; }
void set_error(int e_code, const std::string e_str)
{ e_code_ = e_code; e_str_ = e_str; }
void set_know_capabilities(bool f) { know_capabilities_ = f; }
void set_voice_capability(bool f) { voice_capability_ = f; }
void set_pmuc_capability(bool f) { pmuc_capability_ = f; }
void set_video_capability(bool f) { video_capability_ = f; }
void set_camera_capability(bool f) { camera_capability_ = f; }
void set_caps_node(const std::string& f) { caps_node_ = f; }
void set_version(const std::string& v) { version_ = v; }
void set_feedback_probation(bool f) { feedback_probation_ = f; }
void set_sent_time(const std::string& time) { sent_time_ = time; }
void UpdateWith(const PresenceStatus& new_value);
bool HasQuietStatus() const {
if (status_.empty())
return false;
return !(QuietStatus().empty());
}
// Knowledge of other clients' silly automatic status strings -
// Don't show these.
std::string QuietStatus() const {
if (jid_.resource().find("Psi") != std::string::npos) {
if (status_ == "Online" ||
status_.find("Auto Status") != std::string::npos)
return STR_EMPTY;
}
if (jid_.resource().find("Gaim") != std::string::npos) {
if (status_ == "Sorry, I ran out for a bit!")
return STR_EMPTY;
}
return TrimStatus(status_);
}
std::string ExplicitStatus() const {
std::string result = QuietStatus();
if (result.empty()) {
result = ShowStatus();
}
return result;
}
std::string ShowStatus() const {
std::string result;
if (!available()) {
result = "Offline";
}
else {
switch (show()) {
case SHOW_AWAY:
case SHOW_XA:
result = "Idle";
break;
case SHOW_DND:
result = "Busy";
break;
case SHOW_CHAT:
result = "Chatty";
break;
default:
result = "Available";
break;
}
}
return result;
}
static std::string TrimStatus(const std::string& st) {
std::string s(st);
int j = 0;
bool collapsing = true;
for (unsigned int i = 0; i < s.length(); i+= 1) {
if (s[i] <= ' ' && s[i] >= 0) {
if (collapsing) {
continue;
}
else {
s[j] = ' ';
j += 1;
collapsing = true;
}
}
else {
s[j] = s[i];
j += 1;
collapsing = false;
}
}
if (collapsing && j > 0) {
j -= 1;
}
s.erase(j, s.length());
return s;
}
private:
Jid jid_;
int pri_;
Show show_;
std::string status_;
std::string nick_;
bool available_;
int e_code_;
std::string e_str_;
bool feedback_probation_;
// capabilities (valid only if know_capabilities_
bool know_capabilities_;
bool voice_capability_;
bool pmuc_capability_;
bool video_capability_;
bool camera_capability_;
std::string caps_node_;
std::string version_;
std::string sent_time_; // from the jabber:x:delay element
};
class MucPresenceStatus : public PresenceStatus {
};
} // namespace buzz
#endif // THIRD_PARTY_LIBJINGLE_FILES_WEBRTC_LIBJINGLE_XMPP_PRESENCESTATUS_H_

View File

@ -1,71 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_PREXMPPAUTH_H_
#define WEBRTC_LIBJINGLE_XMPP_PREXMPPAUTH_H_
#include "webrtc/libjingle/xmpp/saslhandler.h"
#include "webrtc/base/cryptstring.h"
#include "webrtc/base/sigslot.h"
namespace rtc {
class SocketAddress;
}
namespace buzz {
class Jid;
class SaslMechanism;
class CaptchaChallenge {
public:
CaptchaChallenge() : captcha_needed_(false) {}
CaptchaChallenge(const std::string& token, const std::string& url)
: captcha_needed_(true), captcha_token_(token), captcha_image_url_(url) {
}
bool captcha_needed() const { return captcha_needed_; }
const std::string& captcha_token() const { return captcha_token_; }
// This url is relative to the gaia server. Once we have better tools
// for cracking URLs, we should probably make this a full URL
const std::string& captcha_image_url() const { return captcha_image_url_; }
private:
bool captcha_needed_;
std::string captcha_token_;
std::string captcha_image_url_;
};
class PreXmppAuth : public SaslHandler {
public:
virtual ~PreXmppAuth() {}
virtual void StartPreXmppAuth(
const Jid& jid,
const rtc::SocketAddress& server,
const rtc::CryptString& pass,
const std::string& auth_mechanism,
const std::string& auth_token) = 0;
sigslot::signal0<> SignalAuthDone;
virtual bool IsAuthDone() const = 0;
virtual bool IsAuthorized() const = 0;
virtual bool HadError() const = 0;
virtual int GetError() const = 0;
virtual CaptchaChallenge GetCaptchaChallenge() const = 0;
virtual std::string GetAuthMechanism() const = 0;
virtual std::string GetAuthToken() const = 0;
};
}
#endif // WEBRTC_LIBJINGLE_XMPP_PREXMPPAUTH_H_

View File

@ -1,201 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/xmpp/pubsub_task.h"
#include <map>
#include <memory>
#include <string>
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/libjingle/xmpp/xmppengine.h"
#include "webrtc/base/common.h"
namespace buzz {
PubsubTask::PubsubTask(XmppTaskParentInterface* parent,
const buzz::Jid& pubsub_node_jid)
: buzz::XmppTask(parent, buzz::XmppEngine::HL_SENDER),
pubsub_node_jid_(pubsub_node_jid) {
}
PubsubTask::~PubsubTask() {
}
// Checks for pubsub publish events as well as responses to get IQs.
bool PubsubTask::HandleStanza(const buzz::XmlElement* stanza) {
const buzz::QName& stanza_name(stanza->Name());
if (stanza_name == buzz::QN_MESSAGE) {
if (MatchStanzaFrom(stanza, pubsub_node_jid_)) {
const buzz::XmlElement* pubsub_event_item =
stanza->FirstNamed(QN_PUBSUB_EVENT);
if (pubsub_event_item != NULL) {
QueueStanza(pubsub_event_item);
return true;
}
}
} else if (stanza_name == buzz::QN_IQ) {
if (MatchResponseIq(stanza, pubsub_node_jid_, task_id())) {
const buzz::XmlElement* pubsub_item = stanza->FirstNamed(QN_PUBSUB);
if (pubsub_item != NULL) {
QueueStanza(pubsub_item);
return true;
}
}
}
return false;
}
int PubsubTask::ProcessResponse() {
const buzz::XmlElement* stanza = NextStanza();
if (stanza == NULL) {
return STATE_BLOCKED;
}
if (stanza->Attr(buzz::QN_TYPE) == buzz::STR_ERROR) {
OnPubsubError(stanza->FirstNamed(buzz::QN_ERROR));
return STATE_RESPONSE;
}
const buzz::QName& stanza_name(stanza->Name());
if (stanza_name == QN_PUBSUB_EVENT) {
HandlePubsubEventMessage(stanza);
} else if (stanza_name == QN_PUBSUB) {
HandlePubsubIqGetResponse(stanza);
}
return STATE_RESPONSE;
}
// Registers a function pointer to be called when the value of the pubsub
// node changes.
// Note that this does not actually change the XMPP pubsub
// subscription. All publish events are always received by everyone in the
// MUC. This function just controls whether the handle function will get
// called when the event is received.
bool PubsubTask::SubscribeToNode(const std::string& pubsub_node,
NodeHandler handler) {
subscribed_nodes_[pubsub_node] = handler;
std::unique_ptr<buzz::XmlElement> get_iq_request(
MakeIq(buzz::STR_GET, pubsub_node_jid_, task_id()));
if (!get_iq_request) {
return false;
}
buzz::XmlElement* pubsub_element = new buzz::XmlElement(QN_PUBSUB, true);
buzz::XmlElement* items_element = new buzz::XmlElement(QN_PUBSUB_ITEMS, true);
items_element->AddAttr(buzz::QN_NODE, pubsub_node);
pubsub_element->AddElement(items_element);
get_iq_request->AddElement(pubsub_element);
if (SendStanza(get_iq_request.get()) != buzz::XMPP_RETURN_OK) {
return false;
}
return true;
}
void PubsubTask::UnsubscribeFromNode(const std::string& pubsub_node) {
subscribed_nodes_.erase(pubsub_node);
}
void PubsubTask::OnPubsubError(const buzz::XmlElement* error_stanza) {
}
// Checks for a pubsub event message like the following:
//
// <message from="muvc-private-chat-some-id@groupchat.google.com"
// to="john@site.com/gcomm582B14C9">
// <event xmlns:"http://jabber.org/protocol/pubsub#event">
// <items node="node-name">
// <item id="some-id">
// <payload/>
// </item>
// </items>
// </event>
// </message>
//
// It also checks for retraction event messages like the following:
//
// <message from="muvc-private-chat-some-id@groupchat.google.com"
// to="john@site.com/gcomm582B14C9">
// <event xmlns:"http://jabber.org/protocol/pubsub#event">
// <items node="node-name">
// <retract id="some-id"/>
// </items>
// </event>
// </message>
void PubsubTask::HandlePubsubEventMessage(
const buzz::XmlElement* pubsub_event) {
ASSERT(pubsub_event->Name() == QN_PUBSUB_EVENT);
for (const buzz::XmlChild* child = pubsub_event->FirstChild();
child != NULL;
child = child->NextChild()) {
const buzz::XmlElement* child_element = child->AsElement();
const buzz::QName& child_name(child_element->Name());
if (child_name == QN_PUBSUB_EVENT_ITEMS) {
HandlePubsubItems(child_element);
}
}
}
// Checks for a response to an pubsub IQ get like the following:
//
// <iq from="muvc-private-chat-some-id@groupchat.google.com"
// to="john@site.com/gcomm582B14C9"
// type="result">
// <pubsub xmlns:"http://jabber.org/protocol/pubsub">
// <items node="node-name">
// <item id="some-id">
// <payload/>
// </item>
// </items>
// </event>
// </message>
void PubsubTask::HandlePubsubIqGetResponse(
const buzz::XmlElement* pubsub_iq_response) {
ASSERT(pubsub_iq_response->Name() == QN_PUBSUB);
for (const buzz::XmlChild* child = pubsub_iq_response->FirstChild();
child != NULL;
child = child->NextChild()) {
const buzz::XmlElement* child_element = child->AsElement();
const buzz::QName& child_name(child_element->Name());
if (child_name == QN_PUBSUB_ITEMS) {
HandlePubsubItems(child_element);
}
}
}
// Calls registered handlers in response to pubsub event or response to
// IQ pubsub get.
// 'items' is the child of a pubsub#event:event node or pubsub:pubsub node.
void PubsubTask::HandlePubsubItems(const buzz::XmlElement* items) {
ASSERT(items->HasAttr(QN_NODE));
const std::string& node_name(items->Attr(QN_NODE));
NodeSubscriptions::iterator iter = subscribed_nodes_.find(node_name);
if (iter != subscribed_nodes_.end()) {
NodeHandler handler = iter->second;
const buzz::XmlElement* item = items->FirstElement();
while (item != NULL) {
const buzz::QName& item_name(item->Name());
if (item_name != QN_PUBSUB_EVENT_ITEM &&
item_name != QN_PUBSUB_EVENT_RETRACT &&
item_name != QN_PUBSUB_ITEM) {
continue;
}
(this->*handler)(item);
item = item->NextElement();
}
return;
}
}
}

View File

@ -1,58 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_PUBSUB_TASK_H_
#define WEBRTC_LIBJINGLE_XMPP_PUBSUB_TASK_H_
#include <map>
#include <string>
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/libjingle/xmpp/jid.h"
#include "webrtc/libjingle/xmpp/xmpptask.h"
namespace buzz {
// Base class to help write pubsub tasks.
// In ProcessStart call SubscribeNode with namespaces of interest along with
// NodeHandlers.
// When pubsub notifications arrive and matches the namespace, the NodeHandlers
// will be called back.
class PubsubTask : public buzz::XmppTask {
public:
virtual ~PubsubTask();
protected:
typedef void (PubsubTask::*NodeHandler)(const buzz::XmlElement* node);
PubsubTask(XmppTaskParentInterface* parent, const buzz::Jid& pubsub_node_jid);
virtual bool HandleStanza(const buzz::XmlElement* stanza);
virtual int ProcessResponse();
bool SubscribeToNode(const std::string& pubsub_node, NodeHandler handler);
void UnsubscribeFromNode(const std::string& pubsub_node);
// Called when there is an error. Derived class can do what it needs to.
virtual void OnPubsubError(const buzz::XmlElement* error_stanza);
private:
typedef std::map<std::string, NodeHandler> NodeSubscriptions;
void HandlePubsubIqGetResponse(const buzz::XmlElement* pubsub_iq_response);
void HandlePubsubEventMessage(const buzz::XmlElement* pubsub_event_message);
void HandlePubsubItems(const buzz::XmlElement* items);
buzz::Jid pubsub_node_jid_;
NodeSubscriptions subscribed_nodes_;
};
} // namespace buzz
#endif // WEBRTC_LIBJINGLE_XMPP_PUBSUB_TASK_H_

View File

@ -1,129 +0,0 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/xmpp/pubsubclient.h"
#include <string>
#include <vector>
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/libjingle/xmpp/jid.h"
#include "webrtc/libjingle/xmpp/pubsubtasks.h"
namespace buzz {
void PubSubClient::RequestItems() {
PubSubRequestTask* request_task =
new PubSubRequestTask(parent_, pubsubjid_, node_);
request_task->SignalResult.connect(this, &PubSubClient::OnRequestResult);
request_task->SignalError.connect(this, &PubSubClient::OnRequestError);
PubSubReceiveTask* receive_task =
new PubSubReceiveTask(parent_, pubsubjid_, node_);
receive_task->SignalUpdate.connect(this, &PubSubClient::OnReceiveUpdate);
receive_task->Start();
request_task->Start();
}
void PubSubClient::PublishItem(
const std::string& itemid, XmlElement* payload, std::string* task_id_out) {
std::vector<XmlElement*> children;
children.push_back(payload);
PublishItem(itemid, children, task_id_out);
}
void PubSubClient::PublishItem(
const std::string& itemid, const std::vector<XmlElement*>& children,
std::string* task_id_out) {
PubSubPublishTask* publish_task =
new PubSubPublishTask(parent_, pubsubjid_, node_, itemid, children);
publish_task->SignalError.connect(this, &PubSubClient::OnPublishError);
publish_task->SignalResult.connect(this, &PubSubClient::OnPublishResult);
publish_task->Start();
if (task_id_out) {
*task_id_out = publish_task->task_id();
}
}
void PubSubClient::RetractItem(
const std::string& itemid, std::string* task_id_out) {
PubSubRetractTask* retract_task =
new PubSubRetractTask(parent_, pubsubjid_, node_, itemid);
retract_task->SignalError.connect(this, &PubSubClient::OnRetractError);
retract_task->SignalResult.connect(this, &PubSubClient::OnRetractResult);
retract_task->Start();
if (task_id_out) {
*task_id_out = retract_task->task_id();
}
}
void PubSubClient::OnRequestResult(PubSubRequestTask* task,
const std::vector<PubSubItem>& items) {
SignalItems(this, items);
}
void PubSubClient::OnRequestError(IqTask* task,
const XmlElement* stanza) {
SignalRequestError(this, stanza);
}
void PubSubClient::OnReceiveUpdate(PubSubReceiveTask* task,
const std::vector<PubSubItem>& items) {
SignalItems(this, items);
}
const XmlElement* GetItemFromStanza(const XmlElement* stanza) {
if (stanza != NULL) {
const XmlElement* pubsub = stanza->FirstNamed(QN_PUBSUB);
if (pubsub != NULL) {
const XmlElement* publish = pubsub->FirstNamed(QN_PUBSUB_PUBLISH);
if (publish != NULL) {
return publish->FirstNamed(QN_PUBSUB_ITEM);
}
}
}
return NULL;
}
void PubSubClient::OnPublishResult(PubSubPublishTask* task) {
const XmlElement* item = GetItemFromStanza(task->stanza());
SignalPublishResult(this, task->task_id(), item);
}
void PubSubClient::OnPublishError(IqTask* task,
const XmlElement* error_stanza) {
PubSubPublishTask* publish_task =
static_cast<PubSubPublishTask*>(task);
const XmlElement* item = GetItemFromStanza(publish_task->stanza());
SignalPublishError(this, publish_task->task_id(), item, error_stanza);
}
void PubSubClient::OnRetractResult(PubSubRetractTask* task) {
SignalRetractResult(this, task->task_id());
}
void PubSubClient::OnRetractError(IqTask* task,
const XmlElement* stanza) {
PubSubRetractTask* retract_task =
static_cast<PubSubRetractTask*>(task);
SignalRetractError(this, retract_task->task_id(), stanza);
}
const std::string PubSubClient::GetPublisherNickFromPubSubItem(
const XmlElement* item_elem) {
if (item_elem == NULL) {
return "";
}
return Jid(item_elem->Attr(QN_ATTR_PUBLISHER)).resource();
}
} // namespace buzz

View File

@ -1,111 +0,0 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_PUBSUBCLIENT_H_
#define WEBRTC_LIBJINGLE_XMPP_PUBSUBCLIENT_H_
#include <string>
#include <vector>
#include "webrtc/libjingle/xmpp/jid.h"
#include "webrtc/libjingle/xmpp/pubsubtasks.h"
#include "webrtc/base/sigslot.h"
#include "webrtc/base/sigslotrepeater.h"
#include "webrtc/base/task.h"
// Easy to use clients built on top of the tasks for XEP-0060
// (http://xmpp.org/extensions/xep-0060.html).
namespace buzz {
class Jid;
class XmlElement;
class XmppTaskParentInterface;
// An easy-to-use pubsub client that handles the three tasks of
// getting, publishing, and listening for updates. Tied to a specific
// pubsub jid and node. All you have to do is RequestItems, listen
// for SignalItems and PublishItems.
class PubSubClient : public sigslot::has_slots<> {
public:
PubSubClient(XmppTaskParentInterface* parent,
const Jid& pubsubjid,
const std::string& node)
: parent_(parent),
pubsubjid_(pubsubjid),
node_(node) {}
const std::string& node() const { return node_; }
// Requests the <pubsub><items>, which will be returned via
// SignalItems, or SignalRequestError if there is a failure. Should
// auto-subscribe.
void RequestItems();
// Fired when either <pubsub><items> are returned or when
// <event><items> are received.
sigslot::signal2<PubSubClient*,
const std::vector<PubSubItem>&> SignalItems;
// Signal (this, error stanza)
sigslot::signal2<PubSubClient*,
const XmlElement*> SignalRequestError;
// Signal (this, task_id, item, error stanza)
sigslot::signal4<PubSubClient*,
const std::string&,
const XmlElement*,
const XmlElement*> SignalPublishError;
// Signal (this, task_id, item)
sigslot::signal3<PubSubClient*,
const std::string&,
const XmlElement*> SignalPublishResult;
// Signal (this, task_id, error stanza)
sigslot::signal3<PubSubClient*,
const std::string&,
const XmlElement*> SignalRetractError;
// Signal (this, task_id)
sigslot::signal2<PubSubClient*,
const std::string&> SignalRetractResult;
// Publish an item. Takes ownership of payload.
void PublishItem(const std::string& itemid,
XmlElement* payload,
std::string* task_id_out);
// Publish an item. Takes ownership of children.
void PublishItem(const std::string& itemid,
const std::vector<XmlElement*>& children,
std::string* task_id_out);
// Retract (delete) an item.
void RetractItem(const std::string& itemid,
std::string* task_id_out);
// Get the publisher nick if it exists from the pubsub item.
const std::string GetPublisherNickFromPubSubItem(const XmlElement* item_elem);
private:
void OnRequestError(IqTask* task,
const XmlElement* stanza);
void OnRequestResult(PubSubRequestTask* task,
const std::vector<PubSubItem>& items);
void OnReceiveUpdate(PubSubReceiveTask* task,
const std::vector<PubSubItem>& items);
void OnPublishResult(PubSubPublishTask* task);
void OnPublishError(IqTask* task,
const XmlElement* stanza);
void OnRetractResult(PubSubRetractTask* task);
void OnRetractError(IqTask* task,
const XmlElement* stanza);
XmppTaskParentInterface* parent_;
Jid pubsubjid_;
std::string node_;
};
} // namespace buzz
#endif // WEBRTC_LIBJINGLE_XMPP_PUBSUBCLIENT_H_

View File

@ -1,279 +0,0 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <memory>
#include <string>
#include "webrtc/libjingle/xmllite/qname.h"
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/libjingle/xmpp/fakexmppclient.h"
#include "webrtc/libjingle/xmpp/jid.h"
#include "webrtc/libjingle/xmpp/pubsubclient.h"
#include "webrtc/base/faketaskrunner.h"
#include "webrtc/base/gunit.h"
#include "webrtc/base/sigslot.h"
struct HandledPubSubItem {
std::string itemid;
std::string payload;
};
class TestPubSubItemsListener : public sigslot::has_slots<> {
public:
TestPubSubItemsListener() : error_count(0) {}
void OnItems(buzz::PubSubClient*,
const std::vector<buzz::PubSubItem>& items) {
for (std::vector<buzz::PubSubItem>::const_iterator item = items.begin();
item != items.end(); ++item) {
HandledPubSubItem handled_item;
handled_item.itemid = item->itemid;
if (item->elem->FirstElement() != NULL) {
handled_item.payload = item->elem->FirstElement()->Str();
}
this->items.push_back(handled_item);
}
}
void OnRequestError(buzz::PubSubClient* client,
const buzz::XmlElement* stanza) {
error_count++;
}
void OnPublishResult(buzz::PubSubClient* client,
const std::string& task_id,
const buzz::XmlElement* item) {
result_task_id = task_id;
}
void OnPublishError(buzz::PubSubClient* client,
const std::string& task_id,
const buzz::XmlElement* item,
const buzz::XmlElement* stanza) {
error_count++;
error_task_id = task_id;
}
void OnRetractResult(buzz::PubSubClient* client,
const std::string& task_id) {
result_task_id = task_id;
}
void OnRetractError(buzz::PubSubClient* client,
const std::string& task_id,
const buzz::XmlElement* stanza) {
error_count++;
error_task_id = task_id;
}
std::vector<HandledPubSubItem> items;
int error_count;
std::string error_task_id;
std::string result_task_id;
};
class PubSubClientTest : public testing::Test {
public:
PubSubClientTest() :
pubsubjid("room@domain.com"),
node("topic"),
itemid("key") {
runner.reset(new rtc::FakeTaskRunner());
xmpp_client = new buzz::FakeXmppClient(runner.get());
client.reset(new buzz::PubSubClient(xmpp_client, pubsubjid, node));
listener.reset(new TestPubSubItemsListener());
client->SignalItems.connect(
listener.get(), &TestPubSubItemsListener::OnItems);
client->SignalRequestError.connect(
listener.get(), &TestPubSubItemsListener::OnRequestError);
client->SignalPublishResult.connect(
listener.get(), &TestPubSubItemsListener::OnPublishResult);
client->SignalPublishError.connect(
listener.get(), &TestPubSubItemsListener::OnPublishError);
client->SignalRetractResult.connect(
listener.get(), &TestPubSubItemsListener::OnRetractResult);
client->SignalRetractError.connect(
listener.get(), &TestPubSubItemsListener::OnRetractError);
}
std::unique_ptr<rtc::FakeTaskRunner> runner;
// xmpp_client deleted by deleting runner.
buzz::FakeXmppClient* xmpp_client;
std::unique_ptr<buzz::PubSubClient> client;
std::unique_ptr<TestPubSubItemsListener> listener;
buzz::Jid pubsubjid;
std::string node;
std::string itemid;
};
TEST_F(PubSubClientTest, TestRequest) {
client->RequestItems();
std::string expected_iq =
"<cli:iq type=\"get\" to=\"room@domain.com\" id=\"0\" "
"xmlns:cli=\"jabber:client\">"
"<pub:pubsub xmlns:pub=\"http://jabber.org/protocol/pubsub\">"
"<pub:items node=\"topic\"/>"
"</pub:pubsub>"
"</cli:iq>";
ASSERT_EQ(1U, xmpp_client->sent_stanzas().size());
EXPECT_EQ(expected_iq, xmpp_client->sent_stanzas()[0]->Str());
std::string result_iq =
"<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'>"
" <pubsub xmlns='http://jabber.org/protocol/pubsub'>"
" <items node='topic'>"
" <item id='key0'>"
" <value0a/>"
" </item>"
" <item id='key1'>"
" <value1a/>"
" </item>"
" </items>"
" </pubsub>"
"</iq>";
xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
ASSERT_EQ(2U, listener->items.size());
EXPECT_EQ("key0", listener->items[0].itemid);
EXPECT_EQ("<pub:value0a xmlns:pub=\"http://jabber.org/protocol/pubsub\"/>",
listener->items[0].payload);
EXPECT_EQ("key1", listener->items[1].itemid);
EXPECT_EQ("<pub:value1a xmlns:pub=\"http://jabber.org/protocol/pubsub\"/>",
listener->items[1].payload);
std::string items_message =
"<message xmlns='jabber:client' from='room@domain.com'>"
" <event xmlns='http://jabber.org/protocol/pubsub#event'>"
" <items node='topic'>"
" <item id='key0'>"
" <value0b/>"
" </item>"
" <item id='key1'>"
" <value1b/>"
" </item>"
" </items>"
" </event>"
"</message>";
xmpp_client->HandleStanza(buzz::XmlElement::ForStr(items_message));
ASSERT_EQ(4U, listener->items.size());
EXPECT_EQ("key0", listener->items[2].itemid);
EXPECT_EQ("<eve:value0b"
" xmlns:eve=\"http://jabber.org/protocol/pubsub#event\"/>",
listener->items[2].payload);
EXPECT_EQ("key1", listener->items[3].itemid);
EXPECT_EQ("<eve:value1b"
" xmlns:eve=\"http://jabber.org/protocol/pubsub#event\"/>",
listener->items[3].payload);
}
TEST_F(PubSubClientTest, TestRequestError) {
std::string result_iq =
"<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'>"
" <error type='auth'>"
" <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>"
" </error>"
"</iq>";
client->RequestItems();
xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
EXPECT_EQ(1, listener->error_count);
}
TEST_F(PubSubClientTest, TestPublish) {
buzz::XmlElement* payload =
new buzz::XmlElement(buzz::QName(buzz::NS_PUBSUB, "value"));
std::string task_id;
client->PublishItem(itemid, payload, &task_id);
std::string expected_iq =
"<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" "
"xmlns:cli=\"jabber:client\">"
"<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">"
"<publish node=\"topic\">"
"<item id=\"key\">"
"<value/>"
"</item>"
"</publish>"
"</pubsub>"
"</cli:iq>";
ASSERT_EQ(1U, xmpp_client->sent_stanzas().size());
EXPECT_EQ(expected_iq, xmpp_client->sent_stanzas()[0]->Str());
std::string result_iq =
"<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'/>";
xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
EXPECT_EQ(task_id, listener->result_task_id);
}
TEST_F(PubSubClientTest, TestPublishError) {
buzz::XmlElement* payload =
new buzz::XmlElement(buzz::QName(buzz::NS_PUBSUB, "value"));
std::string task_id;
client->PublishItem(itemid, payload, &task_id);
std::string result_iq =
"<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'>"
" <error type='auth'>"
" <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>"
" </error>"
"</iq>";
xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
EXPECT_EQ(1, listener->error_count);
EXPECT_EQ(task_id, listener->error_task_id);
}
TEST_F(PubSubClientTest, TestRetract) {
std::string task_id;
client->RetractItem(itemid, &task_id);
std::string expected_iq =
"<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" "
"xmlns:cli=\"jabber:client\">"
"<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">"
"<retract node=\"topic\" notify=\"true\">"
"<item id=\"key\"/>"
"</retract>"
"</pubsub>"
"</cli:iq>";
ASSERT_EQ(1U, xmpp_client->sent_stanzas().size());
EXPECT_EQ(expected_iq, xmpp_client->sent_stanzas()[0]->Str());
std::string result_iq =
"<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'/>";
xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
EXPECT_EQ(task_id, listener->result_task_id);
}
TEST_F(PubSubClientTest, TestRetractError) {
std::string task_id;
client->RetractItem(itemid, &task_id);
std::string result_iq =
"<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'>"
" <error type='auth'>"
" <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>"
" </error>"
"</iq>";
xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
EXPECT_EQ(1, listener->error_count);
EXPECT_EQ(task_id, listener->error_task_id);
}

View File

@ -1,25 +0,0 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/xmpp/pubsubstateclient.h"
namespace buzz {
std::string PublishedNickKeySerializer::GetKey(
const std::string& publisher_nick, const std::string& published_nick) {
return published_nick;
}
std::string PublisherAndPublishedNicksKeySerializer::GetKey(
const std::string& publisher_nick, const std::string& published_nick) {
return publisher_nick + ":" + published_nick;
}
} // namespace buzz

View File

@ -1,271 +0,0 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_PUBSUBSTATECLIENT_H_
#define WEBRTC_LIBJINGLE_XMPP_PUBSUBSTATECLIENT_H_
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "webrtc/libjingle/xmllite/qname.h"
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/libjingle/xmpp/jid.h"
#include "webrtc/libjingle/xmpp/pubsubclient.h"
#include "webrtc/base/constructormagic.h"
#include "webrtc/base/sigslot.h"
#include "webrtc/base/sigslotrepeater.h"
namespace buzz {
// To handle retracts correctly, we need to remember certain details
// about an item. We could just cache the entire XML element, but
// that would take more memory and require re-parsing.
struct StateItemInfo {
std::string published_nick;
std::string publisher_nick;
};
// Represents a PubSub state change. Usually, the key is the nick,
// but not always. It's a per-state-type thing. Look below on how keys are
// computed.
template <typename C>
struct PubSubStateChange {
// The nick of the user changing the state.
std::string publisher_nick;
// The nick of the user whose state is changing.
std::string published_nick;
C old_state;
C new_state;
};
// Knows how to handle specific states and XML.
template <typename C>
class PubSubStateSerializer {
public:
virtual ~PubSubStateSerializer() {}
virtual XmlElement* Write(const QName& state_name, const C& state) = 0;
virtual void Parse(const XmlElement* state_elem, C* state_out) = 0;
};
// Knows how to create "keys" for states, which determines their
// uniqueness. Most states are per-nick, but block is
// per-blocker-and-blockee. This is independent of itemid, especially
// in the case of presenter state.
class PubSubStateKeySerializer {
public:
virtual ~PubSubStateKeySerializer() {}
virtual std::string GetKey(const std::string& publisher_nick,
const std::string& published_nick) = 0;
};
class PublishedNickKeySerializer : public PubSubStateKeySerializer {
public:
virtual std::string GetKey(const std::string& publisher_nick,
const std::string& published_nick);
};
class PublisherAndPublishedNicksKeySerializer
: public PubSubStateKeySerializer {
public:
virtual std::string GetKey(const std::string& publisher_nick,
const std::string& published_nick);
};
// Adapts PubSubClient to be specifically suited for pub sub call
// states. Signals state changes and keeps track of keys, which are
// normally nicks.
template <typename C>
class PubSubStateClient : public sigslot::has_slots<> {
public:
// Gets ownership of the serializers, but not the client.
PubSubStateClient(const std::string& publisher_nick,
PubSubClient* client,
const QName& state_name,
C default_state,
PubSubStateKeySerializer* key_serializer,
PubSubStateSerializer<C>* state_serializer)
: publisher_nick_(publisher_nick),
client_(client),
state_name_(state_name),
default_state_(default_state) {
key_serializer_.reset(key_serializer);
state_serializer_.reset(state_serializer);
client_->SignalItems.connect(
this, &PubSubStateClient<C>::OnItems);
client_->SignalPublishResult.connect(
this, &PubSubStateClient<C>::OnPublishResult);
client_->SignalPublishError.connect(
this, &PubSubStateClient<C>::OnPublishError);
client_->SignalRetractResult.connect(
this, &PubSubStateClient<C>::OnRetractResult);
client_->SignalRetractError.connect(
this, &PubSubStateClient<C>::OnRetractError);
}
virtual ~PubSubStateClient() {}
virtual void Publish(const std::string& published_nick,
const C& state,
std::string* task_id_out) {
std::string key = key_serializer_->GetKey(publisher_nick_, published_nick);
std::string itemid = state_name_.LocalPart() + ":" + key;
if (StatesEqual(state, default_state_)) {
client_->RetractItem(itemid, task_id_out);
} else {
XmlElement* state_elem = state_serializer_->Write(state_name_, state);
state_elem->AddAttr(QN_NICK, published_nick);
client_->PublishItem(itemid, state_elem, task_id_out);
}
}
sigslot::signal1<const PubSubStateChange<C>&> SignalStateChange;
// Signal (task_id, item). item is NULL for retract.
sigslot::signal2<const std::string&,
const XmlElement*> SignalPublishResult;
// Signal (task_id, item, error stanza). item is NULL for retract.
sigslot::signal3<const std::string&,
const XmlElement*,
const XmlElement*> SignalPublishError;
protected:
// return false if retracted item (no info or state given)
virtual bool ParseStateItem(const PubSubItem& item,
StateItemInfo* info_out,
C* state_out) {
const XmlElement* state_elem = item.elem->FirstNamed(state_name_);
if (state_elem == NULL) {
return false;
}
info_out->publisher_nick =
client_->GetPublisherNickFromPubSubItem(item.elem);
info_out->published_nick = state_elem->Attr(QN_NICK);
state_serializer_->Parse(state_elem, state_out);
return true;
}
virtual bool StatesEqual(const C& state1, const C& state2) {
return state1 == state2;
}
PubSubClient* client() { return client_; }
const QName& state_name() { return state_name_; }
private:
void OnItems(PubSubClient* pub_sub_client,
const std::vector<PubSubItem>& items) {
for (std::vector<PubSubItem>::const_iterator item = items.begin();
item != items.end(); ++item) {
OnItem(*item);
}
}
void OnItem(const PubSubItem& item) {
const std::string& itemid = item.itemid;
StateItemInfo info;
C new_state;
bool retracted = !ParseStateItem(item, &info, &new_state);
if (retracted) {
bool known_itemid =
(info_by_itemid_.find(itemid) != info_by_itemid_.end());
if (!known_itemid) {
// Nothing to retract, and nothing to publish.
// Probably a different state type.
return;
} else {
info = info_by_itemid_[itemid];
info_by_itemid_.erase(itemid);
new_state = default_state_;
}
} else {
// TODO: Assert new key matches the known key. It
// shouldn't change!
info_by_itemid_[itemid] = info;
}
std::string key = key_serializer_->GetKey(
info.publisher_nick, info.published_nick);
bool has_old_state = (state_by_key_.find(key) != state_by_key_.end());
C old_state = has_old_state ? state_by_key_[key] : default_state_;
if ((retracted && !has_old_state) || StatesEqual(new_state, old_state)) {
// Nothing change, so don't bother signalling.
return;
}
if (retracted || StatesEqual(new_state, default_state_)) {
// We treat a default state similar to a retract.
state_by_key_.erase(key);
} else {
state_by_key_[key] = new_state;
}
PubSubStateChange<C> change;
if (!retracted) {
// Retracts do not have publisher information.
change.publisher_nick = info.publisher_nick;
}
change.published_nick = info.published_nick;
change.old_state = old_state;
change.new_state = new_state;
SignalStateChange(change);
}
void OnPublishResult(PubSubClient* pub_sub_client,
const std::string& task_id,
const XmlElement* item) {
SignalPublishResult(task_id, item);
}
void OnPublishError(PubSubClient* pub_sub_client,
const std::string& task_id,
const buzz::XmlElement* item,
const buzz::XmlElement* stanza) {
SignalPublishError(task_id, item, stanza);
}
void OnRetractResult(PubSubClient* pub_sub_client,
const std::string& task_id) {
// There's no point in differentiating between publish and retract
// errors, so we simplify by making them both signal a publish
// result.
const XmlElement* item = NULL;
SignalPublishResult(task_id, item);
}
void OnRetractError(PubSubClient* pub_sub_client,
const std::string& task_id,
const buzz::XmlElement* stanza) {
// There's no point in differentiating between publish and retract
// errors, so we simplify by making them both signal a publish
// error.
const XmlElement* item = NULL;
SignalPublishError(task_id, item, stanza);
}
std::string publisher_nick_;
PubSubClient* client_;
const QName state_name_;
C default_state_;
std::unique_ptr<PubSubStateKeySerializer> key_serializer_;
std::unique_ptr<PubSubStateSerializer<C> > state_serializer_;
// key => state
std::map<std::string, C> state_by_key_;
// itemid => StateItemInfo
std::map<std::string, StateItemInfo> info_by_itemid_;
RTC_DISALLOW_COPY_AND_ASSIGN(PubSubStateClient);
};
} // namespace buzz
#endif // WEBRTC_LIBJINGLE_XMPP_PUBSUBSTATECLIENT_H_

View File

@ -1,204 +0,0 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/xmpp/pubsubtasks.h"
#include <string>
#include <vector>
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/libjingle/xmpp/receivetask.h"
// An implementation of the tasks for XEP-0060
// (http://xmpp.org/extensions/xep-0060.html).
namespace buzz {
namespace {
bool IsPubSubEventItemsElem(const XmlElement* stanza,
const std::string& expected_node) {
if (stanza->Name() != QN_MESSAGE) {
return false;
}
const XmlElement* event_elem = stanza->FirstNamed(QN_PUBSUB_EVENT);
if (event_elem == NULL) {
return false;
}
const XmlElement* items_elem = event_elem->FirstNamed(QN_PUBSUB_EVENT_ITEMS);
if (items_elem == NULL) {
return false;
}
const std::string& actual_node = items_elem->Attr(QN_NODE);
return (actual_node == expected_node);
}
// Creates <pubsub node="node"><items></pubsub>
XmlElement* CreatePubSubItemsElem(const std::string& node) {
XmlElement* items_elem = new XmlElement(QN_PUBSUB_ITEMS, false);
items_elem->AddAttr(QN_NODE, node);
XmlElement* pubsub_elem = new XmlElement(QN_PUBSUB, false);
pubsub_elem->AddElement(items_elem);
return pubsub_elem;
}
// Creates <pubsub node="node"><publish><item id="itemid">payload</item>...
// Takes ownership of payload.
XmlElement* CreatePubSubPublishItemElem(
const std::string& node,
const std::string& itemid,
const std::vector<XmlElement*>& children) {
XmlElement* pubsub_elem = new XmlElement(QN_PUBSUB, true);
XmlElement* publish_elem = new XmlElement(QN_PUBSUB_PUBLISH, false);
publish_elem->AddAttr(QN_NODE, node);
XmlElement* item_elem = new XmlElement(QN_PUBSUB_ITEM, false);
item_elem->AddAttr(QN_ID, itemid);
for (std::vector<XmlElement*>::const_iterator child = children.begin();
child != children.end(); ++child) {
item_elem->AddElement(*child);
}
publish_elem->AddElement(item_elem);
pubsub_elem->AddElement(publish_elem);
return pubsub_elem;
}
// Creates <pubsub node="node"><publish><item id="itemid">payload</item>...
// Takes ownership of payload.
XmlElement* CreatePubSubRetractItemElem(const std::string& node,
const std::string& itemid) {
XmlElement* pubsub_elem = new XmlElement(QN_PUBSUB, true);
XmlElement* retract_elem = new XmlElement(QN_PUBSUB_RETRACT, false);
retract_elem->AddAttr(QN_NODE, node);
retract_elem->AddAttr(QN_NOTIFY, "true");
XmlElement* item_elem = new XmlElement(QN_PUBSUB_ITEM, false);
item_elem->AddAttr(QN_ID, itemid);
retract_elem->AddElement(item_elem);
pubsub_elem->AddElement(retract_elem);
return pubsub_elem;
}
void ParseItem(const XmlElement* item_elem,
std::vector<PubSubItem>* items) {
PubSubItem item;
item.itemid = item_elem->Attr(QN_ID);
item.elem = item_elem;
items->push_back(item);
}
// Right now, <retract>s are treated the same as items with empty
// payloads. We may want to change it in the future, but right now
// it's sufficient for our needs.
void ParseRetract(const XmlElement* retract_elem,
std::vector<PubSubItem>* items) {
ParseItem(retract_elem, items);
}
void ParseEventItemsElem(const XmlElement* stanza,
std::vector<PubSubItem>* items) {
const XmlElement* event_elem = stanza->FirstNamed(QN_PUBSUB_EVENT);
if (event_elem != NULL) {
const XmlElement* items_elem =
event_elem->FirstNamed(QN_PUBSUB_EVENT_ITEMS);
if (items_elem != NULL) {
for (const XmlElement* item_elem =
items_elem->FirstNamed(QN_PUBSUB_EVENT_ITEM);
item_elem != NULL;
item_elem = item_elem->NextNamed(QN_PUBSUB_EVENT_ITEM)) {
ParseItem(item_elem, items);
}
for (const XmlElement* retract_elem =
items_elem->FirstNamed(QN_PUBSUB_EVENT_RETRACT);
retract_elem != NULL;
retract_elem = retract_elem->NextNamed(QN_PUBSUB_EVENT_RETRACT)) {
ParseRetract(retract_elem, items);
}
}
}
}
void ParsePubSubItemsElem(const XmlElement* stanza,
std::vector<PubSubItem>* items) {
const XmlElement* pubsub_elem = stanza->FirstNamed(QN_PUBSUB);
if (pubsub_elem != NULL) {
const XmlElement* items_elem = pubsub_elem->FirstNamed(QN_PUBSUB_ITEMS);
if (items_elem != NULL) {
for (const XmlElement* item_elem = items_elem->FirstNamed(QN_PUBSUB_ITEM);
item_elem != NULL;
item_elem = item_elem->NextNamed(QN_PUBSUB_ITEM)) {
ParseItem(item_elem, items);
}
}
}
}
} // namespace
PubSubRequestTask::PubSubRequestTask(XmppTaskParentInterface* parent,
const Jid& pubsubjid,
const std::string& node)
: IqTask(parent, STR_GET, pubsubjid, CreatePubSubItemsElem(node)) {
}
void PubSubRequestTask::HandleResult(const XmlElement* stanza) {
std::vector<PubSubItem> items;
ParsePubSubItemsElem(stanza, &items);
SignalResult(this, items);
}
int PubSubReceiveTask::ProcessStart() {
if (SignalUpdate.is_empty()) {
return STATE_DONE;
}
return ReceiveTask::ProcessStart();
}
bool PubSubReceiveTask::WantsStanza(const XmlElement* stanza) {
return MatchStanzaFrom(stanza, pubsubjid_) &&
IsPubSubEventItemsElem(stanza, node_) && !SignalUpdate.is_empty();
}
void PubSubReceiveTask::ReceiveStanza(const XmlElement* stanza) {
std::vector<PubSubItem> items;
ParseEventItemsElem(stanza, &items);
SignalUpdate(this, items);
}
PubSubPublishTask::PubSubPublishTask(XmppTaskParentInterface* parent,
const Jid& pubsubjid,
const std::string& node,
const std::string& itemid,
const std::vector<XmlElement*>& children)
: IqTask(parent, STR_SET, pubsubjid,
CreatePubSubPublishItemElem(node, itemid, children)),
itemid_(itemid) {
}
void PubSubPublishTask::HandleResult(const XmlElement* stanza) {
SignalResult(this);
}
PubSubRetractTask::PubSubRetractTask(XmppTaskParentInterface* parent,
const Jid& pubsubjid,
const std::string& node,
const std::string& itemid)
: IqTask(parent, STR_SET, pubsubjid,
CreatePubSubRetractItemElem(node, itemid)),
itemid_(itemid) {
}
void PubSubRetractTask::HandleResult(const XmlElement* stanza) {
SignalResult(this);
}
} // namespace buzz

View File

@ -1,114 +0,0 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_PUBSUBTASKS_H_
#define WEBRTC_LIBJINGLE_XMPP_PUBSUBTASKS_H_
#include <vector>
#include "webrtc/libjingle/xmpp/iqtask.h"
#include "webrtc/libjingle/xmpp/receivetask.h"
#include "webrtc/base/sigslot.h"
namespace buzz {
// A PubSub itemid + payload. Useful for signaling items.
struct PubSubItem {
std::string itemid;
// The entire <item>, owned by the stanza handler. To keep a
// reference after handling, make a copy.
const XmlElement* elem;
};
// An IqTask which gets a <pubsub><items> for a particular jid and
// node, parses the items in the response and signals the items.
class PubSubRequestTask : public IqTask {
public:
PubSubRequestTask(XmppTaskParentInterface* parent,
const Jid& pubsubjid,
const std::string& node);
sigslot::signal2<PubSubRequestTask*,
const std::vector<PubSubItem>&> SignalResult;
// SignalError inherited by IqTask.
private:
virtual void HandleResult(const XmlElement* stanza);
};
// A ReceiveTask which listens for <event><items> of a particular
// pubsub JID and node and then signals them items.
class PubSubReceiveTask : public ReceiveTask {
public:
PubSubReceiveTask(XmppTaskParentInterface* parent,
const Jid& pubsubjid,
const std::string& node)
: ReceiveTask(parent),
pubsubjid_(pubsubjid),
node_(node) {
}
virtual int ProcessStart();
sigslot::signal2<PubSubReceiveTask*,
const std::vector<PubSubItem>&> SignalUpdate;
protected:
virtual bool WantsStanza(const XmlElement* stanza);
virtual void ReceiveStanza(const XmlElement* stanza);
private:
Jid pubsubjid_;
std::string node_;
};
// An IqTask which publishes a <pubsub><publish><item> to a particular
// pubsub jid and node.
class PubSubPublishTask : public IqTask {
public:
// Takes ownership of children
PubSubPublishTask(XmppTaskParentInterface* parent,
const Jid& pubsubjid,
const std::string& node,
const std::string& itemid,
const std::vector<XmlElement*>& children);
const std::string& itemid() const { return itemid_; }
sigslot::signal1<PubSubPublishTask*> SignalResult;
private:
// SignalError inherited by IqTask.
virtual void HandleResult(const XmlElement* stanza);
std::string itemid_;
};
// An IqTask which publishes a <pubsub><publish><retract> to a particular
// pubsub jid and node.
class PubSubRetractTask : public IqTask {
public:
PubSubRetractTask(XmppTaskParentInterface* parent,
const Jid& pubsubjid,
const std::string& node,
const std::string& itemid);
const std::string& itemid() const { return itemid_; }
sigslot::signal1<PubSubRetractTask*> SignalResult;
private:
// SignalError inherited by IqTask.
virtual void HandleResult(const XmlElement* stanza);
std::string itemid_;
};
} // namespace buzz
#endif // WEBRTC_LIBJINGLE_XMPP_PUBSUBTASKS_H_

View File

@ -1,281 +0,0 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <memory>
#include <string>
#include "webrtc/libjingle/xmllite/qname.h"
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/libjingle/xmpp/fakexmppclient.h"
#include "webrtc/libjingle/xmpp/iqtask.h"
#include "webrtc/libjingle/xmpp/jid.h"
#include "webrtc/libjingle/xmpp/pubsubtasks.h"
#include "webrtc/base/faketaskrunner.h"
#include "webrtc/base/gunit.h"
#include "webrtc/base/sigslot.h"
struct HandledPubSubItem {
std::string itemid;
std::string payload;
};
class TestPubSubTasksListener : public sigslot::has_slots<> {
public:
TestPubSubTasksListener() : result_count(0), error_count(0) {}
void OnReceiveUpdate(buzz::PubSubReceiveTask* task,
const std::vector<buzz::PubSubItem>& items) {
OnItems(items);
}
void OnRequestResult(buzz::PubSubRequestTask* task,
const std::vector<buzz::PubSubItem>& items) {
OnItems(items);
}
void OnItems(const std::vector<buzz::PubSubItem>& items) {
for (std::vector<buzz::PubSubItem>::const_iterator item = items.begin();
item != items.end(); ++item) {
HandledPubSubItem handled_item;
handled_item.itemid = item->itemid;
if (item->elem->FirstElement() != NULL) {
handled_item.payload = item->elem->FirstElement()->Str();
}
this->items.push_back(handled_item);
}
}
void OnPublishResult(buzz::PubSubPublishTask* task) {
++result_count;
}
void OnRetractResult(buzz::PubSubRetractTask* task) {
++result_count;
}
void OnError(buzz::IqTask* task, const buzz::XmlElement* stanza) {
++error_count;
}
std::vector<HandledPubSubItem> items;
int result_count;
int error_count;
};
class PubSubTasksTest : public testing::Test {
public:
PubSubTasksTest() :
pubsubjid("room@domain.com"),
node("topic"),
itemid("key") {
runner.reset(new rtc::FakeTaskRunner());
client = new buzz::FakeXmppClient(runner.get());
listener.reset(new TestPubSubTasksListener());
}
std::unique_ptr<rtc::FakeTaskRunner> runner;
// Client deleted by deleting runner.
buzz::FakeXmppClient* client;
std::unique_ptr<TestPubSubTasksListener> listener;
buzz::Jid pubsubjid;
std::string node;
std::string itemid;
};
TEST_F(PubSubTasksTest, TestRequest) {
buzz::PubSubRequestTask* task =
new buzz::PubSubRequestTask(client, pubsubjid, node);
task->SignalResult.connect(
listener.get(), &TestPubSubTasksListener::OnRequestResult);
task->Start();
std::string expected_iq =
"<cli:iq type=\"get\" to=\"room@domain.com\" id=\"0\" "
"xmlns:cli=\"jabber:client\">"
"<pub:pubsub xmlns:pub=\"http://jabber.org/protocol/pubsub\">"
"<pub:items node=\"topic\"/>"
"</pub:pubsub>"
"</cli:iq>";
ASSERT_EQ(1U, client->sent_stanzas().size());
EXPECT_EQ(expected_iq, client->sent_stanzas()[0]->Str());
std::string result_iq =
"<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'>"
" <pubsub xmlns='http://jabber.org/protocol/pubsub'>"
" <items node='topic'>"
" <item id='key0'>"
" <value0/>"
" </item>"
" <item id='key1'>"
" <value1/>"
" </item>"
" </items>"
" </pubsub>"
"</iq>";
client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
ASSERT_EQ(2U, listener->items.size());
EXPECT_EQ("key0", listener->items[0].itemid);
EXPECT_EQ("<pub:value0 xmlns:pub=\"http://jabber.org/protocol/pubsub\"/>",
listener->items[0].payload);
EXPECT_EQ("key1", listener->items[1].itemid);
EXPECT_EQ("<pub:value1 xmlns:pub=\"http://jabber.org/protocol/pubsub\"/>",
listener->items[1].payload);
}
TEST_F(PubSubTasksTest, TestRequestError) {
std::string result_iq =
"<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'>"
" <error type='auth'>"
" <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>"
" </error>"
"</iq>";
buzz::PubSubRequestTask* task =
new buzz::PubSubRequestTask(client, pubsubjid, node);
task->SignalResult.connect(
listener.get(), &TestPubSubTasksListener::OnRequestResult);
task->SignalError.connect(
listener.get(), &TestPubSubTasksListener::OnError);
task->Start();
client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
EXPECT_EQ(0, listener->result_count);
EXPECT_EQ(1, listener->error_count);
}
TEST_F(PubSubTasksTest, TestReceive) {
std::string items_message =
"<message xmlns='jabber:client' from='room@domain.com'>"
" <event xmlns='http://jabber.org/protocol/pubsub#event'>"
" <items node='topic'>"
" <item id='key0'>"
" <value0/>"
" </item>"
" <item id='key1'>"
" <value1/>"
" </item>"
" </items>"
" </event>"
"</message>";
buzz::PubSubReceiveTask* task =
new buzz::PubSubReceiveTask(client, pubsubjid, node);
task->SignalUpdate.connect(
listener.get(), &TestPubSubTasksListener::OnReceiveUpdate);
task->Start();
client->HandleStanza(buzz::XmlElement::ForStr(items_message));
ASSERT_EQ(2U, listener->items.size());
EXPECT_EQ("key0", listener->items[0].itemid);
EXPECT_EQ(
"<eve:value0 xmlns:eve=\"http://jabber.org/protocol/pubsub#event\"/>",
listener->items[0].payload);
EXPECT_EQ("key1", listener->items[1].itemid);
EXPECT_EQ(
"<eve:value1 xmlns:eve=\"http://jabber.org/protocol/pubsub#event\"/>",
listener->items[1].payload);
}
TEST_F(PubSubTasksTest, TestPublish) {
buzz::XmlElement* payload =
new buzz::XmlElement(buzz::QName(buzz::NS_PUBSUB, "value"));
std::string expected_iq =
"<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" "
"xmlns:cli=\"jabber:client\">"
"<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">"
"<publish node=\"topic\">"
"<item id=\"key\">"
"<value/>"
"</item>"
"</publish>"
"</pubsub>"
"</cli:iq>";
std::vector<buzz::XmlElement*> children;
children.push_back(payload);
buzz::PubSubPublishTask* task =
new buzz::PubSubPublishTask(client, pubsubjid, node, itemid, children);
task->SignalResult.connect(
listener.get(), &TestPubSubTasksListener::OnPublishResult);
task->Start();
ASSERT_EQ(1U, client->sent_stanzas().size());
EXPECT_EQ(expected_iq, client->sent_stanzas()[0]->Str());
std::string result_iq =
"<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'/>";
client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
EXPECT_EQ(1, listener->result_count);
EXPECT_EQ(0, listener->error_count);
}
TEST_F(PubSubTasksTest, TestPublishError) {
buzz::XmlElement* payload =
new buzz::XmlElement(buzz::QName(buzz::NS_PUBSUB, "value"));
std::vector<buzz::XmlElement*> children;
children.push_back(payload);
buzz::PubSubPublishTask* task =
new buzz::PubSubPublishTask(client, pubsubjid, node, itemid, children);
task->SignalResult.connect(
listener.get(), &TestPubSubTasksListener::OnPublishResult);
task->SignalError.connect(
listener.get(), &TestPubSubTasksListener::OnError);
task->Start();
std::string result_iq =
"<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'>"
" <error type='auth'>"
" <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>"
" </error>"
"</iq>";
client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
EXPECT_EQ(0, listener->result_count);
EXPECT_EQ(1, listener->error_count);
}
TEST_F(PubSubTasksTest, TestRetract) {
buzz::PubSubRetractTask* task =
new buzz::PubSubRetractTask(client, pubsubjid, node, itemid);
task->SignalResult.connect(
listener.get(), &TestPubSubTasksListener::OnRetractResult);
task->SignalError.connect(
listener.get(), &TestPubSubTasksListener::OnError);
task->Start();
std::string expected_iq =
"<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" "
"xmlns:cli=\"jabber:client\">"
"<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">"
"<retract node=\"topic\" notify=\"true\">"
"<item id=\"key\"/>"
"</retract>"
"</pubsub>"
"</cli:iq>";
ASSERT_EQ(1U, client->sent_stanzas().size());
EXPECT_EQ(expected_iq, client->sent_stanzas()[0]->Str());
std::string result_iq =
"<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'/>";
client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
EXPECT_EQ(1, listener->result_count);
EXPECT_EQ(0, listener->error_count);
}

View File

@ -1,34 +0,0 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/libjingle/xmpp/receivetask.h"
namespace buzz {
bool ReceiveTask::HandleStanza(const XmlElement* stanza) {
if (WantsStanza(stanza)) {
QueueStanza(stanza);
return true;
}
return false;
}
int ReceiveTask::ProcessStart() {
const XmlElement* stanza = NextStanza();
if (stanza == NULL)
return STATE_BLOCKED;
ReceiveStanza(stanza);
return STATE_START;
}
} // namespace buzz

View File

@ -1,41 +0,0 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_RECEIVETASK_H_
#define WEBRTC_LIBJINGLE_XMPP_RECEIVETASK_H_
#include "webrtc/libjingle/xmpp/xmpptask.h"
namespace buzz {
// A base class for receiving stanzas. Override WantsStanza to
// indicate that a stanza should be received and ReceiveStanza to
// process it. Once started, ReceiveStanza will be called for all
// stanzas that return true when passed to WantsStanza. This saves
// you from having to remember how to setup the queueing and the task
// states, etc.
class ReceiveTask : public XmppTask {
public:
explicit ReceiveTask(XmppTaskParentInterface* parent) :
XmppTask(parent, XmppEngine::HL_TYPE) {}
virtual int ProcessStart();
protected:
virtual bool HandleStanza(const XmlElement* stanza);
// Return true if the stanza should be received.
virtual bool WantsStanza(const XmlElement* stanza) = 0;
// Process the received stanza.
virtual void ReceiveStanza(const XmlElement* stanza) = 0;
};
} // namespace buzz
#endif // WEBRTC_LIBJINGLE_XMPP_RECEIVETASK_H_

View File

@ -1,331 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_ROSTERMODULE_H_
#define WEBRTC_LIBJINGLE_XMPP_ROSTERMODULE_H_
#include "webrtc/libjingle/xmpp/module.h"
namespace buzz {
class XmppRosterModule;
// The main way you initialize and use the module would be like this:
// XmppRosterModule *roster_module = XmppRosterModule::Create();
// roster_module->RegisterEngine(engine);
// roster_module->BroadcastPresence();
// roster_module->RequestRosterUpdate();
//! This enum captures the valid values for the show attribute in a presence
//! stanza
enum XmppPresenceShow
{
XMPP_PRESENCE_CHAT = 0,
XMPP_PRESENCE_DEFAULT = 1,
XMPP_PRESENCE_AWAY = 2,
XMPP_PRESENCE_XA = 3,
XMPP_PRESENCE_DND = 4,
};
//! These are the valid subscription states in a roster contact. This
//! represents the combination of the subscription and ask attributes
enum XmppSubscriptionState
{
XMPP_SUBSCRIPTION_NONE = 0,
XMPP_SUBSCRIPTION_NONE_ASKED = 1,
XMPP_SUBSCRIPTION_TO = 2,
XMPP_SUBSCRIPTION_FROM = 3,
XMPP_SUBSCRIPTION_FROM_ASKED = 4,
XMPP_SUBSCRIPTION_BOTH = 5,
};
//! These represent the valid types of presence stanzas for managing
//! subscriptions
enum XmppSubscriptionRequestType
{
XMPP_REQUEST_SUBSCRIBE = 0,
XMPP_REQUEST_UNSUBSCRIBE = 1,
XMPP_REQUEST_SUBSCRIBED = 2,
XMPP_REQUEST_UNSUBSCRIBED = 3,
};
enum XmppPresenceAvailable {
XMPP_PRESENCE_UNAVAILABLE = 0,
XMPP_PRESENCE_AVAILABLE = 1,
XMPP_PRESENCE_ERROR = 2,
};
enum XmppPresenceConnectionStatus {
XMPP_CONNECTION_STATUS_UNKNOWN = 0,
// Status set by the server while the user is being rung.
XMPP_CONNECTION_STATUS_CONNECTING = 1,
// Status set by the client when the user has accepted the ring but before
// the client has joined the call.
XMPP_CONNECTION_STATUS_JOINING = 2,
// Status set by the client as part of joining the call.
XMPP_CONNECTION_STATUS_CONNECTED = 3,
XMPP_CONNECTION_STATUS_HANGUP = 4,
};
//! Presence Information
//! This class stores both presence information for outgoing presence and is
//! returned by methods in XmppRosterModule to represent recieved incoming
//! presence information. When this class is writeable (non-const) then each
//! update to any property will set the inner xml. Setting the raw_xml will
//! rederive all of the other properties.
class XmppPresence {
public:
virtual ~XmppPresence() {}
//! Create a new Presence
//! This is typically only used when sending a directed presence
static XmppPresence* Create();
//! The Jid of for the presence information.
//! Typically this will be a full Jid with resource specified.
virtual const Jid jid() const = 0;
//! Is the contact available?
virtual XmppPresenceAvailable available() const = 0;
//! Sets if the user is available or not
virtual XmppReturnStatus set_available(XmppPresenceAvailable available) = 0;
//! The show value of the presence info
virtual XmppPresenceShow presence_show() const = 0;
//! Set the presence show value
virtual XmppReturnStatus set_presence_show(XmppPresenceShow show) = 0;
//! The Priority of the presence info
virtual int priority() const = 0;
//! Set the priority of the presence
virtual XmppReturnStatus set_priority(int priority) = 0;
//! The plain text status of the presence info.
//! If there are multiple status because of language, this will either be a
//! status that is not tagged for language or the first available
virtual const std::string status() const = 0;
//! Sets the status for the presence info.
//! If there is more than one status present already then this will remove
//! them all and replace it with one status element we no specified language
virtual XmppReturnStatus set_status(const std::string& status) = 0;
//! The connection status
virtual XmppPresenceConnectionStatus connection_status() const = 0;
//! The focus obfuscated GAIA id
virtual const std::string google_user_id() const = 0;
//! The nickname in the presence
virtual const std::string nickname() const = 0;
//! The raw xml of the presence update
virtual const XmlElement* raw_xml() const = 0;
//! Sets the raw presence stanza for the presence update
//! This will cause all other data items in this structure to be rederived
virtual XmppReturnStatus set_raw_xml(const XmlElement * xml) = 0;
};
//! A contact as given by the server
class XmppRosterContact {
public:
virtual ~XmppRosterContact() {}
//! Create a new roster contact
//! This is typically only used when doing a roster update/add
static XmppRosterContact* Create();
//! The jid for the contact.
//! Typically this will be a bare Jid.
virtual const Jid jid() const = 0;
//! Sets the jid for the roster contact update
virtual XmppReturnStatus set_jid(const Jid& jid) = 0;
//! The name (nickname) stored for this contact
virtual const std::string name() const = 0;
//! Sets the name
virtual XmppReturnStatus set_name(const std::string& name) = 0;
//! The Presence subscription state stored on the server for this contact
//! This is never settable and will be ignored when generating a roster
//! add/update request
virtual XmppSubscriptionState subscription_state() const = 0;
//! The number of Groups applied to this contact
virtual size_t GetGroupCount() const = 0;
//! Gets a Group applied to the contact based on index.
//! range
virtual const std::string GetGroup(size_t index) const = 0;
//! Adds a group to this contact.
//! This will return a bad argument error if the group is already there.
virtual XmppReturnStatus AddGroup(const std::string& group) = 0;
//! Removes a group from the contact.
//! This will return an error if the group cannot be found in the group list.
virtual XmppReturnStatus RemoveGroup(const std::string& group) = 0;
//! The raw xml for this roster contact
virtual const XmlElement* raw_xml() const = 0;
//! Sets the raw presence stanza for the contact update/add
//! This will cause all other data items in this structure to be rederived
virtual XmppReturnStatus set_raw_xml(const XmlElement * xml) = 0;
};
//! The XmppRosterHandler is an interface for callbacks from the module
class XmppRosterHandler {
public:
virtual ~XmppRosterHandler() {}
//! A request for a subscription has come in.
//! Typically, the UI will ask the user if it is okay to let the requester
//! get presence notifications for the user. The response is send back
//! by calling ApproveSubscriber or CancelSubscriber.
virtual void SubscriptionRequest(XmppRosterModule* roster,
const Jid& requesting_jid,
XmppSubscriptionRequestType type,
const XmlElement* raw_xml) = 0;
//! Some type of presence error has occured
virtual void SubscriptionError(XmppRosterModule* roster,
const Jid& from,
const XmlElement* raw_xml) = 0;
virtual void RosterError(XmppRosterModule* roster,
const XmlElement* raw_xml) = 0;
//! New presence information has come in
//! The user is notified with the presence object directly. This info is also
//! added to the store accessable from the engine.
virtual void IncomingPresenceChanged(XmppRosterModule* roster,
const XmppPresence* presence) = 0;
//! A contact has changed
//! This indicates that the data for a contact may have changed. No
//! contacts have been added or removed.
virtual void ContactChanged(XmppRosterModule* roster,
const XmppRosterContact* old_contact,
size_t index) = 0;
//! A set of contacts have been added
//! These contacts may have been added in response to the original roster
//! request or due to a "roster push" from the server.
virtual void ContactsAdded(XmppRosterModule* roster,
size_t index, size_t number) = 0;
//! A contact has been removed
//! This contact has been removed form the list.
virtual void ContactRemoved(XmppRosterModule* roster,
const XmppRosterContact* removed_contact,
size_t index) = 0;
};
//! An XmppModule for handle roster and presence functionality
class XmppRosterModule : public XmppModule {
public:
//! Creates a new XmppRosterModule
static XmppRosterModule * Create();
virtual ~XmppRosterModule() {}
//! Sets the roster handler (callbacks) for the module
virtual XmppReturnStatus set_roster_handler(XmppRosterHandler * handler) = 0;
//! Gets the roster handler for the module
virtual XmppRosterHandler* roster_handler() = 0;
// USER PRESENCE STATE -------------------------------------------------------
//! Gets the aggregate outgoing presence
//! This object is non-const and be edited directly. No update is sent
//! to the server until a Broadcast is sent
virtual XmppPresence* outgoing_presence() = 0;
//! Broadcasts that the user is available.
//! Nothing with respect to presence is sent until this is called.
virtual XmppReturnStatus BroadcastPresence() = 0;
//! Sends a directed presence to a Jid
//! Note that the client doesn't store where directed presence notifications
//! have been sent. The server can keep the appropriate state
virtual XmppReturnStatus SendDirectedPresence(const XmppPresence* presence,
const Jid& to_jid) = 0;
// INCOMING PRESENCE STATUS --------------------------------------------------
//! Returns the number of incoming presence data recorded
virtual size_t GetIncomingPresenceCount() = 0;
//! Returns an incoming presence datum based on index
virtual const XmppPresence* GetIncomingPresence(size_t index) = 0;
//! Gets the number of presence data for a bare Jid
//! There may be a datum per resource
virtual size_t GetIncomingPresenceForJidCount(const Jid& jid) = 0;
//! Returns a single presence data for a Jid based on index
virtual const XmppPresence* GetIncomingPresenceForJid(const Jid& jid,
size_t index) = 0;
// ROSTER MANAGEMENT ---------------------------------------------------------
//! Requests an update of the roster from the server
//! This must be called to initialize the client side cache of the roster
//! After this is sent the server should keep this module apprised of any
//! changes.
virtual XmppReturnStatus RequestRosterUpdate() = 0;
//! Returns the number of contacts in the roster
virtual size_t GetRosterContactCount() = 0;
//! Returns a contact by index
virtual const XmppRosterContact* GetRosterContact(size_t index) = 0;
//! Finds a contact by Jid
virtual const XmppRosterContact* FindRosterContact(const Jid& jid) = 0;
//! Send a request to the server to add a contact
//! Note that the contact won't show up in the roster until the server can
//! respond. This happens async when the socket is being serviced
virtual XmppReturnStatus RequestRosterChange(
const XmppRosterContact* contact) = 0;
//! Request that the server remove a contact
//! The jabber protocol specifies that the server should also cancel any
//! subscriptions when this is done. Like adding, this contact won't be
//! removed until the server responds.
virtual XmppReturnStatus RequestRosterRemove(const Jid& jid) = 0;
// SUBSCRIPTION MANAGEMENT ---------------------------------------------------
//! Request a subscription to presence notifications form a Jid
virtual XmppReturnStatus RequestSubscription(const Jid& jid) = 0;
//! Cancel a subscription to presence notifications from a Jid
virtual XmppReturnStatus CancelSubscription(const Jid& jid) = 0;
//! Approve a request to deliver presence notifications to a jid
virtual XmppReturnStatus ApproveSubscriber(const Jid& jid) = 0;
//! Deny or cancel presence notification deliver to a jid
virtual XmppReturnStatus CancelSubscriber(const Jid& jid) = 0;
};
}
#endif // WEBRTC_LIBJINGLE_XMPP_ROSTERMODULE_H_

View File

@ -1,832 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/libjingle/xmpp/rostermodule.h"
#include "webrtc/libjingle/xmpp/util_unittest.h"
#include "webrtc/libjingle/xmpp/xmppengine.h"
#include "webrtc/base/gunit.h"
#define TEST_OK(x) EXPECT_EQ((x),XMPP_RETURN_OK)
#define TEST_BADARGUMENT(x) EXPECT_EQ((x),XMPP_RETURN_BADARGUMENT)
namespace buzz {
class RosterModuleTest;
static void
WriteString(std::ostream& os, const std::string& str) {
os<<str;
}
static void
WriteSubscriptionState(std::ostream& os, XmppSubscriptionState state)
{
switch (state) {
case XMPP_SUBSCRIPTION_NONE:
os<<"none";
break;
case XMPP_SUBSCRIPTION_NONE_ASKED:
os<<"none_asked";
break;
case XMPP_SUBSCRIPTION_TO:
os<<"to";
break;
case XMPP_SUBSCRIPTION_FROM:
os<<"from";
break;
case XMPP_SUBSCRIPTION_FROM_ASKED:
os<<"from_asked";
break;
case XMPP_SUBSCRIPTION_BOTH:
os<<"both";
break;
default:
os<<"unknown";
break;
}
}
static void
WriteSubscriptionRequestType(std::ostream& os,
XmppSubscriptionRequestType type) {
switch(type) {
case XMPP_REQUEST_SUBSCRIBE:
os<<"subscribe";
break;
case XMPP_REQUEST_UNSUBSCRIBE:
os<<"unsubscribe";
break;
case XMPP_REQUEST_SUBSCRIBED:
os<<"subscribed";
break;
case XMPP_REQUEST_UNSUBSCRIBED:
os<<"unsubscribe";
break;
default:
os<<"unknown";
break;
}
}
static void
WritePresenceShow(std::ostream& os, XmppPresenceShow show) {
switch(show) {
case XMPP_PRESENCE_AWAY:
os<<"away";
break;
case XMPP_PRESENCE_CHAT:
os<<"chat";
break;
case XMPP_PRESENCE_DND:
os<<"dnd";
break;
case XMPP_PRESENCE_XA:
os<<"xa";
break;
case XMPP_PRESENCE_DEFAULT:
os<<"[default]";
break;
default:
os<<"[unknown]";
break;
}
}
static void
WritePresence(std::ostream& os, const XmppPresence* presence) {
if (presence == NULL) {
os<<"NULL";
return;
}
os<<"[Presence jid:";
WriteString(os, presence->jid().Str());
os<<" available:"<<presence->available();
os<<" presence_show:";
WritePresenceShow(os, presence->presence_show());
os<<" priority:"<<presence->priority();
os<<" status:";
WriteString(os, presence->status());
os<<"]"<<presence->raw_xml()->Str();
}
static void
WriteContact(std::ostream& os, const XmppRosterContact* contact) {
if (contact == NULL) {
os<<"NULL";
return;
}
os<<"[Contact jid:";
WriteString(os, contact->jid().Str());
os<<" name:";
WriteString(os, contact->name());
os<<" subscription_state:";
WriteSubscriptionState(os, contact->subscription_state());
os<<" groups:[";
for(size_t i=0; i < contact->GetGroupCount(); ++i) {
os<<(i==0?"":", ");
WriteString(os, contact->GetGroup(i));
}
os<<"]]"<<contact->raw_xml()->Str();
}
//! This session handler saves all calls to a string. These are events and
//! data delivered form the engine to application code.
class XmppTestRosterHandler : public XmppRosterHandler {
public:
XmppTestRosterHandler() {}
virtual ~XmppTestRosterHandler() {}
virtual void SubscriptionRequest(XmppRosterModule*,
const Jid& requesting_jid,
XmppSubscriptionRequestType type,
const XmlElement* raw_xml) {
ss_<<"[SubscriptionRequest Jid:" << requesting_jid.Str()<<" type:";
WriteSubscriptionRequestType(ss_, type);
ss_<<"]"<<raw_xml->Str();
}
//! Some type of presence error has occured
virtual void SubscriptionError(XmppRosterModule*,
const Jid& from,
const XmlElement* raw_xml) {
ss_<<"[SubscriptionError from:"<<from.Str()<<"]"<<raw_xml->Str();
}
virtual void RosterError(XmppRosterModule*,
const XmlElement* raw_xml) {
ss_<<"[RosterError]"<<raw_xml->Str();
}
//! New presence information has come in
//! The user is notified with the presence object directly. This info is also
//! added to the store accessable from the engine.
virtual void IncomingPresenceChanged(XmppRosterModule*,
const XmppPresence* presence) {
ss_<<"[IncomingPresenceChanged presence:";
WritePresence(ss_, presence);
ss_<<"]";
}
//! A contact has changed
//! This indicates that the data for a contact may have changed. No
//! contacts have been added or removed.
virtual void ContactChanged(XmppRosterModule* roster,
const XmppRosterContact* old_contact,
size_t index) {
ss_<<"[ContactChanged old_contact:";
WriteContact(ss_, old_contact);
ss_<<" index:"<<index<<" new_contact:";
WriteContact(ss_, roster->GetRosterContact(index));
ss_<<"]";
}
//! A set of contacts have been added
//! These contacts may have been added in response to the original roster
//! request or due to a "roster push" from the server.
virtual void ContactsAdded(XmppRosterModule* roster,
size_t index, size_t number) {
ss_<<"[ContactsAdded index:"<<index<<" number:"<<number;
for (size_t i = 0; i < number; ++i) {
ss_<<" "<<(index+i)<<":";
WriteContact(ss_, roster->GetRosterContact(index+i));
}
ss_<<"]";
}
//! A contact has been removed
//! This contact has been removed form the list.
virtual void ContactRemoved(XmppRosterModule*,
const XmppRosterContact* removed_contact,
size_t index) {
ss_<<"[ContactRemoved old_contact:";
WriteContact(ss_, removed_contact);
ss_<<" index:"<<index<<"]";
}
std::string Str() {
return ss_.str();
}
std::string StrClear() {
std::string result = ss_.str();
ss_.str("");
return result;
}
private:
std::stringstream ss_;
};
//! This is the class that holds all of the unit test code for the
//! roster module
class RosterModuleTest : public testing::Test {
public:
RosterModuleTest() {}
static void RunLogin(RosterModuleTest* obj, XmppEngine* engine,
XmppTestHandler* handler) {
// Needs to be similar to XmppEngineTest::RunLogin
}
};
TEST_F(RosterModuleTest, TestPresence) {
XmlElement* status = new XmlElement(QN_GOOGLE_PSTN_CONFERENCE_STATUS);
status->AddAttr(QN_STATUS, STR_PSTN_CONFERENCE_STATUS_CONNECTING);
XmlElement presence_xml(QN_PRESENCE);
presence_xml.AddElement(status);
std::unique_ptr<XmppPresence> presence(XmppPresence::Create());
presence->set_raw_xml(&presence_xml);
EXPECT_EQ(presence->connection_status(), XMPP_CONNECTION_STATUS_CONNECTING);
}
TEST_F(RosterModuleTest, TestOutgoingPresence) {
std::stringstream dump;
std::unique_ptr<XmppEngine> engine(XmppEngine::Create());
XmppTestHandler handler(engine.get());
XmppTestRosterHandler roster_handler;
std::unique_ptr<XmppRosterModule> roster(XmppRosterModule::Create());
roster->set_roster_handler(&roster_handler);
// Configure the roster module
roster->RegisterEngine(engine.get());
// Set up callbacks
engine->SetOutputHandler(&handler);
engine->AddStanzaHandler(&handler);
engine->SetSessionHandler(&handler);
// Set up minimal login info
engine->SetUser(Jid("david@my-server"));
// engine->SetPassword("david");
// Do the whole login handshake
RunLogin(this, engine.get(), &handler);
EXPECT_EQ("", handler.OutputActivity());
// Set some presence and broadcast it
TEST_OK(roster->outgoing_presence()->
set_available(XMPP_PRESENCE_AVAILABLE));
TEST_OK(roster->outgoing_presence()->set_priority(-37));
TEST_OK(roster->outgoing_presence()->set_presence_show(XMPP_PRESENCE_DND));
TEST_OK(roster->outgoing_presence()->
set_status("I'm off to the races!<>&"));
TEST_OK(roster->BroadcastPresence());
EXPECT_EQ(roster_handler.StrClear(), "");
EXPECT_EQ(handler.OutputActivity(),
"<presence>"
"<priority>-37</priority>"
"<show>dnd</show>"
"<status>I'm off to the races!&lt;&gt;&amp;</status>"
"</presence>");
EXPECT_EQ(handler.SessionActivity(), "");
// Try some more
TEST_OK(roster->outgoing_presence()->
set_available(XMPP_PRESENCE_UNAVAILABLE));
TEST_OK(roster->outgoing_presence()->set_priority(0));
TEST_OK(roster->outgoing_presence()->set_presence_show(XMPP_PRESENCE_XA));
TEST_OK(roster->outgoing_presence()->set_status("Gone fishin'"));
TEST_OK(roster->BroadcastPresence());
EXPECT_EQ(roster_handler.StrClear(), "");
EXPECT_EQ(handler.OutputActivity(),
"<presence type=\"unavailable\">"
"<show>xa</show>"
"<status>Gone fishin'</status>"
"</presence>");
EXPECT_EQ(handler.SessionActivity(), "");
// Okay -- we are back on
TEST_OK(roster->outgoing_presence()->
set_available(XMPP_PRESENCE_AVAILABLE));
TEST_BADARGUMENT(roster->outgoing_presence()->set_priority(128));
TEST_OK(roster->outgoing_presence()->
set_presence_show(XMPP_PRESENCE_DEFAULT));
TEST_OK(roster->outgoing_presence()->set_status("Cookin' wit gas"));
TEST_OK(roster->BroadcastPresence());
EXPECT_EQ(roster_handler.StrClear(), "");
EXPECT_EQ(handler.OutputActivity(),
"<presence>"
"<status>Cookin' wit gas</status>"
"</presence>");
EXPECT_EQ(handler.SessionActivity(), "");
// Set it via XML
XmlElement presence_input(QN_PRESENCE);
presence_input.AddAttr(QN_TYPE, "unavailable");
presence_input.AddElement(new XmlElement(QN_PRIORITY));
presence_input.AddText("42", 1);
presence_input.AddElement(new XmlElement(QN_STATUS));
presence_input.AddAttr(QN_XML_LANG, "es", 1);
presence_input.AddText("Hola Amigos!", 1);
presence_input.AddElement(new XmlElement(QN_STATUS));
presence_input.AddText("Hey there, friend!", 1);
TEST_OK(roster->outgoing_presence()->set_raw_xml(&presence_input));
TEST_OK(roster->BroadcastPresence());
WritePresence(dump, roster->outgoing_presence());
EXPECT_EQ(dump.str(),
"[Presence jid: available:0 presence_show:[default] "
"priority:42 status:Hey there, friend!]"
"<cli:presence type=\"unavailable\" xmlns:cli=\"jabber:client\">"
"<cli:priority>42</cli:priority>"
"<cli:status xml:lang=\"es\">Hola Amigos!</cli:status>"
"<cli:status>Hey there, friend!</cli:status>"
"</cli:presence>");
dump.str("");
EXPECT_EQ(roster_handler.StrClear(), "");
EXPECT_EQ(handler.OutputActivity(),
"<presence type=\"unavailable\">"
"<priority>42</priority>"
"<status xml:lang=\"es\">Hola Amigos!</status>"
"<status>Hey there, friend!</status>"
"</presence>");
EXPECT_EQ(handler.SessionActivity(), "");
// Construct a directed presence
std::unique_ptr<XmppPresence> directed_presence(XmppPresence::Create());
TEST_OK(directed_presence->set_available(XMPP_PRESENCE_AVAILABLE));
TEST_OK(directed_presence->set_priority(120));
TEST_OK(directed_presence->set_status("*very* available"));
TEST_OK(roster->SendDirectedPresence(directed_presence.get(),
Jid("myhoney@honey.net")));
EXPECT_EQ(roster_handler.StrClear(), "");
EXPECT_EQ(handler.OutputActivity(),
"<presence to=\"myhoney@honey.net\">"
"<priority>120</priority>"
"<status>*very* available</status>"
"</presence>");
EXPECT_EQ(handler.SessionActivity(), "");
}
TEST_F(RosterModuleTest, TestIncomingPresence) {
std::unique_ptr<XmppEngine> engine(XmppEngine::Create());
XmppTestHandler handler(engine.get());
XmppTestRosterHandler roster_handler;
std::unique_ptr<XmppRosterModule> roster(XmppRosterModule::Create());
roster->set_roster_handler(&roster_handler);
// Configure the roster module
roster->RegisterEngine(engine.get());
// Set up callbacks
engine->SetOutputHandler(&handler);
engine->AddStanzaHandler(&handler);
engine->SetSessionHandler(&handler);
// Set up minimal login info
engine->SetUser(Jid("david@my-server"));
// engine->SetPassword("david");
// Do the whole login handshake
RunLogin(this, engine.get(), &handler);
EXPECT_EQ("", handler.OutputActivity());
// Load up with a bunch of data
std::string input;
input = "<presence from='maude@example.net/studio' "
"to='david@my-server/test'/>"
"<presence from='walter@example.net/home' "
"to='david@my-server/test'>"
"<priority>-10</priority>"
"<show>xa</show>"
"<status>Off bowling</status>"
"</presence>"
"<presence from='walter@example.net/alley' "
"to='david@my-server/test'>"
"<priority>20</priority>"
"<status>Looking for toes...</status>"
"</presence>"
"<presence from='donny@example.net/alley' "
"to='david@my-server/test'>"
"<priority>10</priority>"
"<status>Throwing rocks</status>"
"</presence>";
TEST_OK(engine->HandleInput(input.c_str(), input.length()));
EXPECT_EQ(roster_handler.StrClear(),
"[IncomingPresenceChanged "
"presence:[Presence jid:maude@example.net/studio available:1 "
"presence_show:[default] priority:0 status:]"
"<cli:presence from=\"maude@example.net/studio\" "
"to=\"david@my-server/test\" "
"xmlns:cli=\"jabber:client\"/>]"
"[IncomingPresenceChanged "
"presence:[Presence jid:walter@example.net/home available:1 "
"presence_show:xa priority:-10 status:Off bowling]"
"<cli:presence from=\"walter@example.net/home\" "
"to=\"david@my-server/test\" "
"xmlns:cli=\"jabber:client\">"
"<cli:priority>-10</cli:priority>"
"<cli:show>xa</cli:show>"
"<cli:status>Off bowling</cli:status>"
"</cli:presence>]"
"[IncomingPresenceChanged "
"presence:[Presence jid:walter@example.net/alley available:1 "
"presence_show:[default] "
"priority:20 status:Looking for toes...]"
"<cli:presence from=\"walter@example.net/alley\" "
"to=\"david@my-server/test\" "
"xmlns:cli=\"jabber:client\">"
"<cli:priority>20</cli:priority>"
"<cli:status>Looking for toes...</cli:status>"
"</cli:presence>]"
"[IncomingPresenceChanged "
"presence:[Presence jid:donny@example.net/alley available:1 "
"presence_show:[default] priority:10 status:Throwing rocks]"
"<cli:presence from=\"donny@example.net/alley\" "
"to=\"david@my-server/test\" "
"xmlns:cli=\"jabber:client\">"
"<cli:priority>10</cli:priority>"
"<cli:status>Throwing rocks</cli:status>"
"</cli:presence>]");
EXPECT_EQ(handler.OutputActivity(), "");
handler.SessionActivity(); // Ignore the session output
// Now look at the data structure we've built
EXPECT_EQ(roster->GetIncomingPresenceCount(), static_cast<size_t>(4));
EXPECT_EQ(roster->GetIncomingPresenceForJidCount(Jid("maude@example.net")),
static_cast<size_t>(1));
EXPECT_EQ(roster->GetIncomingPresenceForJidCount(Jid("walter@example.net")),
static_cast<size_t>(2));
const XmppPresence * presence;
presence = roster->GetIncomingPresenceForJid(Jid("walter@example.net"), 1);
std::stringstream dump;
WritePresence(dump, presence);
EXPECT_EQ(dump.str(),
"[Presence jid:walter@example.net/alley available:1 "
"presence_show:[default] priority:20 status:Looking for toes...]"
"<cli:presence from=\"walter@example.net/alley\" "
"to=\"david@my-server/test\" "
"xmlns:cli=\"jabber:client\">"
"<cli:priority>20</cli:priority>"
"<cli:status>Looking for toes...</cli:status>"
"</cli:presence>");
dump.str("");
// Maude took off...
input = "<presence from='maude@example.net/studio' "
"to='david@my-server/test' "
"type='unavailable'>"
"<status>Stealing my rug back</status>"
"<priority>-10</priority>"
"</presence>";
TEST_OK(engine->HandleInput(input.c_str(), input.length()));
EXPECT_EQ(roster_handler.StrClear(),
"[IncomingPresenceChanged "
"presence:[Presence jid:maude@example.net/studio available:0 "
"presence_show:[default] priority:-10 "
"status:Stealing my rug back]"
"<cli:presence from=\"maude@example.net/studio\" "
"to=\"david@my-server/test\" type=\"unavailable\" "
"xmlns:cli=\"jabber:client\">"
"<cli:status>Stealing my rug back</cli:status>"
"<cli:priority>-10</cli:priority>"
"</cli:presence>]");
EXPECT_EQ(handler.OutputActivity(), "");
handler.SessionActivity(); // Ignore the session output
}
TEST_F(RosterModuleTest, TestPresenceSubscription) {
std::unique_ptr<XmppEngine> engine(XmppEngine::Create());
XmppTestHandler handler(engine.get());
XmppTestRosterHandler roster_handler;
std::unique_ptr<XmppRosterModule> roster(XmppRosterModule::Create());
roster->set_roster_handler(&roster_handler);
// Configure the roster module
roster->RegisterEngine(engine.get());
// Set up callbacks
engine->SetOutputHandler(&handler);
engine->AddStanzaHandler(&handler);
engine->SetSessionHandler(&handler);
// Set up minimal login info
engine->SetUser(Jid("david@my-server"));
// engine->SetPassword("david");
// Do the whole login handshake
RunLogin(this, engine.get(), &handler);
EXPECT_EQ("", handler.OutputActivity());
// Test incoming requests
std::string input;
input =
"<presence from='maude@example.net' type='subscribe'/>"
"<presence from='maude@example.net' type='unsubscribe'/>"
"<presence from='maude@example.net' type='subscribed'/>"
"<presence from='maude@example.net' type='unsubscribed'/>";
TEST_OK(engine->HandleInput(input.c_str(), input.length()));
EXPECT_EQ(roster_handler.StrClear(),
"[SubscriptionRequest Jid:maude@example.net type:subscribe]"
"<cli:presence from=\"maude@example.net\" type=\"subscribe\" "
"xmlns:cli=\"jabber:client\"/>"
"[SubscriptionRequest Jid:maude@example.net type:unsubscribe]"
"<cli:presence from=\"maude@example.net\" type=\"unsubscribe\" "
"xmlns:cli=\"jabber:client\"/>"
"[SubscriptionRequest Jid:maude@example.net type:subscribed]"
"<cli:presence from=\"maude@example.net\" type=\"subscribed\" "
"xmlns:cli=\"jabber:client\"/>"
"[SubscriptionRequest Jid:maude@example.net type:unsubscribe]"
"<cli:presence from=\"maude@example.net\" type=\"unsubscribed\" "
"xmlns:cli=\"jabber:client\"/>");
EXPECT_EQ(handler.OutputActivity(), "");
handler.SessionActivity(); // Ignore the session output
TEST_OK(roster->RequestSubscription(Jid("maude@example.net")));
TEST_OK(roster->CancelSubscription(Jid("maude@example.net")));
TEST_OK(roster->ApproveSubscriber(Jid("maude@example.net")));
TEST_OK(roster->CancelSubscriber(Jid("maude@example.net")));
EXPECT_EQ(roster_handler.StrClear(), "");
EXPECT_EQ(handler.OutputActivity(),
"<presence to=\"maude@example.net\" type=\"subscribe\"/>"
"<presence to=\"maude@example.net\" type=\"unsubscribe\"/>"
"<presence to=\"maude@example.net\" type=\"subscribed\"/>"
"<presence to=\"maude@example.net\" type=\"unsubscribed\"/>");
EXPECT_EQ(handler.SessionActivity(), "");
}
TEST_F(RosterModuleTest, TestRosterReceive) {
std::unique_ptr<XmppEngine> engine(XmppEngine::Create());
XmppTestHandler handler(engine.get());
XmppTestRosterHandler roster_handler;
std::unique_ptr<XmppRosterModule> roster(XmppRosterModule::Create());
roster->set_roster_handler(&roster_handler);
// Configure the roster module
roster->RegisterEngine(engine.get());
// Set up callbacks
engine->SetOutputHandler(&handler);
engine->AddStanzaHandler(&handler);
engine->SetSessionHandler(&handler);
// Set up minimal login info
engine->SetUser(Jid("david@my-server"));
// engine->SetPassword("david");
// Do the whole login handshake
RunLogin(this, engine.get(), &handler);
EXPECT_EQ("", handler.OutputActivity());
// Request a roster update
TEST_OK(roster->RequestRosterUpdate());
EXPECT_EQ(roster_handler.StrClear(),"");
EXPECT_EQ(handler.OutputActivity(),
"<iq type=\"get\" id=\"2\">"
"<query xmlns=\"jabber:iq:roster\"/>"
"</iq>");
EXPECT_EQ(handler.SessionActivity(), "");
// Prime the roster with a starting set
std::string input =
"<iq to='david@myserver/test' type='result' id='2'>"
"<query xmlns='jabber:iq:roster'>"
"<item jid='maude@example.net' "
"name='Maude Lebowski' "
"subscription='none' "
"ask='subscribe'>"
"<group>Business Partners</group>"
"</item>"
"<item jid='walter@example.net' "
"name='Walter Sobchak' "
"subscription='both'>"
"<group>Friends</group>"
"<group>Bowling Team</group>"
"<group>Bowling League</group>"
"</item>"
"<item jid='donny@example.net' "
"name='Donny' "
"subscription='both'>"
"<group>Friends</group>"
"<group>Bowling Team</group>"
"<group>Bowling League</group>"
"</item>"
"<item jid='jeffrey@example.net' "
"name='The Big Lebowski' "
"subscription='to'>"
"<group>Business Partners</group>"
"</item>"
"<item jid='jesus@example.net' "
"name='Jesus Quintana' "
"subscription='from'>"
"<group>Bowling League</group>"
"</item>"
"</query>"
"</iq>";
TEST_OK(engine->HandleInput(input.c_str(), input.length()));
EXPECT_EQ(roster_handler.StrClear(),
"[ContactsAdded index:0 number:5 "
"0:[Contact jid:maude@example.net name:Maude Lebowski "
"subscription_state:none_asked "
"groups:[Business Partners]]"
"<ros:item jid=\"maude@example.net\" name=\"Maude Lebowski\" "
"subscription=\"none\" ask=\"subscribe\" "
"xmlns:ros=\"jabber:iq:roster\">"
"<ros:group>Business Partners</ros:group>"
"</ros:item> "
"1:[Contact jid:walter@example.net name:Walter Sobchak "
"subscription_state:both "
"groups:[Friends, Bowling Team, Bowling League]]"
"<ros:item jid=\"walter@example.net\" name=\"Walter Sobchak\" "
"subscription=\"both\" "
"xmlns:ros=\"jabber:iq:roster\">"
"<ros:group>Friends</ros:group>"
"<ros:group>Bowling Team</ros:group>"
"<ros:group>Bowling League</ros:group>"
"</ros:item> "
"2:[Contact jid:donny@example.net name:Donny "
"subscription_state:both "
"groups:[Friends, Bowling Team, Bowling League]]"
"<ros:item jid=\"donny@example.net\" name=\"Donny\" "
"subscription=\"both\" "
"xmlns:ros=\"jabber:iq:roster\">"
"<ros:group>Friends</ros:group>"
"<ros:group>Bowling Team</ros:group>"
"<ros:group>Bowling League</ros:group>"
"</ros:item> "
"3:[Contact jid:jeffrey@example.net name:The Big Lebowski "
"subscription_state:to "
"groups:[Business Partners]]"
"<ros:item jid=\"jeffrey@example.net\" name=\"The Big Lebowski\" "
"subscription=\"to\" "
"xmlns:ros=\"jabber:iq:roster\">"
"<ros:group>Business Partners</ros:group>"
"</ros:item> "
"4:[Contact jid:jesus@example.net name:Jesus Quintana "
"subscription_state:from groups:[Bowling League]]"
"<ros:item jid=\"jesus@example.net\" name=\"Jesus Quintana\" "
"subscription=\"from\" xmlns:ros=\"jabber:iq:roster\">"
"<ros:group>Bowling League</ros:group>"
"</ros:item>]");
EXPECT_EQ(handler.OutputActivity(), "");
EXPECT_EQ(handler.SessionActivity(), "");
// Request that someone be added
std::unique_ptr<XmppRosterContact> contact(XmppRosterContact::Create());
TEST_OK(contact->set_jid(Jid("brandt@example.net")));
TEST_OK(contact->set_name("Brandt"));
TEST_OK(contact->AddGroup("Business Partners"));
TEST_OK(contact->AddGroup("Watchers"));
TEST_OK(contact->AddGroup("Friends"));
TEST_OK(contact->RemoveGroup("Friends")); // Maybe not...
TEST_OK(roster->RequestRosterChange(contact.get()));
EXPECT_EQ(roster_handler.StrClear(), "");
EXPECT_EQ(handler.OutputActivity(),
"<iq type=\"set\" id=\"3\">"
"<query xmlns=\"jabber:iq:roster\">"
"<item jid=\"brandt@example.net\" "
"name=\"Brandt\">"
"<group>Business Partners</group>"
"<group>Watchers</group>"
"</item>"
"</query>"
"</iq>");
EXPECT_EQ(handler.SessionActivity(), "");
// Get the push from the server
input =
"<iq type='result' to='david@my-server/test' id='3'/>"
"<iq type='set' id='server_1'>"
"<query xmlns='jabber:iq:roster'>"
"<item jid='brandt@example.net' "
"name='Brandt' "
"subscription='none'>"
"<group>Business Partners</group>"
"<group>Watchers</group>"
"</item>"
"</query>"
"</iq>";
TEST_OK(engine->HandleInput(input.c_str(), input.length()));
EXPECT_EQ(roster_handler.StrClear(),
"[ContactsAdded index:5 number:1 "
"5:[Contact jid:brandt@example.net name:Brandt "
"subscription_state:none "
"groups:[Business Partners, Watchers]]"
"<ros:item jid=\"brandt@example.net\" name=\"Brandt\" "
"subscription=\"none\" "
"xmlns:ros=\"jabber:iq:roster\">"
"<ros:group>Business Partners</ros:group>"
"<ros:group>Watchers</ros:group>"
"</ros:item>]");
EXPECT_EQ(handler.OutputActivity(),
"<iq type=\"result\" id=\"server_1\"/>");
EXPECT_EQ(handler.SessionActivity(), "");
// Get a contact update
input =
"<iq type='set' id='server_2'>"
"<query xmlns='jabber:iq:roster'>"
"<item jid='walter@example.net' "
"name='Walter Sobchak' "
"subscription='both'>"
"<group>Friends</group>"
"<group>Bowling Team</group>"
"<group>Bowling League</group>"
"<group>Not wrong, just an...</group>"
"</item>"
"</query>"
"</iq>";
TEST_OK(engine->HandleInput(input.c_str(), input.length()));
EXPECT_EQ(roster_handler.StrClear(),
"[ContactChanged "
"old_contact:[Contact jid:walter@example.net name:Walter Sobchak "
"subscription_state:both "
"groups:[Friends, Bowling Team, Bowling League]]"
"<ros:item jid=\"walter@example.net\" name=\"Walter Sobchak\" "
"subscription=\"both\" xmlns:ros=\"jabber:iq:roster\">"
"<ros:group>Friends</ros:group>"
"<ros:group>Bowling Team</ros:group>"
"<ros:group>Bowling League</ros:group>"
"</ros:item> "
"index:1 "
"new_contact:[Contact jid:walter@example.net name:Walter Sobchak "
"subscription_state:both "
"groups:[Friends, Bowling Team, Bowling League, "
"Not wrong, just an...]]"
"<ros:item jid=\"walter@example.net\" name=\"Walter Sobchak\" "
"subscription=\"both\" xmlns:ros=\"jabber:iq:roster\">"
"<ros:group>Friends</ros:group>"
"<ros:group>Bowling Team</ros:group>"
"<ros:group>Bowling League</ros:group>"
"<ros:group>Not wrong, just an...</ros:group>"
"</ros:item>]");
EXPECT_EQ(handler.OutputActivity(),
"<iq type=\"result\" id=\"server_2\"/>");
EXPECT_EQ(handler.SessionActivity(), "");
// Remove a contact
TEST_OK(roster->RequestRosterRemove(Jid("jesus@example.net")));
EXPECT_EQ(roster_handler.StrClear(), "");
EXPECT_EQ(handler.OutputActivity(),
"<iq type=\"set\" id=\"4\">"
"<query xmlns=\"jabber:iq:roster\" jid=\"jesus@example.net\" "
"subscription=\"remove\"/>"
"</iq>");
EXPECT_EQ(handler.SessionActivity(), "");
// Response from the server
input =
"<iq type='result' to='david@my-server/test' id='4'/>"
"<iq type='set' id='server_3'>"
"<query xmlns='jabber:iq:roster'>"
"<item jid='jesus@example.net' "
"subscription='remove'>"
"</item>"
"</query>"
"</iq>";
TEST_OK(engine->HandleInput(input.c_str(), input.length()));
EXPECT_EQ(roster_handler.StrClear(),
"[ContactRemoved "
"old_contact:[Contact jid:jesus@example.net name:Jesus Quintana "
"subscription_state:from groups:[Bowling League]]"
"<ros:item jid=\"jesus@example.net\" name=\"Jesus Quintana\" "
"subscription=\"from\" "
"xmlns:ros=\"jabber:iq:roster\">"
"<ros:group>Bowling League</ros:group>"
"</ros:item> index:4]");
EXPECT_EQ(handler.OutputActivity(),
"<iq type=\"result\" id=\"server_3\"/>");
EXPECT_EQ(handler.SessionActivity(), "");
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,287 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_XMPPTHREAD_H_
#define WEBRTC_LIBJINGLE_XMPP_XMPPTHREAD_H_
#include <memory>
#include "webrtc/libjingle/xmpp/moduleimpl.h"
#include "webrtc/libjingle/xmpp/rostermodule.h"
namespace buzz {
//! Presence Information
//! This class stores both presence information for outgoing presence and is
//! returned by methods in XmppRosterModule to represent received incoming
//! presence information. When this class is writeable (non-const) then each
//! update to any property will set the inner xml. Setting the raw_xml will
//! rederive all of the other properties.
class XmppPresenceImpl : public XmppPresence {
public:
virtual ~XmppPresenceImpl() {}
//! The from Jid of for the presence information.
//! Typically this will be a full Jid with resource specified. For outgoing
//! presence this should remain JID_NULL and will be scrubbed from the
//! stanza when being sent.
virtual const Jid jid() const;
//! Is the contact available?
virtual XmppPresenceAvailable available() const;
//! Sets if the user is available or not
virtual XmppReturnStatus set_available(XmppPresenceAvailable available);
//! The show value of the presence info
virtual XmppPresenceShow presence_show() const;
//! Set the presence show value
virtual XmppReturnStatus set_presence_show(XmppPresenceShow show);
//! The Priority of the presence info
virtual int priority() const;
//! Set the priority of the presence
virtual XmppReturnStatus set_priority(int priority);
//! The plain text status of the presence info.
//! If there are multiple status because of language, this will either be a
//! status that is not tagged for language or the first available
virtual const std::string status() const;
//! Sets the status for the presence info.
//! If there is more than one status present already then this will remove
//! them all and replace it with one status element we no specified language
virtual XmppReturnStatus set_status(const std::string& status);
//! The connection status
virtual XmppPresenceConnectionStatus connection_status() const;
//! The focus obfuscated GAIA id
virtual const std::string google_user_id() const;
//! The nickname in the presence
virtual const std::string nickname() const;
//! The raw xml of the presence update
virtual const XmlElement* raw_xml() const;
//! Sets the raw presence stanza for the presence update
//! This will cause all other data items in this structure to be rederived
virtual XmppReturnStatus set_raw_xml(const XmlElement * xml);
private:
XmppPresenceImpl();
friend class XmppPresence;
friend class XmppRosterModuleImpl;
void CreateRawXmlSkeleton();
// Store everything in the XML element. If this becomes a perf issue we can
// cache the data.
std::unique_ptr<XmlElement> raw_xml_;
};
//! A contact as given by the server
class XmppRosterContactImpl : public XmppRosterContact {
public:
virtual ~XmppRosterContactImpl() {}
//! The jid for the contact.
//! Typically this will be a bare Jid.
virtual const Jid jid() const;
//! Sets the jid for the roster contact update
virtual XmppReturnStatus set_jid(const Jid& jid);
//! The name (nickname) stored for this contact
virtual const std::string name() const;
//! Sets the name
virtual XmppReturnStatus set_name(const std::string& name);
//! The Presence subscription state stored on the server for this contact
//! This is never settable and will be ignored when generating a roster
//! add/update request
virtual XmppSubscriptionState subscription_state() const;
//! The number of Groups applied to this contact
virtual size_t GetGroupCount() const;
//! Gets a Group applied to the contact based on index.
virtual const std::string GetGroup(size_t index) const;
//! Adds a group to this contact.
//! This will return a no error if the group is already present.
virtual XmppReturnStatus AddGroup(const std::string& group);
//! Removes a group from the contact.
//! This will return no error if the group isn't there
virtual XmppReturnStatus RemoveGroup(const std::string& group);
//! The raw xml for this roster contact
virtual const XmlElement* raw_xml() const;
//! Sets the raw presence stanza for the presence update
//! This will cause all other data items in this structure to be rederived
virtual XmppReturnStatus set_raw_xml(const XmlElement * xml);
private:
XmppRosterContactImpl();
void CreateRawXmlSkeleton();
void SetXmlFromWire(const XmlElement * xml);
void ResetGroupCache();
bool FindGroup(const std::string& group,
XmlElement** element,
XmlChild** child_before);
friend class XmppRosterContact;
friend class XmppRosterModuleImpl;
int group_count_;
int group_index_returned_;
XmlElement * group_returned_;
std::unique_ptr<XmlElement> raw_xml_;
};
//! An XmppModule for handle roster and presence functionality
class XmppRosterModuleImpl : public XmppModuleImpl,
public XmppRosterModule, public XmppIqHandler {
public:
virtual ~XmppRosterModuleImpl();
IMPLEMENT_XMPPMODULE
//! Sets the roster handler (callbacks) for the module
virtual XmppReturnStatus set_roster_handler(XmppRosterHandler * handler);
//! Gets the roster handler for the module
virtual XmppRosterHandler* roster_handler();
// USER PRESENCE STATE -------------------------------------------------------
//! Gets the aggregate outgoing presence
//! This object is non-const and be edited directly. No update is sent
//! to the server until a Broadcast is sent
virtual XmppPresence* outgoing_presence();
//! Broadcasts that the user is available.
//! Nothing with respect to presence is sent until this is called.
virtual XmppReturnStatus BroadcastPresence();
//! Sends a directed presence to a Jid
//! Note that the client doesn't store where directed presence notifications
//! have been sent. The server can keep the appropriate state
virtual XmppReturnStatus SendDirectedPresence(const XmppPresence* presence,
const Jid& to_jid);
// INCOMING PRESENCE STATUS --------------------------------------------------
//! Returns the number of incoming presence data recorded
virtual size_t GetIncomingPresenceCount();
//! Returns an incoming presence datum based on index
virtual const XmppPresence* GetIncomingPresence(size_t index);
//! Gets the number of presence data for a bare Jid
//! There may be a datum per resource
virtual size_t GetIncomingPresenceForJidCount(const Jid& jid);
//! Returns a single presence data for a Jid based on index
virtual const XmppPresence* GetIncomingPresenceForJid(const Jid& jid,
size_t index);
// ROSTER MANAGEMENT ---------------------------------------------------------
//! Requests an update of the roster from the server
//! This must be called to initialize the client side cache of the roster
//! After this is sent the server should keep this module apprised of any
//! changes.
virtual XmppReturnStatus RequestRosterUpdate();
//! Returns the number of contacts in the roster
virtual size_t GetRosterContactCount();
//! Returns a contact by index
virtual const XmppRosterContact* GetRosterContact(size_t index);
//! Finds a contact by Jid
virtual const XmppRosterContact* FindRosterContact(const Jid& jid);
//! Send a request to the server to add a contact
//! Note that the contact won't show up in the roster until the server can
//! respond. This happens async when the socket is being serviced
virtual XmppReturnStatus RequestRosterChange(
const XmppRosterContact* contact);
//! Request that the server remove a contact
//! The jabber protocol specifies that the server should also cancel any
//! subscriptions when this is done. Like adding, this contact won't be
//! removed until the server responds.
virtual XmppReturnStatus RequestRosterRemove(const Jid& jid);
// SUBSCRIPTION MANAGEMENT ---------------------------------------------------
//! Request a subscription to presence notifications form a Jid
virtual XmppReturnStatus RequestSubscription(const Jid& jid);
//! Cancel a subscription to presence notifications from a Jid
virtual XmppReturnStatus CancelSubscription(const Jid& jid);
//! Approve a request to deliver presence notifications to a jid
virtual XmppReturnStatus ApproveSubscriber(const Jid& jid);
//! Deny or cancel presence notification deliver to a jid
virtual XmppReturnStatus CancelSubscriber(const Jid& jid);
// XmppIqHandler IMPLEMENTATION ----------------------------------------------
virtual void IqResponse(XmppIqCookie cookie, const XmlElement * stanza);
protected:
// XmppModuleImpl OVERRIDES --------------------------------------------------
virtual bool HandleStanza(const XmlElement *);
// PRIVATE DATA --------------------------------------------------------------
private:
friend class XmppRosterModule;
XmppRosterModuleImpl();
// Helper functions
void DeleteIncomingPresence();
void DeleteContacts();
XmppReturnStatus SendSubscriptionRequest(const Jid& jid,
const std::string& type);
void InternalSubscriptionRequest(const Jid& jid, const XmlElement* stanza,
XmppSubscriptionRequestType request_type);
void InternalIncomingPresence(const Jid& jid, const XmlElement* stanza);
void InternalIncomingPresenceError(const Jid& jid, const XmlElement* stanza);
void InternalRosterItems(const XmlElement* stanza);
// Member data
XmppPresenceImpl outgoing_presence_;
XmppRosterHandler* roster_handler_;
typedef std::vector<XmppPresenceImpl*> PresenceVector;
typedef std::map<Jid, PresenceVector*> JidPresenceVectorMap;
std::unique_ptr<JidPresenceVectorMap> incoming_presence_map_;
std::unique_ptr<PresenceVector> incoming_presence_vector_;
typedef std::vector<XmppRosterContactImpl*> ContactVector;
std::unique_ptr<ContactVector> contacts_;
};
}
#endif // WEBRTC_LIBJINGLE_XMPP_XMPPTHREAD_H_

View File

@ -1,69 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_SASLCOOKIEMECHANISM_H_
#define WEBRTC_LIBJINGLE_XMPP_SASLCOOKIEMECHANISM_H_
#include "webrtc/libjingle/xmllite/qname.h"
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/libjingle/xmpp/saslmechanism.h"
namespace buzz {
class SaslCookieMechanism : public SaslMechanism {
public:
SaslCookieMechanism(const std::string & mechanism,
const std::string & username,
const std::string & cookie,
const std::string & token_service)
: mechanism_(mechanism),
username_(username),
cookie_(cookie),
token_service_(token_service) {}
SaslCookieMechanism(const std::string & mechanism,
const std::string & username,
const std::string & cookie)
: mechanism_(mechanism),
username_(username),
cookie_(cookie),
token_service_("") {}
virtual std::string GetMechanismName() { return mechanism_; }
virtual XmlElement * StartSaslAuth() {
// send initial request
XmlElement * el = new XmlElement(QN_SASL_AUTH, true);
el->AddAttr(QN_MECHANISM, mechanism_);
if (!token_service_.empty()) {
el->AddAttr(QN_GOOGLE_AUTH_SERVICE, token_service_);
}
std::string credential;
credential.append("\0", 1);
credential.append(username_);
credential.append("\0", 1);
credential.append(cookie_);
el->AddText(Base64Encode(credential));
return el;
}
private:
std::string mechanism_;
std::string username_;
std::string cookie_;
std::string token_service_;
};
}
#endif // WEBRTC_LIBJINGLE_XMPP_SASLCOOKIEMECHANISM_H_

View File

@ -1,42 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_SASLHANDLER_H_
#define WEBRTC_LIBJINGLE_XMPP_SASLHANDLER_H_
#include <string>
#include <vector>
namespace buzz {
class XmlElement;
class SaslMechanism;
// Creates mechanisms to deal with a given mechanism
class SaslHandler {
public:
// Intended to be subclassed
virtual ~SaslHandler() {}
// Should pick the best method according to this handler
// returns the empty string if none are suitable
virtual std::string ChooseBestSaslMechanism(const std::vector<std::string> & mechanisms, bool encrypted) = 0;
// Creates a SaslMechanism for the given mechanism name (you own it
// once you get it).
// If not handled, return NULL.
virtual SaslMechanism * CreateSaslMechanism(const std::string & mechanism) = 0;
};
}
#endif // WEBRTC_LIBJINGLE_XMPP_SASLHANDLER_H_

View File

@ -1,55 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/libjingle/xmpp/saslmechanism.h"
#include "webrtc/base/base64.h"
using rtc::Base64;
namespace buzz {
XmlElement *
SaslMechanism::StartSaslAuth() {
return new XmlElement(QN_SASL_AUTH, true);
}
XmlElement *
SaslMechanism::HandleSaslChallenge(const XmlElement * challenge) {
return new XmlElement(QN_SASL_ABORT, true);
}
void
SaslMechanism::HandleSaslSuccess(const XmlElement * success) {
}
void
SaslMechanism::HandleSaslFailure(const XmlElement * failure) {
}
std::string
SaslMechanism::Base64Encode(const std::string & plain) {
return Base64::Encode(plain);
}
std::string
SaslMechanism::Base64Decode(const std::string & encoded) {
return Base64::Decode(encoded, Base64::DO_LAX);
}
std::string
SaslMechanism::Base64EncodeFromArray(const char * plain, size_t length) {
std::string result;
Base64::EncodeFromArray(plain, length, &result);
return result;
}
}

View File

@ -1,57 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_SASLMECHANISM_H_
#define WEBRTC_LIBJINGLE_XMPP_SASLMECHANISM_H_
#include <string>
namespace buzz {
class XmlElement;
// Defines a mechnanism to do SASL authentication.
// Subclass instances should have a self-contained way to present
// credentials.
class SaslMechanism {
public:
// Intended to be subclassed
virtual ~SaslMechanism() {}
// Should return the name of the SASL mechanism, e.g., "PLAIN"
virtual std::string GetMechanismName() = 0;
// Should generate the initial "auth" request. Default is just <auth/>.
virtual XmlElement * StartSaslAuth();
// Should respond to a SASL "<challenge>" request. Default is
// to abort (for mechanisms that do not do challenge-response)
virtual XmlElement * HandleSaslChallenge(const XmlElement * challenge);
// Notification of a SASL "<success>". Sometimes information
// is passed on success.
virtual void HandleSaslSuccess(const XmlElement * success);
// Notification of a SASL "<failure>". Sometimes information
// for the user is passed on failure.
virtual void HandleSaslFailure(const XmlElement * failure);
protected:
static std::string Base64Encode(const std::string & plain);
static std::string Base64Decode(const std::string & encoded);
static std::string Base64EncodeFromArray(const char * plain, size_t length);
};
}
#endif // WEBRTC_LIBJINGLE_XMPP_SASLMECHANISM_H_

View File

@ -1,48 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_SASLPLAINMECHANISM_H_
#define WEBRTC_LIBJINGLE_XMPP_SASLPLAINMECHANISM_H_
#include "webrtc/libjingle/xmpp/saslmechanism.h"
#include "webrtc/base/cryptstring.h"
namespace buzz {
class SaslPlainMechanism : public SaslMechanism {
public:
SaslPlainMechanism(const buzz::Jid user_jid, const rtc::CryptString & password) :
user_jid_(user_jid), password_(password) {}
virtual std::string GetMechanismName() { return "PLAIN"; }
virtual XmlElement * StartSaslAuth() {
// send initial request
XmlElement * el = new XmlElement(QN_SASL_AUTH, true);
el->AddAttr(QN_MECHANISM, "PLAIN");
rtc::FormatCryptString credential;
credential.Append("\0", 1);
credential.Append(user_jid_.node());
credential.Append("\0", 1);
credential.Append(&password_);
el->AddText(Base64EncodeFromArray(credential.GetData(), credential.GetLength()));
return el;
}
private:
Jid user_jid_;
rtc::CryptString password_;
};
}
#endif // WEBRTC_LIBJINGLE_XMPP_SASLPLAINMECHANISM_H_

View File

@ -1,109 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <iostream>
#include <sstream>
#include <string>
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/libjingle/xmpp/util_unittest.h"
#include "webrtc/libjingle/xmpp/xmppengine.h"
#include "webrtc/base/gunit.h"
namespace buzz {
void XmppTestHandler::WriteOutput(const char * bytes, size_t len) {
output_ << std::string(bytes, len);
}
void XmppTestHandler::StartTls(const std::string & cname) {
output_ << "[START-TLS " << cname << "]";
}
void XmppTestHandler::CloseConnection() {
output_ << "[CLOSED]";
}
void XmppTestHandler::OnStateChange(int state) {
switch (static_cast<XmppEngine::State>(state)) {
case XmppEngine::STATE_START:
session_ << "[START]";
break;
case XmppEngine::STATE_OPENING:
session_ << "[OPENING]";
break;
case XmppEngine::STATE_OPEN:
session_ << "[OPEN]";
break;
case XmppEngine::STATE_CLOSED:
session_ << "[CLOSED]";
switch (engine_->GetError(NULL)) {
case XmppEngine::ERROR_NONE:
// do nothing
break;
case XmppEngine::ERROR_XML:
session_ << "[ERROR-XML]";
break;
case XmppEngine::ERROR_STREAM:
session_ << "[ERROR-STREAM]";
break;
case XmppEngine::ERROR_VERSION:
session_ << "[ERROR-VERSION]";
break;
case XmppEngine::ERROR_UNAUTHORIZED:
session_ << "[ERROR-UNAUTHORIZED]";
break;
case XmppEngine::ERROR_TLS:
session_ << "[ERROR-TLS]";
break;
case XmppEngine::ERROR_AUTH:
session_ << "[ERROR-AUTH]";
break;
case XmppEngine::ERROR_BIND:
session_ << "[ERROR-BIND]";
break;
case XmppEngine::ERROR_CONNECTION_CLOSED:
session_ << "[ERROR-CONNECTION-CLOSED]";
break;
case XmppEngine::ERROR_DOCUMENT_CLOSED:
session_ << "[ERROR-DOCUMENT-CLOSED]";
break;
default:
break;
}
break;
default:
break;
}
}
bool XmppTestHandler::HandleStanza(const XmlElement * stanza) {
stanza_ << stanza->Str();
return true;
}
std::string XmppTestHandler::OutputActivity() {
std::string result = output_.str();
output_.str("");
return result;
}
std::string XmppTestHandler::SessionActivity() {
std::string result = session_.str();
session_.str("");
return result;
}
std::string XmppTestHandler::StanzaActivity() {
std::string result = stanza_.str();
stanza_.str("");
return result;
}
} // namespace buzz

View File

@ -1,58 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_UTIL_UNITTEST_H_
#define WEBRTC_LIBJINGLE_XMPP_UTIL_UNITTEST_H_
#include <sstream>
#include <string>
#include "webrtc/libjingle/xmpp/xmppengine.h"
namespace buzz {
// This class captures callbacks from engine.
class XmppTestHandler : public XmppOutputHandler, public XmppSessionHandler,
public XmppStanzaHandler {
public:
explicit XmppTestHandler(XmppEngine* engine) : engine_(engine) {}
virtual ~XmppTestHandler() {}
void SetEngine(XmppEngine* engine);
// Output handler
virtual void WriteOutput(const char * bytes, size_t len);
virtual void StartTls(const std::string & cname);
virtual void CloseConnection();
// Session handler
virtual void OnStateChange(int state);
// Stanza handler
virtual bool HandleStanza(const XmlElement* stanza);
std::string OutputActivity();
std::string SessionActivity();
std::string StanzaActivity();
private:
XmppEngine* engine_;
std::stringstream output_;
std::stringstream session_;
std::stringstream stanza_;
};
} // namespace buzz
inline std::ostream& operator<<(std::ostream& os, const buzz::Jid& jid) {
os << jid.Str();
return os;
}
#endif // WEBRTC_LIBJINGLE_XMPP_UTIL_UNITTEST_H_

View File

@ -1,88 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/xmpp/xmppauth.h"
#include <algorithm>
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/libjingle/xmpp/saslcookiemechanism.h"
#include "webrtc/libjingle/xmpp/saslplainmechanism.h"
XmppAuth::XmppAuth() : done_(false) {
}
XmppAuth::~XmppAuth() {
}
void XmppAuth::StartPreXmppAuth(const buzz::Jid& jid,
const rtc::SocketAddress& server,
const rtc::CryptString& pass,
const std::string& auth_mechanism,
const std::string& auth_token) {
jid_ = jid;
passwd_ = pass;
auth_mechanism_ = auth_mechanism;
auth_token_ = auth_token;
done_ = true;
SignalAuthDone();
}
static bool contains(const std::vector<std::string>& strings,
const std::string& string) {
return std::find(strings.begin(), strings.end(), string) != strings.end();
}
std::string XmppAuth::ChooseBestSaslMechanism(
const std::vector<std::string>& mechanisms,
bool encrypted) {
// First try Oauth2.
if (GetAuthMechanism() == buzz::AUTH_MECHANISM_OAUTH2 &&
contains(mechanisms, buzz::AUTH_MECHANISM_OAUTH2)) {
return buzz::AUTH_MECHANISM_OAUTH2;
}
// A token is the weakest auth - 15s, service-limited, so prefer it.
if (GetAuthMechanism() == buzz::AUTH_MECHANISM_GOOGLE_TOKEN &&
contains(mechanisms, buzz::AUTH_MECHANISM_GOOGLE_TOKEN)) {
return buzz::AUTH_MECHANISM_GOOGLE_TOKEN;
}
// A cookie is the next weakest - 14 days.
if (GetAuthMechanism() == buzz::AUTH_MECHANISM_GOOGLE_COOKIE &&
contains(mechanisms, buzz::AUTH_MECHANISM_GOOGLE_COOKIE)) {
return buzz::AUTH_MECHANISM_GOOGLE_COOKIE;
}
// As a last resort, use plain authentication.
if (contains(mechanisms, buzz::AUTH_MECHANISM_PLAIN)) {
return buzz::AUTH_MECHANISM_PLAIN;
}
// No good mechanism found
return "";
}
buzz::SaslMechanism* XmppAuth::CreateSaslMechanism(
const std::string& mechanism) {
if (mechanism == buzz::AUTH_MECHANISM_OAUTH2) {
return new buzz::SaslCookieMechanism(
mechanism, jid_.Str(), auth_token_, "oauth2");
} else if (mechanism == buzz::AUTH_MECHANISM_GOOGLE_TOKEN) {
return new buzz::SaslCookieMechanism(mechanism, jid_.Str(), auth_token_);
// } else if (mechanism == buzz::AUTH_MECHANISM_GOOGLE_COOKIE) {
// return new buzz::SaslCookieMechanism(mechanism, jid.Str(), sid_);
} else if (mechanism == buzz::AUTH_MECHANISM_PLAIN) {
return new buzz::SaslPlainMechanism(jid_, passwd_);
} else {
return NULL;
}
}

View File

@ -1,61 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_XMPPAUTH_H_
#define WEBRTC_LIBJINGLE_XMPP_XMPPAUTH_H_
#include <vector>
#include "webrtc/libjingle/xmpp/jid.h"
#include "webrtc/libjingle/xmpp/prexmppauth.h"
#include "webrtc/libjingle/xmpp/saslhandler.h"
#include "webrtc/base/cryptstring.h"
#include "webrtc/base/sigslot.h"
class XmppAuth: public buzz::PreXmppAuth {
public:
XmppAuth();
virtual ~XmppAuth();
// TODO: Just have one "secret" that is either pass or
// token?
virtual void StartPreXmppAuth(const buzz::Jid& jid,
const rtc::SocketAddress& server,
const rtc::CryptString& pass,
const std::string& auth_mechanism,
const std::string& auth_token);
virtual bool IsAuthDone() const { return done_; }
virtual bool IsAuthorized() const { return true; }
virtual bool HadError() const { return false; }
virtual int GetError() const { return 0; }
virtual buzz::CaptchaChallenge GetCaptchaChallenge() const {
return buzz::CaptchaChallenge();
}
virtual std::string GetAuthMechanism() const { return auth_mechanism_; }
virtual std::string GetAuthToken() const { return auth_token_; }
virtual std::string ChooseBestSaslMechanism(
const std::vector<std::string>& mechanisms,
bool encrypted);
virtual buzz::SaslMechanism * CreateSaslMechanism(
const std::string& mechanism);
private:
buzz::Jid jid_;
rtc::CryptString passwd_;
std::string auth_mechanism_;
std::string auth_token_;
bool done_;
};
#endif // WEBRTC_LIBJINGLE_XMPP_XMPPAUTH_H_

View File

@ -1,423 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/xmpp/xmppclient.h"
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/libjingle/xmpp/plainsaslhandler.h"
#include "webrtc/libjingle/xmpp/prexmppauth.h"
#include "webrtc/libjingle/xmpp/saslplainmechanism.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/sigslot.h"
#include "webrtc/base/stringutils.h"
#include "xmpptask.h"
namespace buzz {
class XmppClient::Private :
public sigslot::has_slots<>,
public XmppSessionHandler,
public XmppOutputHandler {
public:
explicit Private(XmppClient* client) :
client_(client),
socket_(),
engine_(),
proxy_port_(0),
pre_engine_error_(XmppEngine::ERROR_NONE),
pre_engine_subcode_(0),
signal_closed_(false),
allow_plain_(false) {}
virtual ~Private() {
// We need to disconnect from socket_ before engine_ is destructed (by
// the auto-generated destructor code).
ResetSocket();
}
// the owner
XmppClient* const client_;
// the two main objects
std::unique_ptr<AsyncSocket> socket_;
std::unique_ptr<XmppEngine> engine_;
std::unique_ptr<PreXmppAuth> pre_auth_;
rtc::CryptString pass_;
std::string auth_mechanism_;
std::string auth_token_;
rtc::SocketAddress server_;
std::string proxy_host_;
int proxy_port_;
XmppEngine::Error pre_engine_error_;
int pre_engine_subcode_;
CaptchaChallenge captcha_challenge_;
bool signal_closed_;
bool allow_plain_;
void ResetSocket() {
if (socket_) {
socket_->SignalConnected.disconnect(this);
socket_->SignalRead.disconnect(this);
socket_->SignalClosed.disconnect(this);
socket_.reset(NULL);
}
}
// implementations of interfaces
void OnStateChange(int state);
void WriteOutput(const char* bytes, size_t len);
void StartTls(const std::string& domainname);
void CloseConnection();
// slots for socket signals
void OnSocketConnected();
void OnSocketRead();
void OnSocketClosed();
};
bool IsTestServer(const std::string& server_name,
const std::string& test_server_domain) {
return (!test_server_domain.empty() &&
rtc::ends_with(server_name.c_str(),
test_server_domain.c_str()));
}
XmppReturnStatus XmppClient::Connect(
const XmppClientSettings& settings,
const std::string& lang, AsyncSocket* socket, PreXmppAuth* pre_auth) {
if (socket == NULL)
return XMPP_RETURN_BADARGUMENT;
if (d_->socket_)
return XMPP_RETURN_BADSTATE;
d_->socket_.reset(socket);
d_->socket_->SignalConnected.connect(d_.get(), &Private::OnSocketConnected);
d_->socket_->SignalRead.connect(d_.get(), &Private::OnSocketRead);
d_->socket_->SignalClosed.connect(d_.get(), &Private::OnSocketClosed);
d_->engine_.reset(XmppEngine::Create());
d_->engine_->SetSessionHandler(d_.get());
d_->engine_->SetOutputHandler(d_.get());
if (!settings.resource().empty()) {
d_->engine_->SetRequestedResource(settings.resource());
}
d_->engine_->SetTls(settings.use_tls());
// The talk.google.com server returns a certificate with common-name:
// CN="gmail.com" for @gmail.com accounts,
// CN="googlemail.com" for @googlemail.com accounts,
// CN="talk.google.com" for other accounts (such as @example.com),
// so we tweak the tls server setting for those other accounts to match the
// returned certificate CN of "talk.google.com".
// For other servers, we leave the strings empty, which causes the jid's
// domain to be used. We do the same for gmail.com and googlemail.com as the
// returned CN matches the account domain in those cases.
std::string server_name = settings.server().HostAsURIString();
if (server_name == buzz::STR_TALK_GOOGLE_COM ||
server_name == buzz::STR_TALKX_L_GOOGLE_COM ||
server_name == buzz::STR_XMPP_GOOGLE_COM ||
server_name == buzz::STR_XMPPX_L_GOOGLE_COM ||
IsTestServer(server_name, settings.test_server_domain())) {
if (settings.host() != STR_GMAIL_COM &&
settings.host() != STR_GOOGLEMAIL_COM) {
d_->engine_->SetTlsServer("", STR_TALK_GOOGLE_COM);
}
}
// Set language
d_->engine_->SetLanguage(lang);
d_->engine_->SetUser(buzz::Jid(settings.user(), settings.host(), STR_EMPTY));
d_->pass_ = settings.pass();
d_->auth_mechanism_ = settings.auth_mechanism();
d_->auth_token_ = settings.auth_token();
d_->server_ = settings.server();
d_->proxy_host_ = settings.proxy_host();
d_->proxy_port_ = settings.proxy_port();
d_->allow_plain_ = settings.allow_plain();
d_->pre_auth_.reset(pre_auth);
return XMPP_RETURN_OK;
}
XmppEngine::State XmppClient::GetState() const {
if (!d_->engine_)
return XmppEngine::STATE_NONE;
return d_->engine_->GetState();
}
XmppEngine::Error XmppClient::GetError(int* subcode) {
if (subcode) {
*subcode = 0;
}
if (!d_->engine_)
return XmppEngine::ERROR_NONE;
if (d_->pre_engine_error_ != XmppEngine::ERROR_NONE) {
if (subcode) {
*subcode = d_->pre_engine_subcode_;
}
return d_->pre_engine_error_;
}
return d_->engine_->GetError(subcode);
}
const XmlElement* XmppClient::GetStreamError() {
if (!d_->engine_) {
return NULL;
}
return d_->engine_->GetStreamError();
}
CaptchaChallenge XmppClient::GetCaptchaChallenge() {
if (!d_->engine_)
return CaptchaChallenge();
return d_->captcha_challenge_;
}
std::string XmppClient::GetAuthMechanism() {
if (!d_->engine_)
return "";
return d_->auth_mechanism_;
}
std::string XmppClient::GetAuthToken() {
if (!d_->engine_)
return "";
return d_->auth_token_;
}
int XmppClient::ProcessStart() {
// Should not happen, but was observed in crash reports
if (!d_->socket_) {
LOG(LS_ERROR) << "socket_ already reset";
return STATE_DONE;
}
if (d_->pre_auth_) {
d_->pre_auth_->SignalAuthDone.connect(this, &XmppClient::OnAuthDone);
d_->pre_auth_->StartPreXmppAuth(
d_->engine_->GetUser(), d_->server_, d_->pass_,
d_->auth_mechanism_, d_->auth_token_);
d_->pass_.Clear(); // done with this;
return STATE_PRE_XMPP_LOGIN;
}
else {
d_->engine_->SetSaslHandler(new PlainSaslHandler(
d_->engine_->GetUser(), d_->pass_, d_->allow_plain_));
d_->pass_.Clear(); // done with this;
return STATE_START_XMPP_LOGIN;
}
}
void XmppClient::OnAuthDone() {
Wake();
}
int XmppClient::ProcessTokenLogin() {
// Should not happen, but was observed in crash reports
if (!d_->socket_) {
LOG(LS_ERROR) << "socket_ already reset";
return STATE_DONE;
}
// Don't know how this could happen, but crash reports show it as NULL
if (!d_->pre_auth_) {
d_->pre_engine_error_ = XmppEngine::ERROR_AUTH;
EnsureClosed();
return STATE_ERROR;
}
// Wait until pre authentication is done is done
if (!d_->pre_auth_->IsAuthDone())
return STATE_BLOCKED;
if (!d_->pre_auth_->IsAuthorized()) {
// maybe split out a case when gaia is down?
if (d_->pre_auth_->HadError()) {
d_->pre_engine_error_ = XmppEngine::ERROR_AUTH;
d_->pre_engine_subcode_ = d_->pre_auth_->GetError();
}
else {
d_->pre_engine_error_ = XmppEngine::ERROR_UNAUTHORIZED;
d_->pre_engine_subcode_ = 0;
d_->captcha_challenge_ = d_->pre_auth_->GetCaptchaChallenge();
}
d_->pre_auth_.reset(NULL); // done with this
EnsureClosed();
return STATE_ERROR;
}
// Save auth token as a result
d_->auth_mechanism_ = d_->pre_auth_->GetAuthMechanism();
d_->auth_token_ = d_->pre_auth_->GetAuthToken();
// transfer ownership of pre_auth_ to engine
d_->engine_->SetSaslHandler(d_->pre_auth_.release());
return STATE_START_XMPP_LOGIN;
}
int XmppClient::ProcessStartXmppLogin() {
// Should not happen, but was observed in crash reports
if (!d_->socket_) {
LOG(LS_ERROR) << "socket_ already reset";
return STATE_DONE;
}
// Done with pre-connect tasks - connect!
if (!d_->socket_->Connect(d_->server_)) {
EnsureClosed();
return STATE_ERROR;
}
return STATE_RESPONSE;
}
int XmppClient::ProcessResponse() {
// Hang around while we are connected.
if (!delivering_signal_ &&
(!d_->engine_ || d_->engine_->GetState() == XmppEngine::STATE_CLOSED))
return STATE_DONE;
return STATE_BLOCKED;
}
XmppReturnStatus XmppClient::Disconnect() {
if (!d_->socket_)
return XMPP_RETURN_BADSTATE;
Abort();
d_->engine_->Disconnect();
d_->ResetSocket();
return XMPP_RETURN_OK;
}
XmppClient::XmppClient(TaskParent* parent)
: XmppTaskParentInterface(parent),
delivering_signal_(false),
valid_(false) {
d_.reset(new Private(this));
valid_ = true;
}
XmppClient::~XmppClient() {
valid_ = false;
}
const Jid& XmppClient::jid() const {
return d_->engine_->FullJid();
}
std::string XmppClient::NextId() {
return d_->engine_->NextId();
}
XmppReturnStatus XmppClient::SendStanza(const XmlElement* stanza) {
return d_->engine_->SendStanza(stanza);
}
XmppReturnStatus XmppClient::SendStanzaError(
const XmlElement* old_stanza, XmppStanzaError xse,
const std::string& message) {
return d_->engine_->SendStanzaError(old_stanza, xse, message);
}
XmppReturnStatus XmppClient::SendRaw(const std::string& text) {
return d_->engine_->SendRaw(text);
}
XmppEngine* XmppClient::engine() {
return d_->engine_.get();
}
void XmppClient::Private::OnSocketConnected() {
engine_->Connect();
}
void XmppClient::Private::OnSocketRead() {
char bytes[4096];
size_t bytes_read;
for (;;) {
// Should not happen, but was observed in crash reports
if (!socket_) {
LOG(LS_ERROR) << "socket_ already reset";
return;
}
if (!socket_->Read(bytes, sizeof(bytes), &bytes_read)) {
// TODO: deal with error information
return;
}
if (bytes_read == 0)
return;
//#if !defined(NDEBUG)
client_->SignalLogInput(bytes, static_cast<int>(bytes_read));
//#endif
engine_->HandleInput(bytes, bytes_read);
}
}
void XmppClient::Private::OnSocketClosed() {
int code = socket_->GetError();
engine_->ConnectionClosed(code);
}
void XmppClient::Private::OnStateChange(int state) {
if (state == XmppEngine::STATE_CLOSED) {
client_->EnsureClosed();
}
else {
client_->SignalStateChange((XmppEngine::State)state);
}
client_->Wake();
}
void XmppClient::Private::WriteOutput(const char* bytes, size_t len) {
//#if !defined(NDEBUG)
client_->SignalLogOutput(bytes, static_cast<int>(len));
//#endif
socket_->Write(bytes, len);
// TODO: deal with error information
}
void XmppClient::Private::StartTls(const std::string& domain) {
#if defined(FEATURE_ENABLE_SSL)
socket_->StartTls(domain);
#endif
}
void XmppClient::Private::CloseConnection() {
socket_->Close();
}
void XmppClient::AddXmppTask(XmppTask* task, XmppEngine::HandlerLevel level) {
d_->engine_->AddStanzaHandler(task, level);
}
void XmppClient::RemoveXmppTask(XmppTask* task) {
d_->engine_->RemoveStanzaHandler(task);
}
void XmppClient::EnsureClosed() {
if (!d_->signal_closed_) {
d_->signal_closed_ = true;
delivering_signal_ = true;
SignalStateChange(XmppEngine::STATE_CLOSED);
delivering_signal_ = false;
}
}
} // namespace buzz

View File

@ -1,149 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_XMPPCLIENT_H_
#define WEBRTC_LIBJINGLE_XMPP_XMPPCLIENT_H_
#include <memory>
#include <string>
#include "webrtc/libjingle/xmpp/asyncsocket.h"
#include "webrtc/libjingle/xmpp/xmppclientsettings.h"
#include "webrtc/libjingle/xmpp/xmppengine.h"
#include "webrtc/libjingle/xmpp/xmpptask.h"
#include "webrtc/base/sigslot.h"
#include "webrtc/base/task.h"
namespace buzz {
class PreXmppAuth;
class CaptchaChallenge;
// Just some non-colliding number. Could have picked "1".
#define XMPP_CLIENT_TASK_CODE 0x366c1e47
/////////////////////////////////////////////////////////////////////
//
// XMPPCLIENT
//
/////////////////////////////////////////////////////////////////////
//
// See Task first. XmppClient is a parent task for XmppTasks.
//
// XmppClient is a task which is designed to be the parent task for
// all tasks that depend on a single Xmpp connection. If you want to,
// for example, listen for subscription requests forever, then your
// listener should be a task that is a child of the XmppClient that owns
// the connection you are using. XmppClient has all the utility methods
// that basically drill through to XmppEngine.
//
// XmppClient is just a wrapper for XmppEngine, and if I were writing it
// all over again, I would make XmppClient == XmppEngine. Why?
// XmppEngine needs tasks too, for example it has an XmppLoginTask which
// should just be the same kind of Task instead of an XmppEngine specific
// thing. It would help do certain things like GAIA auth cleaner.
//
/////////////////////////////////////////////////////////////////////
class XmppClient : public XmppTaskParentInterface,
public XmppClientInterface,
public sigslot::has_slots<>
{
public:
explicit XmppClient(rtc::TaskParent * parent);
virtual ~XmppClient();
XmppReturnStatus Connect(const XmppClientSettings & settings,
const std::string & lang,
AsyncSocket * socket,
PreXmppAuth * preauth);
virtual int ProcessStart();
virtual int ProcessResponse();
XmppReturnStatus Disconnect();
sigslot::signal1<XmppEngine::State> SignalStateChange;
XmppEngine::Error GetError(int *subcode);
// When there is a <stream:error> stanza, return the stanza
// so that they can be handled.
const XmlElement *GetStreamError();
// When there is an authentication error, we may have captcha info
// that the user can use to unlock their account
CaptchaChallenge GetCaptchaChallenge();
// When authentication is successful, this returns the service token
// (if we used GAIA authentication)
std::string GetAuthMechanism();
std::string GetAuthToken();
XmppReturnStatus SendRaw(const std::string & text);
XmppEngine* engine();
sigslot::signal2<const char *, int> SignalLogInput;
sigslot::signal2<const char *, int> SignalLogOutput;
// As XmppTaskParentIntreface
virtual XmppClientInterface* GetClient() { return this; }
// As XmppClientInterface
virtual XmppEngine::State GetState() const;
virtual const Jid& jid() const;
virtual std::string NextId();
virtual XmppReturnStatus SendStanza(const XmlElement *stanza);
virtual XmppReturnStatus SendStanzaError(const XmlElement * pelOriginal,
XmppStanzaError code,
const std::string & text);
virtual void AddXmppTask(XmppTask *, XmppEngine::HandlerLevel);
virtual void RemoveXmppTask(XmppTask *);
private:
friend class XmppTask;
void OnAuthDone();
// Internal state management
enum {
STATE_PRE_XMPP_LOGIN = STATE_NEXT,
STATE_START_XMPP_LOGIN = STATE_NEXT + 1,
};
int Process(int state) {
switch (state) {
case STATE_PRE_XMPP_LOGIN: return ProcessTokenLogin();
case STATE_START_XMPP_LOGIN: return ProcessStartXmppLogin();
default: return Task::Process(state);
}
}
std::string GetStateName(int state) const {
switch (state) {
case STATE_PRE_XMPP_LOGIN: return "PRE_XMPP_LOGIN";
case STATE_START_XMPP_LOGIN: return "START_XMPP_LOGIN";
default: return Task::GetStateName(state);
}
}
int ProcessTokenLogin();
int ProcessStartXmppLogin();
void EnsureClosed();
class Private;
friend class Private;
std::unique_ptr<Private> d_;
bool delivering_signal_;
bool valid_;
};
}
#endif // WEBRTC_LIBJINGLE_XMPP_XMPPCLIENT_H_

View File

@ -1,111 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_XMPPCLIENTSETTINGS_H_
#define WEBRTC_LIBJINGLE_XMPP_XMPPCLIENTSETTINGS_H_
#include "webrtc/p2p/base/port.h"
#include "webrtc/libjingle/xmpp/xmppengine.h"
#include "webrtc/base/cryptstring.h"
namespace buzz {
class XmppUserSettings {
public:
XmppUserSettings()
: use_tls_(buzz::TLS_DISABLED),
allow_plain_(false) {
}
void set_user(const std::string& user) { user_ = user; }
void set_host(const std::string& host) { host_ = host; }
void set_pass(const rtc::CryptString& pass) { pass_ = pass; }
void set_auth_token(const std::string& mechanism,
const std::string& token) {
auth_mechanism_ = mechanism;
auth_token_ = token;
}
void set_resource(const std::string& resource) { resource_ = resource; }
void set_use_tls(const TlsOptions use_tls) { use_tls_ = use_tls; }
void set_allow_plain(bool f) { allow_plain_ = f; }
void set_test_server_domain(const std::string& test_server_domain) {
test_server_domain_ = test_server_domain;
}
void set_token_service(const std::string& token_service) {
token_service_ = token_service;
}
const std::string& user() const { return user_; }
const std::string& host() const { return host_; }
const rtc::CryptString& pass() const { return pass_; }
const std::string& auth_mechanism() const { return auth_mechanism_; }
const std::string& auth_token() const { return auth_token_; }
const std::string& resource() const { return resource_; }
TlsOptions use_tls() const { return use_tls_; }
bool allow_plain() const { return allow_plain_; }
const std::string& test_server_domain() const { return test_server_domain_; }
const std::string& token_service() const { return token_service_; }
private:
std::string user_;
std::string host_;
rtc::CryptString pass_;
std::string auth_mechanism_;
std::string auth_token_;
std::string resource_;
TlsOptions use_tls_;
bool allow_plain_;
std::string test_server_domain_;
std::string token_service_;
};
class XmppClientSettings : public XmppUserSettings {
public:
XmppClientSettings()
: protocol_(cricket::PROTO_TCP),
proxy_(rtc::PROXY_NONE),
proxy_port_(80),
use_proxy_auth_(false) {
}
void set_server(const rtc::SocketAddress& server) {
server_ = server;
}
void set_protocol(cricket::ProtocolType protocol) { protocol_ = protocol; }
void set_proxy(rtc::ProxyType f) { proxy_ = f; }
void set_proxy_host(const std::string& host) { proxy_host_ = host; }
void set_proxy_port(int port) { proxy_port_ = port; };
void set_use_proxy_auth(bool f) { use_proxy_auth_ = f; }
void set_proxy_user(const std::string& user) { proxy_user_ = user; }
void set_proxy_pass(const rtc::CryptString& pass) { proxy_pass_ = pass; }
const rtc::SocketAddress& server() const { return server_; }
cricket::ProtocolType protocol() const { return protocol_; }
rtc::ProxyType proxy() const { return proxy_; }
const std::string& proxy_host() const { return proxy_host_; }
int proxy_port() const { return proxy_port_; }
bool use_proxy_auth() const { return use_proxy_auth_; }
const std::string& proxy_user() const { return proxy_user_; }
const rtc::CryptString& proxy_pass() const { return proxy_pass_; }
private:
rtc::SocketAddress server_;
cricket::ProtocolType protocol_;
rtc::ProxyType proxy_;
std::string proxy_host_;
int proxy_port_;
bool use_proxy_auth_;
std::string proxy_user_;
rtc::CryptString proxy_pass_;
};
}
#endif // WEBRTC_LIBJINGLE_XMPP_XMPPCLIENT_H_

View File

@ -1,332 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_XMPP_XMPPENGINE_H_
#define WEBRTC_LIBJINGLE_XMPP_XMPPENGINE_H_
// also part of the API
#include "webrtc/libjingle/xmllite/qname.h"
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/libjingle/xmpp/jid.h"
namespace buzz {
class XmppEngine;
class SaslHandler;
typedef void * XmppIqCookie;
//! XMPP stanza error codes.
//! Used in XmppEngine.SendStanzaError().
enum XmppStanzaError {
XSE_BAD_REQUEST,
XSE_CONFLICT,
XSE_FEATURE_NOT_IMPLEMENTED,
XSE_FORBIDDEN,
XSE_GONE,
XSE_INTERNAL_SERVER_ERROR,
XSE_ITEM_NOT_FOUND,
XSE_JID_MALFORMED,
XSE_NOT_ACCEPTABLE,
XSE_NOT_ALLOWED,
XSE_PAYMENT_REQUIRED,
XSE_RECIPIENT_UNAVAILABLE,
XSE_REDIRECT,
XSE_REGISTRATION_REQUIRED,
XSE_SERVER_NOT_FOUND,
XSE_SERVER_TIMEOUT,
XSE_RESOURCE_CONSTRAINT,
XSE_SERVICE_UNAVAILABLE,
XSE_SUBSCRIPTION_REQUIRED,
XSE_UNDEFINED_CONDITION,
XSE_UNEXPECTED_REQUEST,
};
// XmppReturnStatus
// This is used by API functions to synchronously return status.
enum XmppReturnStatus {
XMPP_RETURN_OK,
XMPP_RETURN_BADARGUMENT,
XMPP_RETURN_BADSTATE,
XMPP_RETURN_PENDING,
XMPP_RETURN_UNEXPECTED,
XMPP_RETURN_NOTYETIMPLEMENTED,
};
// TlsOptions
// This is used by API to identify TLS setting.
enum TlsOptions {
TLS_DISABLED,
TLS_ENABLED,
TLS_REQUIRED
};
//! Callback for socket output for an XmppEngine connection.
//! Register via XmppEngine.SetOutputHandler. An XmppEngine
//! can call back to this handler while it is processing
//! Connect, SendStanza, SendIq, Disconnect, or HandleInput.
class XmppOutputHandler {
public:
virtual ~XmppOutputHandler() {}
//! Deliver the specified bytes to the XMPP socket.
virtual void WriteOutput(const char * bytes, size_t len) = 0;
//! Initiate TLS encryption on the socket.
//! The implementation must verify that the SSL
//! certificate matches the given domainname.
virtual void StartTls(const std::string & domainname) = 0;
//! Called when engine wants the connecton closed.
virtual void CloseConnection() = 0;
};
//! Callback to deliver engine state change notifications
//! to the object managing the engine.
class XmppSessionHandler {
public:
virtual ~XmppSessionHandler() {}
//! Called when engine changes state. Argument is new state.
virtual void OnStateChange(int state) = 0;
};
//! Callback to deliver stanzas to an Xmpp application module.
//! Register via XmppEngine.SetDefaultSessionHandler or via
//! XmppEngine.AddSessionHAndler.
class XmppStanzaHandler {
public:
virtual ~XmppStanzaHandler() {}
//! Process the given stanza.
//! The handler must return true if it has handled the stanza.
//! A false return value causes the stanza to be passed on to
//! the next registered handler.
virtual bool HandleStanza(const XmlElement * stanza) = 0;
};
//! Callback to deliver iq responses (results and errors).
//! Register while sending an iq via XmppEngine.SendIq.
//! Iq responses are routed to matching XmppIqHandlers in preference
//! to sending to any registered SessionHandlers.
class XmppIqHandler {
public:
virtual ~XmppIqHandler() {}
//! Called to handle the iq response.
//! The response may be either a result or an error, and will have
//! an 'id' that matches the request and a 'from' that matches the
//! 'to' of the request. Called no more than once; once this is
//! called, the handler is automatically unregistered.
virtual void IqResponse(XmppIqCookie cookie, const XmlElement * pelStanza) = 0;
};
//! The XMPP connection engine.
//! This engine implements the client side of the 'core' XMPP protocol.
//! To use it, register an XmppOutputHandler to handle socket output
//! and pass socket input to HandleInput. Then application code can
//! set up the connection with a user, password, and other settings,
//! and then call Connect() to initiate the connection.
//! An application can listen for events and receive stanzas by
//! registering an XmppStanzaHandler via AddStanzaHandler().
class XmppEngine {
public:
static XmppEngine * Create();
virtual ~XmppEngine() {}
//! Error codes. See GetError().
enum Error {
ERROR_NONE = 0, //!< No error
ERROR_XML, //!< Malformed XML or encoding error
ERROR_STREAM, //!< XMPP stream error - see GetStreamError()
ERROR_VERSION, //!< XMPP version error
ERROR_UNAUTHORIZED, //!< User is not authorized (rejected credentials)
ERROR_TLS, //!< TLS could not be negotiated
ERROR_AUTH, //!< Authentication could not be negotiated
ERROR_BIND, //!< Resource or session binding could not be negotiated
ERROR_CONNECTION_CLOSED,//!< Connection closed by output handler.
ERROR_DOCUMENT_CLOSED, //!< Closed by </stream:stream>
ERROR_SOCKET, //!< Socket error
ERROR_NETWORK_TIMEOUT, //!< Some sort of timeout (eg., we never got the roster)
ERROR_MISSING_USERNAME //!< User has a Google Account but no nickname
};
//! States. See GetState().
enum State {
STATE_NONE = 0, //!< Nonexistent state
STATE_START, //!< Initial state.
STATE_OPENING, //!< Exchanging stream headers, authenticating and so on.
STATE_OPEN, //!< Authenticated and bound.
STATE_CLOSED, //!< Session closed, possibly due to error.
};
// SOCKET INPUT AND OUTPUT ------------------------------------------------
//! Registers the handler for socket output
virtual XmppReturnStatus SetOutputHandler(XmppOutputHandler *pxoh) = 0;
//! Provides socket input to the engine
virtual XmppReturnStatus HandleInput(const char * bytes, size_t len) = 0;
//! Advises the engine that the socket has closed
virtual XmppReturnStatus ConnectionClosed(int subcode) = 0;
// SESSION SETUP ---------------------------------------------------------
//! Indicates the (bare) JID for the user to use.
virtual XmppReturnStatus SetUser(const Jid & jid)= 0;
//! Get the login (bare) JID.
virtual const Jid & GetUser() = 0;
//! Provides different methods for credentials for login.
//! Takes ownership of this object; deletes when login is done
virtual XmppReturnStatus SetSaslHandler(SaslHandler * h) = 0;
//! Sets whether TLS will be used within the connection (default true).
virtual XmppReturnStatus SetTls(TlsOptions useTls) = 0;
//! Sets an alternate domain from which we allows TLS certificates.
//! This is for use in the case where a we want to allow a proxy to
//! serve up its own certificate rather than one owned by the underlying
//! domain.
virtual XmppReturnStatus SetTlsServer(const std::string & proxy_hostname,
const std::string & proxy_domain) = 0;
//! Gets whether TLS will be used within the connection.
virtual TlsOptions GetTls() = 0;
//! Sets the request resource name, if any (optional).
//! Note that the resource name may be overridden by the server; after
//! binding, the actual resource name is available as part of FullJid().
virtual XmppReturnStatus SetRequestedResource(const std::string& resource) = 0;
//! Gets the request resource name.
virtual const std::string & GetRequestedResource() = 0;
//! Sets language
virtual void SetLanguage(const std::string & lang) = 0;
// SESSION MANAGEMENT ---------------------------------------------------
//! Set callback for state changes.
virtual XmppReturnStatus SetSessionHandler(XmppSessionHandler* handler) = 0;
//! Initiates the XMPP connection.
//! After supplying connection settings, call this once to initiate,
//! (optionally) encrypt, authenticate, and bind the connection.
virtual XmppReturnStatus Connect() = 0;
//! The current engine state.
virtual State GetState() = 0;
//! Returns true if the connection is encrypted (under TLS)
virtual bool IsEncrypted() = 0;
//! The error code.
//! Consult this after XmppOutputHandler.OnClose().
virtual Error GetError(int *subcode) = 0;
//! The stream:error stanza, when the error is XmppEngine::ERROR_STREAM.
//! Notice the stanza returned is owned by the XmppEngine and
//! is deleted when the engine is destroyed.
virtual const XmlElement * GetStreamError() = 0;
//! Closes down the connection.
//! Sends CloseConnection to output, and disconnects and registered
//! session handlers. After Disconnect completes, it is guaranteed
//! that no further callbacks will be made.
virtual XmppReturnStatus Disconnect() = 0;
// APPLICATION USE -------------------------------------------------------
enum HandlerLevel {
HL_NONE = 0,
HL_PEEK, //!< Sees messages before all other processing; cannot abort
HL_SINGLE, //!< Watches for a single message, e.g., by id and sender
HL_SENDER, //!< Watches for a type of message from a specific sender
HL_TYPE, //!< Watches a type of message, e.g., all groupchat msgs
HL_ALL, //!< Watches all messages - gets last shot
HL_COUNT, //!< Count of handler levels
};
//! Adds a listener for session events.
//! Stanza delivery is chained to session handlers; the first to
//! return 'true' is the last to get each stanza.
virtual XmppReturnStatus AddStanzaHandler(XmppStanzaHandler* handler, HandlerLevel level = HL_PEEK) = 0;
//! Removes a listener for session events.
virtual XmppReturnStatus RemoveStanzaHandler(XmppStanzaHandler* handler) = 0;
//! Sends a stanza to the server.
virtual XmppReturnStatus SendStanza(const XmlElement * pelStanza) = 0;
//! Sends raw text to the server
virtual XmppReturnStatus SendRaw(const std::string & text) = 0;
//! Sends an iq to the server, and registers a callback for the result.
//! Returns the cookie passed to the result handler.
virtual XmppReturnStatus SendIq(const XmlElement* pelStanza,
XmppIqHandler* iq_handler,
XmppIqCookie* cookie) = 0;
//! Unregisters an iq callback handler given its cookie.
//! No callback will come to this handler after it's unregistered.
virtual XmppReturnStatus RemoveIqHandler(XmppIqCookie cookie,
XmppIqHandler** iq_handler) = 0;
//! Forms and sends an error in response to the given stanza.
//! Swaps to and from, sets type to "error", and adds error information
//! based on the passed code. Text is optional and may be STR_EMPTY.
virtual XmppReturnStatus SendStanzaError(const XmlElement * pelOriginal,
XmppStanzaError code,
const std::string & text) = 0;
//! The fullly bound JID.
//! This JID is only valid after binding has succeeded. If the value
//! is JID_NULL, the binding has not succeeded.
virtual const Jid & FullJid() = 0;
//! The next unused iq id for this connection.
//! Call this when building iq stanzas, to ensure that each iq
//! gets its own unique id.
virtual std::string NextId() = 0;
};
}
// Move these to a better location
#define XMPP_FAILED(x) \
( (x) == buzz::XMPP_RETURN_OK ? false : true) \
#define XMPP_SUCCEEDED(x) \
( (x) == buzz::XMPP_RETURN_OK ? true : false) \
#define IFR(x) \
do { \
xmpp_status = (x); \
if (XMPP_FAILED(xmpp_status)) { \
return xmpp_status; \
} \
} while (false) \
#define IFC(x) \
do { \
xmpp_status = (x); \
if (XMPP_FAILED(xmpp_status)) { \
goto Cleanup; \
} \
} while (false) \
#endif // WEBRTC_LIBJINGLE_XMPP_XMPPENGINE_H_

Some files were not shown because too many files have changed in this diff Show More