bind.rs

 1use futures::stream::StreamExt;
 2use std::convert::TryFrom;
 3use std::marker::Unpin;
 4use tokio::io::{AsyncRead, AsyncWrite};
 5use xmpp_parsers::bind::{BindQuery, BindResponse};
 6use xmpp_parsers::iq::{Iq, IqType};
 7use xmpp_parsers::Jid;
 8
 9use crate::xmpp_codec::Packet;
10use crate::xmpp_stream::XMPPStream;
11use crate::{Error, ProtocolError};
12
13const NS_XMPP_BIND: &str = "urn:ietf:params:xml:ns:xmpp-bind";
14const BIND_REQ_ID: &str = "resource-bind";
15
16pub async fn bind<S: AsyncRead + AsyncWrite + Unpin>(
17    mut stream: XMPPStream<S>,
18) -> Result<XMPPStream<S>, Error> {
19    match stream.stream_features.get_child("bind", NS_XMPP_BIND) {
20        None => {
21            // No resource binding available,
22            // return the (probably // usable) stream immediately
23            return Ok(stream);
24        }
25        Some(_) => {
26            let resource = if let Jid::Full(jid) = stream.jid.clone() {
27                Some(jid.resource)
28            } else {
29                None
30            };
31            let iq = Iq::from_set(BIND_REQ_ID, BindQuery::new(resource));
32            stream.send_stanza(iq).await?;
33
34            loop {
35                match stream.next().await {
36                    Some(Ok(Packet::Stanza(stanza))) => match Iq::try_from(stanza) {
37                        Ok(iq) if iq.id == BIND_REQ_ID => match iq.payload {
38                            IqType::Result(payload) => {
39                                payload
40                                    .and_then(|payload| BindResponse::try_from(payload).ok())
41                                    .map(|bind| stream.jid = bind.into());
42                                return Ok(stream);
43                            }
44                            _ => return Err(ProtocolError::InvalidBindResponse.into()),
45                        },
46                        _ => {}
47                    },
48                    Some(Ok(_)) => {}
49                    Some(Err(e)) => return Err(e),
50                    None => return Err(Error::Disconnected),
51                }
52            }
53        }
54    }
55}