forked from lavina/lavina
399 lines
12 KiB
Rust
399 lines
12 KiB
Rust
use quick_xml::events::attributes::Attribute;
|
|
use quick_xml::events::{BytesEnd, BytesStart, Event};
|
|
use quick_xml::name::{QName, ResolveResult};
|
|
|
|
use anyhow::{Result, anyhow as ffail};
|
|
use crate::xml::*;
|
|
|
|
use super::bind::Jid;
|
|
|
|
pub const XMLNS_INFO: &'static str = "http://jabber.org/protocol/disco#info";
|
|
pub const XMLNS_ITEM: &'static str = "http://jabber.org/protocol/disco#items";
|
|
|
|
#[derive(PartialEq, Eq, Debug)]
|
|
pub struct InfoQuery {
|
|
pub node: Option<String>,
|
|
pub identity: Vec<Identity>,
|
|
pub feature: Vec<Feature>,
|
|
}
|
|
|
|
impl FromXml for InfoQuery {
|
|
type P = impl Parser<Output = Result<Self>>;
|
|
|
|
fn parse() -> Self::P {
|
|
|(namespace, event): (ResolveResult<'static>, &'static Event<'static>)| -> Result<Self> {
|
|
let mut node = None;
|
|
let mut identity = vec![];
|
|
let mut feature = vec![];
|
|
let (bytes, end) = match event {
|
|
Event::Start(bytes) => (bytes, false),
|
|
Event::Empty(bytes) => (bytes, true),
|
|
_ => return Err(ffail!("Unexpected XML event: {event:?}")),
|
|
};
|
|
for attr in bytes.attributes() {
|
|
let attr = attr?;
|
|
match attr.key.0 {
|
|
b"node" => {
|
|
let s = std::str::from_utf8(&attr.value)?;
|
|
node = Some(s.to_owned())
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
if end {
|
|
return Ok(InfoQuery {
|
|
node,
|
|
identity,
|
|
feature,
|
|
});
|
|
}
|
|
loop {
|
|
let (namespace, event) = yield;
|
|
let bytes = match event {
|
|
Event::Start(bytes) => bytes,
|
|
Event::Empty(bytes) => bytes,
|
|
Event::End(_) => break,
|
|
_ => return Err(ffail!("Unexpected XML event: {event:?}")),
|
|
};
|
|
if bytes.name().0 == Identity::NAME.as_bytes() {
|
|
let res = delegate_parsing!(Identity, namespace, event)?;
|
|
identity.push(res);
|
|
} else if bytes.name().0 == Feature::NAME.as_bytes() {
|
|
let res = delegate_parsing!(Feature, namespace, event)?;
|
|
feature.push(res);
|
|
} else {
|
|
return Err(ffail!("Unexpected XML event: {event:?}"));
|
|
}
|
|
}
|
|
return Ok(InfoQuery {
|
|
node,
|
|
identity,
|
|
feature,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
impl FromXmlTag for InfoQuery {
|
|
const NAME: &'static str = "query";
|
|
|
|
const NS: &'static str = XMLNS_INFO;
|
|
}
|
|
|
|
impl ToXml for InfoQuery {
|
|
fn serialize(&self, events: &mut Vec<Event<'static>>) {
|
|
let mut bytes = BytesStart::new(format!(r#"query xmlns="{}""#, XMLNS_INFO));
|
|
if let Some(node) = &self.node {
|
|
bytes.push_attribute(Attribute {
|
|
key: QName(b"node"),
|
|
value: node.as_bytes().into(),
|
|
});
|
|
}
|
|
let empty = self.feature.is_empty() && self.identity.is_empty();
|
|
if empty {
|
|
events.push(Event::Empty(bytes));
|
|
} else {
|
|
events.push(Event::Start(bytes));
|
|
}
|
|
|
|
for i in &self.identity {
|
|
let mut bytes = BytesStart::new("identity");
|
|
bytes.push_attribute(Attribute {
|
|
key: QName(b"category"),
|
|
value: i.category.as_bytes().into(),
|
|
});
|
|
if let Some(name) = &i.name {
|
|
bytes.push_attribute(Attribute {
|
|
key: QName(b"name"),
|
|
value: name.as_bytes().into(),
|
|
});
|
|
}
|
|
bytes.push_attribute(Attribute {
|
|
key: QName(b"type"),
|
|
value: i.r#type.as_bytes().into(),
|
|
});
|
|
events.push(Event::Empty(bytes));
|
|
}
|
|
|
|
for f in &self.feature {
|
|
let mut bytes = BytesStart::new("feature");
|
|
bytes.push_attribute(Attribute {
|
|
key: QName(b"var"),
|
|
value: f.var.as_bytes().into(),
|
|
});
|
|
events.push(Event::Empty(bytes));
|
|
}
|
|
|
|
if !empty {
|
|
events.push(Event::End(BytesEnd::new("query")));
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(PartialEq, Eq, Debug)]
|
|
pub struct Identity {
|
|
pub category: String,
|
|
pub name: Option<String>,
|
|
pub r#type: String,
|
|
}
|
|
|
|
impl FromXml for Identity {
|
|
type P = impl Parser<Output = Result<Self>>;
|
|
|
|
fn parse() -> Self::P {
|
|
|(namespace, event): (ResolveResult<'static>, &'static Event<'static>)| -> Result<Self> {
|
|
let mut category = None;
|
|
let mut name = None;
|
|
let mut r#type = None;
|
|
let (bytes, end) = match event {
|
|
Event::Start(bytes) => (bytes, false),
|
|
Event::Empty(bytes) => (bytes, true),
|
|
_ => return Err(ffail!("Unexpected XML event: {event:?}")),
|
|
};
|
|
for attr in bytes.attributes() {
|
|
let attr = attr?;
|
|
match attr.key.0 {
|
|
b"category" => {
|
|
let s = std::str::from_utf8(&attr.value)?;
|
|
category = Some(s.to_owned())
|
|
}
|
|
b"name" => {
|
|
let s = std::str::from_utf8(&attr.value)?;
|
|
name = Some(s.to_owned())
|
|
}
|
|
b"type" => {
|
|
let s = std::str::from_utf8(&attr.value)?;
|
|
r#type = Some(s.to_owned())
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
let Some(category) = category else {
|
|
return Err(ffail!("No jid provided"));
|
|
};
|
|
let Some(r#type) = r#type else {
|
|
return Err(ffail!("No type provided"));
|
|
};
|
|
let item = Identity {
|
|
category,
|
|
name,
|
|
r#type,
|
|
};
|
|
if end {
|
|
return Ok(item);
|
|
}
|
|
|
|
let (namespace, event) = yield;
|
|
let Event::End(bytes) = event else {
|
|
return Err(ffail!("Unexpected XML event: {event:?}"));
|
|
};
|
|
Ok(item)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl FromXmlTag for Identity {
|
|
const NAME: &'static str = "identity";
|
|
|
|
const NS: &'static str = XMLNS_INFO;
|
|
}
|
|
|
|
#[derive(PartialEq, Eq, Debug)]
|
|
pub struct Feature {
|
|
pub var: String,
|
|
}
|
|
|
|
impl Feature {
|
|
pub fn new(s: &str) -> Feature {
|
|
Feature { var: s.to_string() }
|
|
}
|
|
}
|
|
|
|
impl FromXml for Feature {
|
|
type P = impl Parser<Output = Result<Self>>;
|
|
|
|
fn parse() -> Self::P {
|
|
|(namespace, event): (ResolveResult<'static>, &'static Event<'static>)| -> Result<Self> {
|
|
let mut var = None;
|
|
let (bytes, end) = match event {
|
|
Event::Start(bytes) => (bytes, false),
|
|
Event::Empty(bytes) => (bytes, true),
|
|
_ => return Err(ffail!("Unexpected XML event: {event:?}")),
|
|
};
|
|
for attr in bytes.attributes() {
|
|
let attr = attr?;
|
|
match attr.key.0 {
|
|
b"var" => {
|
|
let s = std::str::from_utf8(&attr.value)?;
|
|
var = Some(s.to_owned())
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
let Some(var) = var else {
|
|
return Err(ffail!("No jid provided"));
|
|
};
|
|
let item = Feature { var };
|
|
if end {
|
|
return Ok(item);
|
|
}
|
|
|
|
let (namespace, event) = yield;
|
|
let Event::End(bytes) = event else {
|
|
return Err(ffail!("Unexpected XML event: {event:?}"));
|
|
};
|
|
Ok(item)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl FromXmlTag for Feature {
|
|
const NAME: &'static str = "feature";
|
|
|
|
const NS: &'static str = XMLNS_INFO;
|
|
}
|
|
|
|
#[derive(PartialEq, Eq, Debug)]
|
|
pub struct ItemQuery {
|
|
pub item: Vec<Item>,
|
|
}
|
|
|
|
impl FromXml for ItemQuery {
|
|
type P = impl Parser<Output = Result<Self>>;
|
|
|
|
fn parse() -> Self::P {
|
|
|(namespace, event): (ResolveResult<'static>, &'static Event<'static>)| -> Result<Self> {
|
|
let mut item = vec![];
|
|
let (bytes, end) = match event {
|
|
Event::Start(bytes) => (bytes, false),
|
|
Event::Empty(bytes) => (bytes, true),
|
|
_ => return Err(ffail!("Unexpected XML event: {event:?}")),
|
|
};
|
|
if end {
|
|
return Ok(ItemQuery { item });
|
|
}
|
|
loop {
|
|
let (namespace, event) = yield;
|
|
let bytes = match event {
|
|
Event::Start(bytes) => bytes,
|
|
Event::Empty(bytes) => bytes,
|
|
Event::End(_) => break,
|
|
_ => return Err(ffail!("Unexpected XML event: {event:?}")),
|
|
};
|
|
if bytes.name().0 == Item::NAME.as_bytes() {
|
|
let res = delegate_parsing!(Item, namespace, event)?;
|
|
item.push(res);
|
|
} else {
|
|
return Err(ffail!("Unexpected XML event: {event:?}"));
|
|
}
|
|
}
|
|
Ok(ItemQuery { item })
|
|
}
|
|
}
|
|
}
|
|
|
|
impl FromXmlTag for ItemQuery {
|
|
const NAME: &'static str = "query";
|
|
|
|
const NS: &'static str = XMLNS_ITEM;
|
|
}
|
|
|
|
impl ToXml for ItemQuery {
|
|
fn serialize(&self, events: &mut Vec<Event<'static>>) {
|
|
let mut bytes = BytesStart::new(format!(r#"query xmlns="{}""#, XMLNS_ITEM));
|
|
let empty = self.item.is_empty();
|
|
if empty {
|
|
events.push(Event::Empty(bytes));
|
|
} else {
|
|
events.push(Event::Start(bytes));
|
|
}
|
|
|
|
for f in &self.item {
|
|
let mut bytes = BytesStart::new("item");
|
|
bytes.push_attribute(Attribute {
|
|
key: QName(b"jid"),
|
|
value: f.jid.to_string().into_bytes().into(),
|
|
});
|
|
if let Some(name) = &f.name {
|
|
bytes.push_attribute(Attribute {
|
|
key: QName(b"name"),
|
|
value: name.as_bytes().into(),
|
|
});
|
|
}
|
|
if let Some(node) = &f.node {
|
|
bytes.push_attribute(Attribute {
|
|
key: QName(b"node"),
|
|
value: node.as_bytes().into(),
|
|
});
|
|
}
|
|
events.push(Event::Empty(bytes));
|
|
}
|
|
|
|
if !empty {
|
|
events.push(Event::End(BytesEnd::new("query")));
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(PartialEq, Eq, Debug)]
|
|
pub struct Item {
|
|
pub jid: super::bind::Jid,
|
|
pub name: Option<String>,
|
|
pub node: Option<String>,
|
|
}
|
|
|
|
impl FromXml for Item {
|
|
type P = impl Parser<Output = Result<Self>>;
|
|
|
|
fn parse() -> Self::P {
|
|
|(namespace, event): (ResolveResult<'static>, &'static Event<'static>)| -> Result<Self> {
|
|
let mut jid = None;
|
|
let mut name = None;
|
|
let mut node = None;
|
|
let (bytes, end) = match event {
|
|
Event::Start(bytes) => (bytes, false),
|
|
Event::Empty(bytes) => (bytes, true),
|
|
_ => return Err(ffail!("Unexpected XML event: {event:?}")),
|
|
};
|
|
for attr in bytes.attributes() {
|
|
let attr = attr?;
|
|
match attr.key.0 {
|
|
b"name" => {
|
|
let s = std::str::from_utf8(&attr.value)?;
|
|
name = Some(s.to_owned())
|
|
}
|
|
b"node" => {
|
|
let s = std::str::from_utf8(&attr.value)?;
|
|
node = Some(s.to_owned())
|
|
}
|
|
b"jid" => {
|
|
let s = std::str::from_utf8(&attr.value)?;
|
|
let s = Jid::from_string(s)?;
|
|
jid = Some(s)
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
let Some(jid) = jid else {
|
|
return Err(ffail!("No jid provided"));
|
|
};
|
|
let item = Item { jid, name, node };
|
|
if end {
|
|
return Ok(item);
|
|
}
|
|
|
|
let (namespace, event) = yield;
|
|
let Event::End(bytes) = event else {
|
|
return Err(ffail!("Unexpected XML event: {event:?}"));
|
|
};
|
|
Ok(item)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl FromXmlTag for Item {
|
|
const NAME: &'static str = "item";
|
|
|
|
const NS: &'static str = XMLNS_ITEM;
|
|
}
|