2023-07-11 21:28:42 +01:00
|
|
|
use std::str;
|
2023-06-19 19:23:54 +01:00
|
|
|
|
2023-07-11 21:28:42 +01:00
|
|
|
use quick_xml::{
|
|
|
|
events::{BytesStart, Event},
|
|
|
|
name::QName,
|
|
|
|
};
|
2023-07-04 21:27:15 +01:00
|
|
|
|
2023-07-12 12:41:36 +01:00
|
|
|
use super::Element;
|
|
|
|
use crate::{JabberError, Result, JID};
|
2023-07-11 21:28:42 +01:00
|
|
|
|
|
|
|
const XMLNS_STREAM: &str = "http://etherx.jabber.org/streams";
|
|
|
|
const VERSION: &str = "1.0";
|
|
|
|
|
|
|
|
enum XMLNS {
|
|
|
|
Client,
|
|
|
|
Server,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<XMLNS> for &str {
|
|
|
|
fn from(xmlns: XMLNS) -> Self {
|
|
|
|
match xmlns {
|
|
|
|
XMLNS::Client => return "jabber:client",
|
|
|
|
XMLNS::Server => return "jabber:server",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TryInto<XMLNS> for &str {
|
|
|
|
type Error = JabberError;
|
|
|
|
|
|
|
|
fn try_into(self) -> Result<XMLNS> {
|
|
|
|
match self {
|
|
|
|
"jabber:client" => Ok(XMLNS::Client),
|
|
|
|
"jabber:server" => Ok(XMLNS::Server),
|
|
|
|
_ => Err(JabberError::UnknownNamespace),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Stream {
|
|
|
|
from: Option<JID>,
|
2023-06-19 19:23:54 +01:00
|
|
|
id: Option<String>,
|
2023-07-11 21:28:42 +01:00
|
|
|
to: Option<JID>,
|
|
|
|
version: Option<String>,
|
2023-06-19 19:23:54 +01:00
|
|
|
lang: Option<String>,
|
2023-07-12 13:03:04 +01:00
|
|
|
ns: XMLNS,
|
2023-06-19 19:23:54 +01:00
|
|
|
}
|
|
|
|
|
2023-07-11 21:28:42 +01:00
|
|
|
impl Stream {
|
|
|
|
pub fn new_client(from: &JID, to: &JID, id: Option<String>, lang: Option<String>) -> Self {
|
|
|
|
Self {
|
|
|
|
from: Some(from.clone()),
|
|
|
|
id,
|
|
|
|
to: Some(to.clone()),
|
|
|
|
version: Some(VERSION.to_owned()),
|
|
|
|
lang,
|
2023-07-12 13:03:04 +01:00
|
|
|
ns: XMLNS::Client,
|
2023-07-11 21:28:42 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-12 21:11:20 +01:00
|
|
|
fn event(&self) -> Event<'static> {
|
2023-07-11 21:28:42 +01:00
|
|
|
let mut start = BytesStart::new("stream:stream");
|
|
|
|
if let Some(from) = &self.from {
|
|
|
|
start.push_attribute(("from", from.to_string().as_str()));
|
|
|
|
}
|
|
|
|
if let Some(id) = &self.id {
|
|
|
|
start.push_attribute(("id", id.as_str()));
|
|
|
|
}
|
|
|
|
if let Some(to) = &self.to {
|
|
|
|
start.push_attribute(("to", to.to_string().as_str()));
|
|
|
|
}
|
|
|
|
if let Some(version) = &self.version {
|
|
|
|
start.push_attribute(("version", version.to_string().as_str()));
|
|
|
|
}
|
|
|
|
if let Some(lang) = &self.lang {
|
|
|
|
start.push_attribute(("xml:lang", lang.as_str()));
|
|
|
|
}
|
2023-07-12 13:03:04 +01:00
|
|
|
match &self.ns {
|
|
|
|
XMLNS::Client => start.push_attribute(("xmlns", XMLNS::Client.into())),
|
|
|
|
XMLNS::Server => start.push_attribute(("xmlns", XMLNS::Server.into())),
|
|
|
|
}
|
2023-07-11 21:28:42 +01:00
|
|
|
start.push_attribute(("xmlns:stream", XMLNS_STREAM));
|
2023-07-12 21:11:20 +01:00
|
|
|
Event::Start(start)
|
2023-07-11 21:28:42 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'e> Into<Element<'e>> for Stream {
|
|
|
|
fn into(self) -> Element<'e> {
|
|
|
|
Element {
|
2023-07-12 21:11:20 +01:00
|
|
|
event: self.event(),
|
|
|
|
children: None,
|
2023-07-11 21:28:42 +01:00
|
|
|
}
|
|
|
|
}
|
2023-06-19 19:23:54 +01:00
|
|
|
}
|
|
|
|
|
2023-07-11 21:28:42 +01:00
|
|
|
impl<'e> TryFrom<Element<'e>> for Stream {
|
|
|
|
type Error = JabberError;
|
|
|
|
|
|
|
|
fn try_from(value: Element<'e>) -> Result<Stream> {
|
|
|
|
let (mut from, mut id, mut to, mut version, mut lang, mut ns) =
|
|
|
|
(None, None, None, None, None, XMLNS::Client);
|
|
|
|
if let Event::Start(e) = value.event.as_ref() {
|
|
|
|
for attribute in e.attributes() {
|
|
|
|
let attribute = attribute?;
|
|
|
|
match attribute.key {
|
|
|
|
QName(b"from") => {
|
|
|
|
from = Some(str::from_utf8(&attribute.value)?.to_string().try_into()?);
|
|
|
|
}
|
|
|
|
QName(b"id") => {
|
|
|
|
id = Some(str::from_utf8(&attribute.value)?.to_owned());
|
|
|
|
}
|
|
|
|
QName(b"to") => {
|
|
|
|
to = Some(str::from_utf8(&attribute.value)?.to_string().try_into()?);
|
|
|
|
}
|
|
|
|
QName(b"version") => {
|
|
|
|
version = Some(str::from_utf8(&attribute.value)?.to_owned());
|
|
|
|
}
|
|
|
|
QName(b"lang") => {
|
|
|
|
lang = Some(str::from_utf8(&attribute.value)?.to_owned());
|
|
|
|
}
|
|
|
|
QName(b"xmlns") => {
|
|
|
|
ns = str::from_utf8(&attribute.value)?.try_into()?;
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
println!("unknown attribute: {:?}", attribute)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(Stream {
|
|
|
|
from,
|
|
|
|
id,
|
|
|
|
to,
|
|
|
|
version,
|
|
|
|
lang,
|
2023-07-12 13:03:04 +01:00
|
|
|
ns,
|
2023-07-11 21:28:42 +01:00
|
|
|
})
|
|
|
|
} else {
|
|
|
|
Err(JabberError::ParseError)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(PartialEq, Debug)]
|
2023-06-19 19:23:54 +01:00
|
|
|
pub enum StreamFeature {
|
|
|
|
StartTls,
|
2023-07-11 21:28:42 +01:00
|
|
|
Sasl(Vec<String>),
|
2023-06-19 19:23:54 +01:00
|
|
|
Bind,
|
2023-07-04 21:27:15 +01:00
|
|
|
Unknown,
|
2023-06-19 19:23:54 +01:00
|
|
|
}
|
2023-07-11 21:28:42 +01:00
|
|
|
|
|
|
|
impl<'e> TryFrom<Element<'e>> for Vec<StreamFeature> {
|
|
|
|
type Error = JabberError;
|
|
|
|
|
|
|
|
fn try_from(features_element: Element) -> Result<Self> {
|
|
|
|
let mut features = Vec::new();
|
2023-07-12 21:11:20 +01:00
|
|
|
if let Some(children) = features_element.children {
|
|
|
|
for feature_element in children {
|
2023-07-11 21:28:42 +01:00
|
|
|
match feature_element.event {
|
|
|
|
Event::Start(e) => match e.name() {
|
|
|
|
QName(b"starttls") => features.push(StreamFeature::StartTls),
|
|
|
|
QName(b"mechanisms") => {
|
|
|
|
let mut mechanisms = Vec::new();
|
2023-07-12 21:11:20 +01:00
|
|
|
if let Some(children) = feature_element.children {
|
|
|
|
for mechanism_element in children {
|
|
|
|
if let Some(children) = mechanism_element.children {
|
|
|
|
for mechanism_text in children {
|
2023-07-11 21:28:42 +01:00
|
|
|
match mechanism_text.event {
|
|
|
|
Event::Text(e) => mechanisms
|
|
|
|
.push(str::from_utf8(e.as_ref())?.to_owned()),
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
features.push(StreamFeature::Sasl(mechanisms))
|
|
|
|
}
|
2023-08-02 00:56:38 +01:00
|
|
|
_ => features.push(StreamFeature::Unknown),
|
|
|
|
},
|
|
|
|
Event::Empty(e) => match e.name() {
|
|
|
|
QName(b"bind") => features.push(StreamFeature::Bind),
|
|
|
|
_ => features.push(StreamFeature::Unknown),
|
2023-07-11 21:28:42 +01:00
|
|
|
},
|
|
|
|
_ => features.push(StreamFeature::Unknown),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(features)
|
|
|
|
}
|
|
|
|
}
|