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"; #[derive(PartialEq, Eq, Debug)] pub struct InfoQuery { pub node: Option, pub identity: Vec, pub feature: Vec, } impl FromXml for InfoQuery { type P = impl Parser>; fn parse() -> Self::P { |(namespace, event): (ResolveResult<'static>, &'static Event<'static>)| -> Result { 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; } #[derive(PartialEq, Eq, Debug)] pub struct Identity { category: String, name: Option, r#type: String, } impl FromXml for Identity { type P = impl Parser>; fn parse() -> Self::P { |(namespace, event): (ResolveResult<'static>, &'static Event<'static>)| -> Result { 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; } #[derive(PartialEq, Eq, Debug)] pub struct Feature { pub var: String, } impl FromXml for Feature { type P = impl Parser>; fn parse() -> Self::P { |(namespace, event): (ResolveResult<'static>, &'static Event<'static>)| -> Result { 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; } #[derive(PartialEq, Eq, Debug)] pub struct ItemQuery { pub item: Vec, } impl FromXml for ItemQuery { type P = impl Parser>; fn parse() -> Self::P { |(namespace, event): (ResolveResult<'static>, &'static Event<'static>)| -> Result { 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(PartialEq, Eq, Debug)] pub struct Item { pub jid: super::bind::Jid, pub name: Option, pub node: Option, } impl FromXml for Item { type P = impl Parser>; fn parse() -> Self::P { |(namespace, event): (ResolveResult<'static>, &'static Event<'static>)| -> Result { 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; }