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 {
|
||||
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.
|
||||
|
|
|
@ -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 client;
|
||||
pub mod disco;
|
||||
pub mod muc;
|
||||
pub mod roster;
|
||||
pub mod sasl;
|
||||
|
|
Loading…
Reference in New Issue