use quick_xml::events::attributes::Attribute; use quick_xml::events::{BytesEnd, BytesStart, Event}; use quick_xml::name::{QName, ResolveResult}; use crate::xml::*; use anyhow::{anyhow as ffail, Result}; 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, pub identity: Vec, pub feature: Vec, } impl FromXml for InfoQuery { type P = impl Parser>; fn parse() -> Self::P { |(mut namespace, mut 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(&attr.value)?; node = Some(s.to_owned()) } _ => {} } } if end { return Ok(InfoQuery { node, identity, feature, }); } loop { (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>) { 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, pub r#type: String, } impl FromXml for Identity { type P = impl Parser>; fn parse() -> Self::P { |(mut namespace, mut 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(&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); } (namespace, event) = yield; let Event::End(_) = 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>; fn parse() -> Self::P { |(mut namespace, mut 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(&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); } (namespace, event) = yield; let Event::End(_) = 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 { |(mut namespace, mut event): (ResolveResult<'static>, &'static Event<'static>)| -> Result { let mut item = vec![]; let (_, 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 { (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>) { let 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, pub node: Option, } impl FromXml for Item { type P = impl Parser>; fn parse() -> Self::P { |(_, mut 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(&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); } (_, event) = yield; let Event::End(_) = 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; }