WIP: mess
This commit is contained in:
parent
b4652b3939
commit
2536fa4937
|
@ -1,8 +1,7 @@
|
||||||
use std::str;
|
use std::{collections::BTreeMap, str};
|
||||||
|
|
||||||
use quick_xml::{
|
use quick_xml::{
|
||||||
events::{BytesDecl, Event},
|
events::{BytesDecl, Event},
|
||||||
name::QName,
|
|
||||||
Reader, Writer,
|
Reader, Writer,
|
||||||
};
|
};
|
||||||
use rsasl::prelude::{Mechname, SASLClient};
|
use rsasl::prelude::{Mechname, SASLClient};
|
||||||
|
@ -53,7 +52,9 @@ impl<'j> JabberClient<'j> {
|
||||||
.write_event_async(Event::Decl(declaration))
|
.write_event_async(Event::Decl(declaration))
|
||||||
.await;
|
.await;
|
||||||
let stream_element: Element<'_> = stream_element.into();
|
let stream_element: Element<'_> = stream_element.into();
|
||||||
stream_element.write_start(&mut self.writer).await?;
|
stream_element
|
||||||
|
.write_start(&mut self.writer, &BTreeMap::new())
|
||||||
|
.await?;
|
||||||
// server to client
|
// server to client
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
self.reader.read_event_into_async(&mut buf).await?;
|
self.reader.read_event_into_async(&mut buf).await?;
|
||||||
|
|
|
@ -1,12 +1,4 @@
|
||||||
use std::collections::BTreeMap;
|
use super::{Element, ElementParseError};
|
||||||
|
|
||||||
use quick_xml::{
|
|
||||||
events::{BytesStart, BytesText, Event},
|
|
||||||
name::QName,
|
|
||||||
Reader,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{Element, IntoElement, Node};
|
|
||||||
use crate::{JabberError, JID};
|
use crate::{JabberError, JID};
|
||||||
|
|
||||||
const XMLNS: &str = "urn:ietf:params:xml:ns:xmpp-bind";
|
const XMLNS: &str = "urn:ietf:params:xml:ns:xmpp-bind";
|
||||||
|
@ -17,120 +9,40 @@ pub struct Bind {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Bind> for Element {
|
impl From<Bind> for Element {
|
||||||
fn from(value: Bind) -> Self {
|
fn from(bind: Bind) -> Self {
|
||||||
let mut namespace_declarations = Box::new(BTreeMap::new());
|
let bind_element = Element::new("bind", None, XMLNS);
|
||||||
namespace_declarations.insert(None, XMLNS.to_owned());
|
bind_element.push_namespace_declaration((None, XMLNS));
|
||||||
let mut children = Vec::new();
|
if let Some(resource) = bind.resource {
|
||||||
if let Some(resource) = value.resource {
|
let resource_element = Element::new("resource", None, XMLNS);
|
||||||
children.push(Node::Element(
|
resource_element.push_child(resource);
|
||||||
Element { prefix: None, localname: "", namespace: , namespace_declarations: , attributes: , children: }
|
bind_element.push_child(resource_element)
|
||||||
)
|
|
||||||
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
Self {
|
if let Some(jid) = bind.jid {
|
||||||
prefix: None,
|
let jid_element = Element::new("jid", None, XMLNS);
|
||||||
localname: "bind".to_string(),
|
jid_element.push_child(jid);
|
||||||
namespace: XMLNS.to_owned(),
|
bind_element.push_child(jid_element)
|
||||||
namespace_declarations,
|
|
||||||
attributes: todo!(),
|
|
||||||
children: todo!(),
|
|
||||||
}
|
}
|
||||||
|
bind_element
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoElement for Bind {
|
impl TryFrom<Element> for Bind {
|
||||||
fn event(&self) -> quick_xml::events::Event<'static> {
|
|
||||||
let mut bind_event = BytesStart::new("bind");
|
|
||||||
bind_event.push_attribute(("xmlns", XMLNS));
|
|
||||||
if self.resource.is_none() && self.jid.is_none() {
|
|
||||||
return Event::Empty(bind_event);
|
|
||||||
} else {
|
|
||||||
return Event::Start(bind_event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn children(&self) -> Option<Vec<Element<'static>>> {
|
|
||||||
if let Some(resource) = &self.resource {
|
|
||||||
let resource_event: BytesStart<'static> = BytesStart::new("resource");
|
|
||||||
let resource_child: BytesText<'static> = BytesText::new(resource).into_owned();
|
|
||||||
let resource_child: Element<'static> = Element {
|
|
||||||
event: Event::Text(resource_child),
|
|
||||||
children: None,
|
|
||||||
};
|
|
||||||
let resource_element: Element<'static> = Element {
|
|
||||||
event: Event::Start(resource_event),
|
|
||||||
children: Some(vec![resource_child]),
|
|
||||||
};
|
|
||||||
return Some(vec![resource_element]);
|
|
||||||
} else if let Some(jid) = &self.jid {
|
|
||||||
let jid_event = BytesStart::new("jid");
|
|
||||||
let jid_child = BytesText::new(&jid.to_string()).into_owned();
|
|
||||||
let jid_child = Element {
|
|
||||||
event: Event::Text(jid_child),
|
|
||||||
children: None,
|
|
||||||
};
|
|
||||||
let jid_element = Element {
|
|
||||||
event: Event::Start(jid_event),
|
|
||||||
children: Some(vec![jid_child]),
|
|
||||||
};
|
|
||||||
return Some(vec![jid_element]);
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<Element<'static>> for Bind {
|
|
||||||
type Error = JabberError;
|
type Error = JabberError;
|
||||||
|
|
||||||
fn try_from(element: Element<'static>) -> Result<Self, Self::Error> {
|
fn try_from(element: Element) -> Result<Self, Self::Error> {
|
||||||
if let Event::Start(start) = &element.event {
|
if element.namespace() == XMLNS && element.localname() == "bind" {
|
||||||
let buf: Vec<u8> = Vec::new();
|
let (resource, jid);
|
||||||
let reader = Reader::from_reader(buf);
|
let child: &Element = element.child()?;
|
||||||
if start.name() == QName(b"bind")
|
if child.namespace() == XMLNS {
|
||||||
&& start.try_get_attribute("xmlns")?.is_some_and(|attribute| {
|
match child.localname() {
|
||||||
attribute.decode_and_unescape_value(&reader).unwrap() == XMLNS
|
"resource" => Bind::new(Some(
|
||||||
})
|
child
|
||||||
{
|
.text_content()?
|
||||||
let child: Element<'static> = element.child()?.clone();
|
.first()
|
||||||
if let Event::Start(start) = &child.event {
|
.ok_or(ElementParseError::NoContent)?,
|
||||||
match start.name() {
|
)),
|
||||||
QName(b"resource") => {
|
|
||||||
let resource_text = child.child()?;
|
|
||||||
if let Event::Text(text) = &resource_text.event {
|
|
||||||
return Ok(Self {
|
|
||||||
resource: Some(text.unescape()?.into_owned()),
|
|
||||||
jid: None,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
QName(b"jid") => {
|
|
||||||
let jid_text = child.child()?;
|
|
||||||
if let Event::Text(text) = &jid_text.event {
|
|
||||||
return Ok(Self {
|
|
||||||
jid: Some(text.unescape()?.into_owned().try_into()?),
|
|
||||||
resource: None,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => return Err(JabberError::UnexpectedElement),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if let Event::Empty(start) = &element.event {
|
|
||||||
let buf: Vec<u8> = Vec::new();
|
|
||||||
let reader = Reader::from_reader(buf);
|
|
||||||
if start.name() == QName(b"bind")
|
|
||||||
&& start.try_get_attribute("xmlns")?.is_some_and(|attribute| {
|
|
||||||
attribute.decode_and_unescape_value(&reader).unwrap() == XMLNS
|
|
||||||
})
|
|
||||||
{
|
|
||||||
return Ok(Bind {
|
|
||||||
resource: None,
|
|
||||||
jid: None,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(JabberError::UnexpectedElement)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ use quick_xml::{
|
||||||
|
|
||||||
use crate::{JabberClient, JabberError, JID};
|
use crate::{JabberClient, JabberError, JID};
|
||||||
|
|
||||||
use super::{Element, IntoElement};
|
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
@ -17,8 +17,6 @@ use tokio::io::{AsyncBufRead, AsyncWrite};
|
||||||
|
|
||||||
use crate::{JabberError, Result};
|
use crate::{JabberError, Result};
|
||||||
|
|
||||||
pub type Prefix<'s> = Option<&'s str>;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
/// represents an xml element as a tree of nodes
|
/// represents an xml element as a tree of nodes
|
||||||
pub struct Element {
|
pub struct Element {
|
||||||
|
@ -78,19 +76,6 @@ pub struct Element {
|
||||||
children: Box<Vec<Node>>,
|
children: Box<Vec<Node>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Element {
|
|
||||||
pub fn new_empty<S: ToString, C: Into<Node>>(
|
|
||||||
prefix: Option<S>,
|
|
||||||
localname: S,
|
|
||||||
namespace: S,
|
|
||||||
namespace_declarations: BTreeMap<Option<S>, S>,
|
|
||||||
attributes: BTreeMap<S, S>,
|
|
||||||
children: Vec<C>,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
pub fn push_child<C: Into<Node>>(&mut self, node: C) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Node {
|
pub enum Node {
|
||||||
Element(Element),
|
Element(Element),
|
||||||
|
@ -244,22 +229,22 @@ impl Element {
|
||||||
/// by a parent, or itself.
|
/// by a parent, or itself.
|
||||||
fn namespace_qualified<S: AsRef<str>>(
|
fn namespace_qualified<S: AsRef<str>>(
|
||||||
&self,
|
&self,
|
||||||
local_namespaces: &BTreeMap<Option<S>, S>,
|
namespace_context: &BTreeMap<Option<S>, S>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
// create a new local_namespaces combining that in the context and those declared within the element
|
||||||
|
let mut local_namespaces = *namespace_context.clone();
|
||||||
|
self.namespace_declarations.iter().for_each(|prefix, declaration| local_namespaces.insert(prefix, declaration));
|
||||||
|
|
||||||
if let Some(namespace) = local_namespaces.get(self.prefix) {
|
if let Some(namespace) = local_namespaces.get(self.prefix) {
|
||||||
if namespace != self.namespace {
|
if namespace != self.namespace {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(namespace) = self.namespace_declarations.get(&self.prefix) {
|
|
||||||
if namespace != self.namespace {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for child in *self.children {
|
for child in *self.children {
|
||||||
if child.namespace_qualified(local_namespaces) == false {
|
if child.namespace_qualified(&local_namespaces) == false {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -267,6 +252,7 @@ impl Element {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// writes an element to a writer. the element's namespace must be qualified by the
|
/// writes an element to a writer. the element's namespace must be qualified by the
|
||||||
/// context given in `local_namespaces` or the element's internal namespace declarations
|
/// context given in `local_namespaces` or the element's internal namespace declarations
|
||||||
pub async fn write<S: AsRef<str>, W: AsyncWrite + Unpin + Send>(
|
pub async fn write<S: AsRef<str>, W: AsyncWrite + Unpin + Send>(
|
||||||
|
@ -274,7 +260,7 @@ impl Element {
|
||||||
writer: &mut Writer<W>,
|
writer: &mut Writer<W>,
|
||||||
local_namespaces: &BTreeMap<Option<S>, S>,
|
local_namespaces: &BTreeMap<Option<S>, S>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
// TODO: NEXT: instead of having a check if namespace qualified function, have the namespace declarations be added if needed given the context when converting from `Element` to `Event`s
|
// TODO: instead of having a check if namespace qualified function, have the namespace declarations be added if needed given the context when converting from `Element` to `Event`s
|
||||||
if self.namespace_qualified(local_namespaces) {
|
if self.namespace_qualified(local_namespaces) {
|
||||||
let events: Vec<Event> = self.into();
|
let events: Vec<Event> = self.into();
|
||||||
for event in events {
|
for event in events {
|
||||||
|
@ -553,17 +539,107 @@ impl Node {
|
||||||
|
|
||||||
fn namespace_qualified<S: AsRef<str>>(
|
fn namespace_qualified<S: AsRef<str>>(
|
||||||
&self,
|
&self,
|
||||||
local_namespaces: &BTreeMap<Option<S>, S>,
|
namespace_context: &BTreeMap<Option<S>, S>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Element(e) => e.namespace_qualified(local_namespaces),
|
Self::Element(e) => e.namespace_qualified(namespace_context),
|
||||||
_ => true,
|
_ => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// the issue is i don't know how to validate that an element always has a namespace when it is being written
|
pub enum NodeBuilder {
|
||||||
// TODO: ElementBuilder that makes it easier to build an element under a namespace
|
Text(String),
|
||||||
|
Element(ElementBuilder),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ElementBuilder {
|
||||||
|
localname: String,
|
||||||
|
prefix: Option<String>,
|
||||||
|
namespace: String,
|
||||||
|
namespace_declarations: BTreeMap<Option<String>, String>,
|
||||||
|
attributes: BTreeMap<String, String>,
|
||||||
|
children: Vec<NodeBuilder>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ElementBuilder {
|
||||||
|
pub fn new<S: ToString>(localname: S, prefix: Option<S>, namespace: S) -> Self {
|
||||||
|
Self {
|
||||||
|
prefix,
|
||||||
|
localname,
|
||||||
|
namespace,
|
||||||
|
namespace_declarations: Box::new(BTreeMap::new()),
|
||||||
|
attributes: Box::new(BTreeMap::new()),
|
||||||
|
children: Box::new(Vec::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_namespace_declaration<S: ToString>(
|
||||||
|
&mut self,
|
||||||
|
(prefix, namespace): (Option<S>, S),
|
||||||
|
) -> Option<S> {
|
||||||
|
self.namespace_declarations.insert(prefix, namespace)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_attribute<S: ToString>(&mut self, (key, value): (S, S)) -> Option<S> {
|
||||||
|
self.attributes.insert(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_child(&mut self, child: Node) {
|
||||||
|
self.children.push(child)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// checks if there is a namespace conflict within the element being built
|
||||||
|
pub fn namespace_conflict<S: AsRef<str>>(
|
||||||
|
&self
|
||||||
|
) -> bool {
|
||||||
|
self.namespace_conflict_recursive(&BTreeMap::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn namespace_conflict_recursive<S: AsRef<str>>(
|
||||||
|
&self,
|
||||||
|
parent_namespaces: &BTreeMap<Option<S>, S>,
|
||||||
|
) -> bool {
|
||||||
|
// create a new local_namespaces combining that in the context and those declared within the element
|
||||||
|
let mut local_namespaces = *parent_namespaces.clone();
|
||||||
|
self.namespace_declarations.iter().for_each(|prefix, declaration| local_namespaces.insert(prefix, declaration));
|
||||||
|
|
||||||
|
if let Some(namespace) = local_namespaces.get(self.prefix) {
|
||||||
|
if namespace != self.namespace {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
for child in *self.children {
|
||||||
|
if child.namespace_conflict(&local_namespaces) == false {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for possible conflicts in namespace
|
||||||
|
pub fn build(self) -> Result<Element> {
|
||||||
|
for child in self.children {
|
||||||
|
match child {
|
||||||
|
Node::Element(e) => {
|
||||||
|
if !e.namespace_conflict()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Element {
|
||||||
|
prefix: self.prefix,
|
||||||
|
localname: self.localname,
|
||||||
|
namespace: self.namespace,
|
||||||
|
namespace_declarations: self.namespace_declarations,
|
||||||
|
attributes: self.attributes,
|
||||||
|
children: self.children,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ElementError<'e> {
|
pub enum ElementError<'e> {
|
||||||
|
|
|
@ -7,7 +7,6 @@ use crate::error::SASLError;
|
||||||
use crate::JabberError;
|
use crate::JabberError;
|
||||||
|
|
||||||
use super::Element;
|
use super::Element;
|
||||||
use super::IntoElement;
|
|
||||||
|
|
||||||
const XMLNS: &str = "urn:ietf:params:xml:ns:xmpp-sasl";
|
const XMLNS: &str = "urn:ietf:params:xml:ns:xmpp-sasl";
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue