use std::sync::Arc;
use quick_xml::{events::Event, se::Serializer, NsReader, Writer};
use rsasl::prelude::SASLConfig;
use serde::Serialize;
use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt, BufReader, ReadHalf, WriteHalf};
use crate::connection::{Tls, Unencrypted};
use crate::error::JabberError;
use crate::stanza::stream::Stream;
use crate::stanza::DECLARATION;
use crate::Result;
use crate::JID;
pub struct Jabber<S>
where
S: AsyncRead + AsyncWrite + Unpin,
{
reader: NsReader<BufReader<ReadHalf<S>>>,
writer: Writer<WriteHalf<S>>,
jid: Option<JID>,
auth: Option<Arc<SASLConfig>>,
server: String,
}
impl<S> Jabber<S>
where
S: AsyncRead + AsyncWrite + Unpin,
{
pub fn new(
reader: ReadHalf<S>,
writer: WriteHalf<S>,
jid: Option<JID>,
auth: Option<Arc<SASLConfig>>,
server: String,
) -> Self {
let reader = NsReader::from_reader(BufReader::new(reader));
let writer = Writer::new(writer);
Self {
reader,
writer,
jid,
auth,
server,
}
}
}
impl<S> Jabber<S>
where
S: AsyncRead + AsyncWrite + Unpin,
Writer<tokio::io::WriteHalf<S>>: AsyncWriteExt,
Writer<tokio::io::WriteHalf<S>>: AsyncWrite,
{
pub async fn start_stream(&mut self) -> Result<()> {
// client to server
// declaration
self.writer.write_event_async(DECLARATION.clone()).await?;
// opening stream element
let server = &self.server.to_owned().try_into()?;
let stream_element = Stream::new_client(None, server, None, "en");
// TODO: nicer function to serialize to xml writer
let mut buffer = String::new();
let ser = Serializer::new(&mut buffer);
stream_element.serialize(ser).unwrap();
self.writer.write_all(buffer.as_bytes());
// server to client
// may or may not send a declaration
let mut buf = Vec::new();
let mut first_event = self.reader.read_resolved_event_into_async(&mut buf).await?;
match first_event {
(quick_xml::name::ResolveResult::Unbound, Event::Decl(e)) => {
if let Ok(version) = e.version() {
if version.as_ref() == b"1.0" {
first_event = self.reader.read_resolved_event_into_async(&mut buf).await?
} else {
// todo: error
todo!()
}
} else {
first_event = self.reader.read_resolved_event_into_async(&mut buf).await?
}
}
_ => (),
}
// receive stream element and validate
let stream_response: Stream;
match first_event {
(quick_xml::name::ResolveResult::Bound(ns), Event::Start(e)) => {
if ns.0 == crate::stanza::stream::XMLNS.as_bytes() {
// stream_response = Stream::new(
// e.try_get_attribute("from")?.try_map(|attribute| {
// str::from_utf8(attribute.value.as_ref())?
// .try_into()?
// .as_ref()
// })?,
// e.try_get_attribute("to")?.try_map(|attribute| {
// str::from_utf8(attribute.value.as_ref())?
// .try_into()?
// .as_ref()
// })?,
// e.try_get_attribute("id")?.try_map(|attribute| {
// str::from_utf8(attribute.value.as_ref())?
// .try_into()?
// .as_ref()
// })?,
// e.try_get_attribute("version")?.try_map(|attribute| {
// str::from_utf8(attribute.value.as_ref())?
// .try_into()?
// .as_ref()
// })?,
// e.try_get_attribute("lang")?.try_map(|attribute| {
// str::from_utf8(attribute.value.as_ref())?
// .try_into()?
// .as_ref()
// })?,
// );
return Ok(());
} else {
return Err(JabberError::BadStream);
}
}
// TODO: errors for incorrect namespace
(quick_xml::name::ResolveResult::Unbound, Event::Decl(_)) => todo!(),
(quick_xml::name::ResolveResult::Unknown(_), Event::Start(_)) => todo!(),
(quick_xml::name::ResolveResult::Unknown(_), Event::End(_)) => todo!(),
(quick_xml::name::ResolveResult::Unknown(_), Event::Empty(_)) => todo!(),
(quick_xml::name::ResolveResult::Unknown(_), Event::Text(_)) => todo!(),
(quick_xml::name::ResolveResult::Unknown(_), Event::CData(_)) => todo!(),
(quick_xml::name::ResolveResult::Unknown(_), Event::Comment(_)) => todo!(),
(quick_xml::name::ResolveResult::Unknown(_), Event::Decl(_)) => todo!(),
(quick_xml::name::ResolveResult::Unknown(_), Event::PI(_)) => todo!(),
(quick_xml::name::ResolveResult::Unknown(_), Event::DocType(_)) => todo!(),
(quick_xml::name::ResolveResult::Unknown(_), Event::Eof) => todo!(),
(quick_xml::name::ResolveResult::Unbound, Event::Start(_)) => todo!(),
(quick_xml::name::ResolveResult::Unbound, Event::End(_)) => todo!(),
(quick_xml::name::ResolveResult::Unbound, Event::Empty(_)) => todo!(),
(quick_xml::name::ResolveResult::Unbound, Event::Text(_)) => todo!(),
(quick_xml::name::ResolveResult::Unbound, Event::CData(_)) => todo!(),
(quick_xml::name::ResolveResult::Unbound, Event::Comment(_)) => todo!(),
(quick_xml::name::ResolveResult::Unbound, Event::PI(_)) => todo!(),
(quick_xml::name::ResolveResult::Unbound, Event::DocType(_)) => todo!(),
(quick_xml::name::ResolveResult::Unbound, Event::Eof) => todo!(),
(quick_xml::name::ResolveResult::Bound(_), Event::End(_)) => todo!(),
(quick_xml::name::ResolveResult::Bound(_), Event::Empty(_)) => todo!(),
(quick_xml::name::ResolveResult::Bound(_), Event::Text(_)) => todo!(),
(quick_xml::name::ResolveResult::Bound(_), Event::CData(_)) => todo!(),
(quick_xml::name::ResolveResult::Bound(_), Event::Comment(_)) => todo!(),
(quick_xml::name::ResolveResult::Bound(_), Event::Decl(_)) => todo!(),
(quick_xml::name::ResolveResult::Bound(_), Event::PI(_)) => todo!(),
(quick_xml::name::ResolveResult::Bound(_), Event::DocType(_)) => todo!(),
(quick_xml::name::ResolveResult::Bound(_), Event::Eof) => todo!(),
}
}
}
// pub async fn get_features(&mut self) -> Result<Vec<StreamFeature>> {
// Element::read(&mut self.reader).await?.try_into()
// }
impl Jabber<Unencrypted> {
pub async fn starttls(mut self) -> Result<Jabber<Tls>> {
todo!()
}
// let mut starttls_element = BytesStart::new("starttls");
// starttls_element.push_attribute(("xmlns", "urn:ietf:params:xml:ns:xmpp-tls"));
// self.writer
// .write_event_async(Event::Empty(starttls_element))
// .await
// .unwrap();
// let mut buf = Vec::new();
// match self.reader.read_event_into_async(&mut buf).await.unwrap() {
// Event::Empty(e) => match e.name() {
// QName(b"proceed") => {
// let connector = TlsConnector::new().unwrap();
// let stream = self
// .reader
// .into_inner()
// .into_inner()
// .unsplit(self.writer.into_inner());
// if let Ok(tlsstream) = tokio_native_tls::TlsConnector::from(connector)
// .connect(&self.jabber.server, stream)
// .await
// {
// let (read, write) = tokio::io::split(tlsstream);
// let reader = Reader::from_reader(BufReader::new(read));
// let writer = Writer::new(write);
// let mut client =
// super::encrypted::JabberClient::new(reader, writer, self.jabber);
// client.start_stream().await?;
// return Ok(client);
// }
// }
// QName(_) => return Err(JabberError::TlsNegotiation),
// },
// _ => return Err(JabberError::TlsNegotiation),
// }
// Err(JabberError::TlsNegotiation)
// }
}