diff options
Diffstat (limited to 'src/jabber.rs')
-rw-r--r-- | src/jabber.rs | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/src/jabber.rs b/src/jabber.rs new file mode 100644 index 0000000..a1f6272 --- /dev/null +++ b/src/jabber.rs @@ -0,0 +1,131 @@ +use std::marker::PhantomData; +use std::net::{IpAddr, SocketAddr}; +use std::str::FromStr; + +use quick_xml::{Reader, Writer}; +use tokio::io::BufReader; +use tokio::net::TcpStream; +use tokio_native_tls::native_tls::TlsConnector; + +use crate::client; +use crate::client::JabberClientType; +use crate::jid::JID; +use crate::{JabberError, Result}; + +pub struct Jabber<'j> { + pub jid: JID, + pub password: String, + pub server: String, + _marker: PhantomData<&'j ()>, +} + +impl<'j> Jabber<'j> { + pub fn new(jid: JID, password: String) -> Self { + let server = jid.domainpart.clone(); + Self { + jid, + password, + server, + _marker: PhantomData, + } + } + + async fn get_sockets(&self) -> Vec<(SocketAddr, bool)> { + 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.jid.domainpart) { + match socket_addr.port() { + 5223 => socket_addrs.push((socket_addr, true)), + _ => socket_addrs.push((socket_addr, false)), + } + + return socket_addrs; + } + // ip + if let Ok(ip) = IpAddr::from_str(&self.jid.domainpart) { + socket_addrs.push((SocketAddr::new(ip, 5222), false)); + socket_addrs.push((SocketAddr::new(ip, 5223), true)); + return socket_addrs; + } + + // 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.jid.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()), false)) + } + }); + } + } + if let Ok(lookup) = resolver + .srv_lookup(format!("_xmpps-client._tcp.{}", self.jid.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()), true)) + } + }); + } + } + + // in case cannot connect through SRV records + resolver.lookup_ip(&self.jid.domainpart).await.map(|ips| { + for ip in ips { + socket_addrs.push((SocketAddr::new(ip, 5222), false)); + socket_addrs.push((SocketAddr::new(ip, 5223), true)); + } + }); + } + socket_addrs + } + + pub async fn connect(&'j mut self) -> Result<JabberClientType> { + for (socket_addr, is_tls) in self.get_sockets().await { + println!("trying {}", socket_addr); + match is_tls { + true => { + let socket = TcpStream::connect(socket_addr).await.unwrap(); + let connector = TlsConnector::new().unwrap(); + if let Ok(stream) = tokio_native_tls::TlsConnector::from(connector) + .connect(&self.server, socket) + .await + { + let (read, write) = tokio::io::split(stream); + let reader = Reader::from_reader(BufReader::new(read)); + let writer = Writer::new(write); + return Ok(JabberClientType::Encrypted( + client::encrypted::JabberClient::new(reader, writer, self), + )); + } + } + false => { + if let Ok(stream) = TcpStream::connect(socket_addr).await { + let (read, write) = tokio::io::split(stream); + let reader = Reader::from_reader(BufReader::new(read)); + let writer = Writer::new(write); + return Ok(JabberClientType::Unencrypted( + client::unencrypted::JabberClient::new(reader, writer, self), + )); + } + } + } + } + Err(JabberError::ConnectionError) + } +} |