use anyhow::{anyhow, Result}; use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event}; use quick_xml::name::{Namespace, ResolveResult}; use std::io::Read; use crate::xml::*; pub const MAM_XMLNS: &'static str = "urn:xmpp:mam:2"; pub const DATA_XMLNS: &'static str = "jabber:x:data"; pub const RESULT_SET_XMLNS: &'static str = "http://jabber.org/protocol/rsm"; #[derive(PartialEq, Eq, Debug, Clone)] pub struct MessageArchiveRequest { pub x: Option, } #[derive(PartialEq, Eq, Debug, Clone)] pub struct X { pub fields: Vec, } #[derive(PartialEq, Eq, Debug, Clone)] pub struct Field { pub values: Vec, } // Message archive response styled as a result set. #[derive(PartialEq, Eq, Debug, Clone)] pub struct Fin { pub set: Set, } #[derive(PartialEq, Eq, Debug, Clone)] pub struct Set { pub count: Option, } impl ToXml for Fin { fn serialize(&self, events: &mut Vec>) { let fin_bytes = BytesStart::new(format!(r#"fin xmlns="{}" complete=True"#, MAM_XMLNS)); let set_bytes = BytesStart::new(format!(r#"set xmlns="{}""#, RESULT_SET_XMLNS)); events.push(Event::Start(fin_bytes)); events.push(Event::Start(set_bytes)); if let &Some(count) = &self.set.count { events.push(Event::Start(BytesStart::new("count"))); events.push(Event::Text(BytesText::new(count.to_string().as_str()).into_owned())); events.push(Event::End(BytesEnd::new("count"))); } events.push(Event::End(BytesEnd::new("set"))); events.push(Event::End(BytesEnd::new("fin"))); } } impl FromXmlTag for X { const NAME: &'static str = "x"; const NS: &'static str = DATA_XMLNS; } impl FromXmlTag for MessageArchiveRequest { const NAME: &'static str = "query"; const NS: &'static str = MAM_XMLNS; } impl FromXml for X { type P = impl Parser>; fn parse() -> Self::P { |(mut namespace, mut event): (ResolveResult<'static>, &'static Event<'static>)| -> Result { println!("X::parse {:?}", event); let bytes = match event { Event::Start(bytes) if bytes.name().0 == X::NAME.as_bytes() => bytes, Event::Empty(bytes) if bytes.name().0 == X::NAME.as_bytes() => return Ok(X { fields: vec![] }), _ => return Err(anyhow!("Unexpected XML event: {event:?}")), }; let mut fields = vec![]; loop { (namespace, event) = yield; match event { Event::Start(_) => { // start of let mut values = vec![]; loop { (namespace, event) = yield; match event { Event::Start(bytes) if bytes.name().0 == b"value" => { // start of } Event::End(bytes) if bytes.name().0 == b"field" => { // end of break; } _ => return Err(anyhow!("Unexpected XML event: {event:?}")), } (namespace, event) = yield; let text: String = match event { Event::Text(bytes) => { // text inside String::from_utf8(bytes.to_vec())? } _ => return Err(anyhow!("Unexpected XML event: {event:?}")), }; (namespace, event) = yield; match event { Event::End(bytes) if bytes.name().0 == b"value" => { // end of } _ => return Err(anyhow!("Unexpected XML event: {event:?}")), } values.push(text); } fields.push(Field { values }) } Event::End(bytes) if bytes.name().0 == X::NAME.as_bytes() => { // end of return Ok(X { fields }); } _ => return Err(anyhow!("Unexpected XML event: {event:?}")), } } } } } impl FromXml for MessageArchiveRequest { type P = impl Parser>; fn parse() -> Self::P { |(mut namespace, mut event): (ResolveResult<'static>, &'static Event<'static>)| -> Result { println!("MessageArchiveRequest::parse {:?}", event); let bytes = match event { Event::Empty(_) => return Ok(MessageArchiveRequest { x: None }), Event::Start(bytes) => bytes, _ => return Err(anyhow!("Unexpected XML event: {event:?}")), }; if bytes.name().0 != MessageArchiveRequest::NAME.as_bytes() { return Err(anyhow!("Unexpected XML tag: {:?}", bytes.name())); } let ResolveResult::Bound(Namespace(ns)) = namespace else { return Err(anyhow!("No namespace provided")); }; if ns != MAM_XMLNS.as_bytes() { return Err(anyhow!("Incorrect namespace")); } (namespace, event) = yield; match event { Event::End(bytes) if bytes.name().0 == MessageArchiveRequest::NAME.as_bytes() => { Ok(MessageArchiveRequest { x: None }) } Event::Start(bytes) | Event::Empty(bytes) if bytes.name().0 == X::NAME.as_bytes() => { let x = delegate_parsing!(X, namespace, event)?; Ok(MessageArchiveRequest { x: Some(x) }) } _ => Err(anyhow!("Unexpected XML event: {event:?}")), } } } } impl MessageArchiveRequest {} #[cfg(test)] mod tests { use super::*; use crate::bind::{Jid, Name, Server}; use crate::client::{Iq, IqType}; #[test] fn test_parse_archive_query() { let input = r#""#; let result: Iq = parse(input).unwrap(); assert_eq!( result, Iq { from: None, id: "juliet1".to_string(), to: Option::from(Jid { name: None, server: Server("pubsub.shakespeare.lit".into()), resource: None, }), r#type: IqType::Set, body: MessageArchiveRequest { x: None }, } ); } #[test] fn test_parse_query_messages_from_jid() { let input = r#"value1juliet@capulet.lit"#; let result: Iq = parse(input).unwrap(); assert_eq!( result, Iq { from: None, id: "juliet1".to_string(), to: None, r#type: IqType::Set, body: MessageArchiveRequest { x: Some(X { fields: vec![ Field { values: vec!["value1".to_string()], }, Field { values: vec!["juliet@capulet.lit".to_string()], }, ] }) }, } ); } #[test] fn test_parse_query_messages_from_jid_with_unclosed_tag() { let input = r#"value1juliet@capulet.lit"#; assert!(parse::>(input).is_err()) } }