feat(xmpp): parse disco queries

This commit is contained in:
Nikita Vilunov 2023-03-27 23:45:44 +02:00
parent 0e78f24fbd
commit 7b2bfae147
3 changed files with 312 additions and 0 deletions

View File

@ -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.

289
src/protos/xmpp/disco.rs Normal file
View File

@ -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;
}

View File

@ -1,5 +1,6 @@
pub mod bind;
pub mod client;
pub mod disco;
pub mod muc;
pub mod roster;
pub mod sasl;