use std::str; use quick_xml::{ events::{BytesStart, Event}, name::QName, se, NsReader, Writer, }; use tokio::io::{BufReader, ReadHalf, WriteHalf}; use tokio::net::TcpStream; use tokio_native_tls::native_tls::TlsConnector; use try_map::FallibleMapExt; use crate::error::JabberError; use crate::stanza::stream::Stream; use crate::stanza::DECLARATION; use crate::Jabber; use crate::Result; pub struct JabberClient<'j> { reader: NsReader>>, writer: Writer>, jabber: &'j mut Jabber<'j>, } impl<'j> JabberClient<'j> { pub fn new( reader: NsReader>>, writer: Writer>, jabber: &'j mut Jabber<'j>, ) -> Self { Self { reader, writer, jabber, } } pub async fn start_stream(&mut self) -> Result<()> { // client to server // declaration self.writer.write_event_async(DECLARATION).await?; // opening stream element let server = &self.jabber.server.to_owned().try_into()?; let stream_element = Stream::new_client(None, server, None, "en"); se::to_writer_with_root(&mut self.writer, "stream:stream", &stream_element); // server to client // may or may not send a declaration let 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> { // Element::read(&mut self.reader).await?.try_into() // } // pub async fn starttls(mut self) -> Result> { // 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) // } }