diff --git a/Cargo.lock b/Cargo.lock index c0f9d4d..1dd64e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -95,6 +95,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + [[package]] name = "cpufeatures" version = "0.2.5" @@ -114,6 +120,19 @@ dependencies = [ "typenum", ] +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn", +] + [[package]] name = "digest" version = "0.10.6" @@ -425,6 +444,7 @@ version = "0.1.0" dependencies = [ "anyhow", "assert_matches", + "derive_more", "figment", "futures-util", "http-body-util", @@ -776,6 +796,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + [[package]] name = "rustls" version = "0.20.8" @@ -819,6 +848,12 @@ dependencies = [ "untrusted", ] +[[package]] +name = "semver" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" + [[package]] name = "serde" version = "1.0.152" diff --git a/Cargo.toml b/Cargo.toml index 42e279f..eb8fec7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ nom = "7.1.3" tokio-rustls = "0.23.4" rustls-pemfile = "1.0.2" quick-xml = { version = "0.27.1", features = ["async-tokio"] } +derive_more = "0.99.17" [dev-dependencies] assert_matches = "1.5.0" diff --git a/src/projections/xmpp/mod.rs b/src/projections/xmpp/mod.rs index 630861d..0fd98c4 100644 --- a/src/projections/xmpp/mod.rs +++ b/src/projections/xmpp/mod.rs @@ -1,3 +1,5 @@ +mod proto; + use std::collections::HashMap; use std::fs::File; use std::io::BufReader as SyncBufReader; diff --git a/src/projections/xmpp/proto.rs b/src/projections/xmpp/proto.rs new file mode 100644 index 0000000..8db2c4c --- /dev/null +++ b/src/projections/xmpp/proto.rs @@ -0,0 +1,71 @@ +use derive_more::From; +use quick_xml::events::Event; +use quick_xml::name::{Namespace, ResolveResult}; + +use crate::protos::xmpp::bind::BindRequest; +use crate::util::xml::{Continuation, FromXml, Parser}; + +use crate::prelude::*; + +#[derive(PartialEq, Eq, Debug, From)] +pub enum IqClientBody { + Bind(BindRequest), +} + +#[derive(From)] +pub struct IqClientBodyParser(IqClientBodyParserInner); + +#[derive(From)] +enum IqClientBodyParserInner { + Initial, + Bind(::P), +} + +impl FromXml for IqClientBody { + type P = IqClientBodyParser; + + fn parse() -> Self::P { + IqClientBodyParserInner::Initial.into() + } +} + +impl Parser for IqClientBodyParser { + type Output = Result; + + fn consume<'a>( + self: Self, + namespace: quick_xml::name::ResolveResult, + event: &quick_xml::events::Event<'a>, + ) -> crate::util::xml::Continuation { + use IqClientBodyParserInner::*; + match self.0 { + Initial => { + let Event::Start(bytes) = event else { + return Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))); + }; + if bytes.name().0 == BindRequest::NAME.as_bytes() + && namespace == ResolveResult::Bound(Namespace(BindRequest::NS.as_bytes())) + { + match BindRequest::parse().consume(namespace, event) { + Continuation::Final(Ok(r)) => Continuation::Final(Ok(r.into())), + Continuation::Final(Err(e)) => Continuation::Final(Err(e)), + Continuation::Continue(s) => { + let inner: IqClientBodyParserInner = s.into(); + Continuation::Continue(inner.into()) + } + } + } else { + Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))) + } + } + Bind(p) => match p.consume(namespace, event) { + Continuation::Final(Ok(r)) => Continuation::Final(Ok(r.into())), + Continuation::Final(Err(e)) => Continuation::Final(Err(e)), + Continuation::Continue(s) => { + let inner: IqClientBodyParserInner = s.into(); + Continuation::Continue(inner.into()) + } + }, + } + } +} diff --git a/src/protos/xmpp/bind.rs b/src/protos/xmpp/bind.rs index 3d53121..bf9b0e0 100644 --- a/src/protos/xmpp/bind.rs +++ b/src/protos/xmpp/bind.rs @@ -47,6 +47,11 @@ enum BindRequestParserInner { InBindResourceEnd(String), } +impl BindRequest { + pub const NS: &'static str = XMLNS; + pub const NAME: &'static str = "bind"; +} + impl FromXml for BindRequest { type P = BindRequestParser; @@ -70,7 +75,7 @@ impl Parser for BindRequestParser { let Event::Start(bytes) = event else { return Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))); }; - if bytes.name().0 != b"bind" { + if bytes.name().0 != BindRequest::NAME.as_bytes() { return Continuation::Final(Err(ffail!( "Unexpected XML tag: {:?}", bytes.name()