summaryrefslogblamecommitdiffstats
path: root/src/lib.rs
blob: 42eb7de15dfc484866ba35c470e1a5f0c492eb29 (plain) (tree)
1
2
3
4
5
6
7
8
9








                                 

        
























































































                                                                                           



            

                        

                 



                                                                                               

     
// TODO: logging (dropped errors)
#![allow(unused_must_use)]
use std::{
    net::{IpAddr, SocketAddr},
    str::FromStr,
};

use tokio::net::TcpStream;

mod jid;

pub struct Jabber {
    connection: Option<TcpStream>,
    login: jid::JID,
    password: String,
}

impl Jabber {
    fn new(login: jid::JID, password: String) -> Self {
        Self {
            connection: None,
            login,
            password,
        }
    }
    async fn resolve_client(&self) -> Vec<SocketAddr> {
        let mut socket_addrs = Vec::new();

        // if it's a socket/ip then just return that

        // socket
        if let Ok(socket_addr) = SocketAddr::from_str(&self.login.domainpart) {
            socket_addrs.push(socket_addr);
            return socket_addrs;
        }
        // ip
        if let Ok(ip) = IpAddr::from_str(&self.login.domainpart) {
            socket_addrs.push(SocketAddr::new(ip, 5222));
            socket_addrs.push(SocketAddr::new(ip, 5223));
            return socket_addrs;
        }

        // if port specified return name resolutions with specified port

        // otherwise resolve
        if let Ok(resolver) = trust_dns_resolver::AsyncResolver::tokio_from_system_conf() {
            if let Ok(lookup) = resolver
                .srv_lookup(format!("_xmpp-client._tcp.{}", self.login.domainpart))
                .await
            {
                for srv in lookup {
                    resolver
                        .lookup_ip(srv.target().to_owned())
                        .await
                        .map(|ips| {
                            for ip in ips {
                                socket_addrs.push(SocketAddr::new(ip, srv.port()))
                            }
                        });
                }
            }
            if let Ok(lookup) = resolver
                .srv_lookup(format!("_xmpps-client._tcp.{}", self.login.domainpart))
                .await
            {
                for srv in lookup {
                    resolver
                        .lookup_ip(srv.target().to_owned())
                        .await
                        .map(|ips| {
                            for ip in ips {
                                socket_addrs.push(SocketAddr::new(ip, srv.port()))
                            }
                        });
                }
            }

            // in case cannot connect through SRV records
            resolver.lookup_ip(&self.login.domainpart).await.map(|ips| {
                for ip in ips {
                    socket_addrs.push(SocketAddr::new(ip, 5222));
                    socket_addrs.push(SocketAddr::new(ip, 5223));
                }
            });
        }

        socket_addrs
    }

    async fn connect(&mut self) {
        for socket_addr in self.resolve_client().await {
            println!("trying {}", socket_addr);
            if let Ok(stream) = TcpStream::connect(socket_addr).await {
                println!("connected to {}", socket_addr);
                self.connection = Some(stream);
                return;
            }
        }
        println!("could not connect")
    }
}

#[cfg(test)]
mod tests {
    use crate::jid::JID;

    use super::*;

    #[tokio::test]
    async fn get_sockets() {
        let client = Jabber::new(JID::from_str("cel@blos.sm").unwrap(), "password".to_owned());
        println!("{:?}", client.resolve_client().await)
    }
}