forked from lavina/lavina
feat(xmpp): parse disco queries
This commit is contained in:
parent
0e78f24fbd
commit
7b2bfae147
|
@ -29,6 +29,28 @@ impl Jid {
|
||||||
pub fn to_string(&self) -> String {
|
pub fn to_string(&self) -> String {
|
||||||
format!("{}@{}/{}", self.name.0, self.server.0, self.resource.0)
|
format!("{}@{}/{}", self.name.0, self.server.0, self.resource.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_string(i: &str) -> Result<Jid> {
|
||||||
|
// TODO make regex static
|
||||||
|
use regex::Regex;
|
||||||
|
let re = Regex::new(r"^([a-zA-Z]+)@([a-zA-Z.]+)/([a-zA-Z\-]+)$").unwrap();
|
||||||
|
let m = re
|
||||||
|
.captures(i)
|
||||||
|
.ok_or(ffail!("Incorrectly format jid: {i}"))?;
|
||||||
|
|
||||||
|
let name = m.get(1).unwrap();
|
||||||
|
let name = Name(name.as_str().to_string());
|
||||||
|
let server = m.get(2).unwrap();
|
||||||
|
let server = Server(server.as_str().to_string());
|
||||||
|
let resource = m.get(3).unwrap();
|
||||||
|
let resource = Resource(resource.as_str().to_string());
|
||||||
|
|
||||||
|
Ok(Jid {
|
||||||
|
name,
|
||||||
|
server,
|
||||||
|
resource,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Request to bind to a resource.
|
/// Request to bind to a resource.
|
||||||
|
|
|
@ -0,0 +1,289 @@
|
||||||
|
use quick_xml::events::Event;
|
||||||
|
use quick_xml::name::ResolveResult;
|
||||||
|
|
||||||
|
use crate::prelude::*;
|
||||||
|
use crate::util::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#item";
|
||||||
|
|
||||||
|
|
||||||
|
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(bytes)?;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Identity {
|
||||||
|
category: String,
|
||||||
|
name: Option<String>,
|
||||||
|
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(bytes)?;
|
||||||
|
category = Some(s.to_owned())
|
||||||
|
}
|
||||||
|
b"name" => {
|
||||||
|
let s = std::str::from_utf8(bytes)?;
|
||||||
|
name = Some(s.to_owned())
|
||||||
|
}
|
||||||
|
b"type" => {
|
||||||
|
let s = std::str::from_utf8(bytes)?;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Feature {
|
||||||
|
pub var: 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(bytes)?;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(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(bytes)?;
|
||||||
|
name = Some(s.to_owned())
|
||||||
|
}
|
||||||
|
b"node" => {
|
||||||
|
let s = std::str::from_utf8(bytes)?;
|
||||||
|
node = Some(s.to_owned())
|
||||||
|
}
|
||||||
|
b"jid" => {
|
||||||
|
let s = std::str::from_utf8(bytes)?;
|
||||||
|
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;
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
pub mod bind;
|
pub mod bind;
|
||||||
pub mod client;
|
pub mod client;
|
||||||
|
pub mod disco;
|
||||||
pub mod muc;
|
pub mod muc;
|
||||||
pub mod roster;
|
pub mod roster;
|
||||||
pub mod sasl;
|
pub mod sasl;
|
||||||
|
|
Loading…
Reference in New Issue