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 BIND_REQ_ID: &str = "resource-bind";
14
15pub async fn bind<S: AsyncRead + AsyncWrite + Unpin>(
16    mut stream: XMPPStream<S>,
17) -> Result<XMPPStream<S>, Error> {
18    if stream.stream_features.can_bind() {
19        let resource = if let Jid::Full(jid) = stream.jid.clone() {
20            Some(jid.resource)
21        } else {
22            None
23        };
24        let iq = Iq::from_set(BIND_REQ_ID, BindQuery::new(resource));
25        stream.send_stanza(iq).await?;
26
27        loop {
28            match stream.next().await {
29                Some(Ok(Packet::Stanza(stanza))) => match Iq::try_from(stanza) {
30                    Ok(iq) if iq.id == BIND_REQ_ID => match iq.payload {
31                        IqType::Result(payload) => {
32                            payload
33                                .and_then(|payload| BindResponse::try_from(payload).ok())
34                                .map(|bind| stream.jid = bind.into());
35                            return Ok(stream);
36                        }
37                        _ => return Err(ProtocolError::InvalidBindResponse.into()),
38                    },
39                    _ => {}
40                },
41                Some(Ok(_)) => {}
42                Some(Err(e)) => return Err(e),
43                None => return Err(Error::Disconnected),
44            }
45        }
46    } else {
47        // No resource binding available,
48        // return the (probably // usable) stream immediately
49        return Ok(stream);
50    }
51}