1use std::sync::Arc;
2use std::collections::HashMap;
3use futures::*;
4use tokio_io::{AsyncRead, AsyncWrite};
5use tokio_io::codec::Framed;
6use rustls::ClientConfig;
7use xml;
8
9use xmpp_codec::*;
10use stream_start::*;
11use starttls::{NS_XMPP_TLS, StartTlsClient};
12
13pub const NS_XMPP_STREAM: &str = "http://etherx.jabber.org/streams";
14
15pub struct XMPPStream<S> {
16 pub stream: Framed<S, XMPPCodec>,
17 pub stream_attrs: HashMap<String, String>,
18 pub stream_features: xml::Element,
19}
20
21impl<S: AsyncRead + AsyncWrite> XMPPStream<S> {
22 pub fn from_stream(stream: S, to: String) -> StreamStart<S> {
23 let xmpp_stream = AsyncRead::framed(stream, XMPPCodec::new());
24 StreamStart::from_stream(xmpp_stream, to)
25 }
26
27 pub fn into_inner(self) -> S {
28 self.stream.into_inner()
29 }
30
31 pub fn can_starttls(&self) -> bool {
32 self.stream_features
33 .get_child("starttls", Some(NS_XMPP_TLS))
34 .is_some()
35 }
36
37 pub fn starttls(self, arc_config: Arc<ClientConfig>) -> StartTlsClient<S> {
38 StartTlsClient::from_stream(self, arc_config)
39 }
40}
41
42impl<S: AsyncWrite> Sink for XMPPStream<S> {
43 type SinkItem = <Framed<S, XMPPCodec> as Sink>::SinkItem;
44 type SinkError = <Framed<S, XMPPCodec> as Sink>::SinkError;
45
46 fn start_send(&mut self, item: Self::SinkItem) -> StartSend<Self::SinkItem, Self::SinkError> {
47 self.stream.start_send(item)
48 }
49
50 fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
51 self.stream.poll_complete()
52 }
53}
54
55impl<S: AsyncRead> Stream for XMPPStream<S> {
56 type Item = <Framed<S, XMPPCodec> as Stream>::Item;
57 type Error = <Framed<S, XMPPCodec> as Stream>::Error;
58
59 fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
60 self.stream.poll()
61 }
62}