Cargo.toml 🔗
@@ -13,3 +13,4 @@ native-tls = "*"
tokio-tls = "*"
sasl = "*"
rustc-serialize = "*"
+jid = "*"
Astro created
Cargo.toml | 1 +
examples/echo_bot.rs | 10 +++++++++-
src/lib.rs | 1 +
src/starttls.rs | 15 +++++++--------
src/stream_start.rs | 10 +++++++---
src/tcp.rs | 7 +++++--
src/xmpp_stream.rs | 20 +++++++++++++-------
7 files changed, 43 insertions(+), 21 deletions(-)
@@ -13,3 +13,4 @@ native-tls = "*"
tokio-tls = "*"
sasl = "*"
rustc-serialize = "*"
+jid = "*"
@@ -1,13 +1,19 @@
extern crate futures;
extern crate tokio_core;
extern crate tokio_xmpp;
+extern crate jid;
+use std::str::FromStr;
use tokio_core::reactor::Core;
use futures::{Future, Stream};
use tokio_xmpp::TcpClient;
use tokio_xmpp::xmpp_codec::Packet;
+use jid::Jid;
fn main() {
+ let jid = Jid::from_str("astrobot@example.net").expect("JID");
+ let password = "".to_owned();
+
use std::net::ToSocketAddrs;
let addr = "[2a01:4f8:a0:33d0::5]:5222"
.to_socket_addrs().unwrap()
@@ -15,6 +21,7 @@ fn main() {
let mut core = Core::new().unwrap();
let client = TcpClient::connect(
+ jid.clone(),
&addr,
&core.handle()
).map_err(|e| format!("{}", e)
@@ -25,7 +32,8 @@ fn main() {
panic!("No STARTTLS")
}
}).and_then(|stream| {
- stream.auth("astrobot", "").expect("auth")
+ let username = jid.node.as_ref().unwrap().to_owned();
+ stream.auth(username, password).expect("auth")
}).and_then(|stream| {
stream.for_each(|event| {
match event {
@@ -8,6 +8,7 @@ extern crate native_tls;
extern crate tokio_tls;
extern crate sasl;
extern crate rustc_serialize as serialize;
+extern crate jid;
pub mod xmpp_codec;
@@ -6,6 +6,7 @@ use tokio_io::{AsyncRead, AsyncWrite};
use tokio_tls::*;
use native_tls::TlsConnector;
use xml;
+use jid::Jid;
use xmpp_codec::*;
use xmpp_stream::*;
@@ -16,7 +17,7 @@ pub const NS_XMPP_TLS: &str = "urn:ietf:params:xml:ns:xmpp-tls";
pub struct StartTlsClient<S: AsyncRead + AsyncWrite> {
state: StartTlsClientState<S>,
- domain: String,
+ jid: Jid,
}
enum StartTlsClientState<S: AsyncRead + AsyncWrite> {
@@ -30,9 +31,7 @@ enum StartTlsClientState<S: AsyncRead + AsyncWrite> {
impl<S: AsyncRead + AsyncWrite> StartTlsClient<S> {
/// Waits for <stream:features>
pub fn from_stream(xmpp_stream: XMPPStream<S>) -> Self {
- let domain = xmpp_stream.stream_attrs.get("from")
- .map(|s| s.to_owned())
- .unwrap_or_else(|| String::new());
+ let jid = xmpp_stream.jid.clone();
let nonza = xml::Element::new(
"starttls".to_owned(), Some(NS_XMPP_TLS.to_owned()),
@@ -44,7 +43,7 @@ impl<S: AsyncRead + AsyncWrite> StartTlsClient<S> {
StartTlsClient {
state: StartTlsClientState::SendStartTls(send),
- domain,
+ jid,
}
}
}
@@ -77,10 +76,10 @@ impl<S: AsyncRead + AsyncWrite> Future for StartTlsClient<S> {
if stanza.name == "proceed" =>
{
println!("* proceed *");
- let stream = xmpp_stream.into_inner();
+ let stream = xmpp_stream.stream.into_inner();
let connect = TlsConnector::builder().unwrap()
.build().unwrap()
- .connect_async(&self.domain, stream);
+ .connect_async(&self.jid.domain, stream);
let new_state = StartTlsClientState::StartingTls(connect);
retry = true;
(new_state, Ok(Async::NotReady))
@@ -98,7 +97,7 @@ impl<S: AsyncRead + AsyncWrite> Future for StartTlsClient<S> {
match connect.poll() {
Ok(Async::Ready(tls_stream)) => {
println!("Got a TLS stream!");
- let start = XMPPStream::from_stream(tls_stream, self.domain.clone());
+ let start = XMPPStream::from_stream(tls_stream, self.jid.clone());
let new_state = StartTlsClientState::Start(start);
retry = true;
(new_state, Ok(Async::NotReady))
@@ -4,6 +4,7 @@ use std::collections::HashMap;
use futures::*;
use tokio_io::{AsyncRead, AsyncWrite};
use tokio_io::codec::Framed;
+use jid::Jid;
use xmpp_codec::*;
use xmpp_stream::*;
@@ -12,6 +13,7 @@ const NS_XMPP_STREAM: &str = "http://etherx.jabber.org/streams";
pub struct StreamStart<S: AsyncWrite> {
state: StreamStartState<S>,
+ jid: Jid,
}
enum StreamStartState<S: AsyncWrite> {
@@ -22,8 +24,8 @@ enum StreamStartState<S: AsyncWrite> {
}
impl<S: AsyncWrite> StreamStart<S> {
- pub fn from_stream(stream: Framed<S, XMPPCodec>, to: String) -> Self {
- let attrs = [("to".to_owned(), to),
+ pub fn from_stream(stream: Framed<S, XMPPCodec>, jid: Jid) -> Self {
+ let attrs = [("to".to_owned(), jid.domain.clone()),
("version".to_owned(), "1.0".to_owned()),
("xmlns".to_owned(), "jabber:client".to_owned()),
("xmlns:stream".to_owned(), NS_XMPP_STREAM.to_owned()),
@@ -32,6 +34,7 @@ impl<S: AsyncWrite> StreamStart<S> {
StreamStart {
state: StreamStartState::SendStart(send),
+ jid,
}
}
}
@@ -75,7 +78,8 @@ impl<S: AsyncRead + AsyncWrite> Future for StreamStart<S> {
Ok(Async::Ready(Some(Packet::Stanza(stanza)))) =>
if stanza.name == "features"
&& stanza.ns == Some(NS_XMPP_STREAM.to_owned()) {
- (StreamStartState::Invalid, Ok(Async::Ready(XMPPStream::new(stream, stream_attrs, stanza))))
+ let stream = XMPPStream::new(self.jid.clone(), stream, stream_attrs, stanza);
+ (StreamStartState::Invalid, Ok(Async::Ready(stream)))
} else {
(StreamStartState::RecvFeatures(stream, stream_attrs), Ok(Async::NotReady))
},
@@ -3,12 +3,14 @@ use std::io::Error;
use futures::{Future, Poll, Async};
use tokio_core::reactor::Handle;
use tokio_core::net::{TcpStream, TcpStreamNew};
+use jid::Jid;
use xmpp_stream::*;
use stream_start::StreamStart;
pub struct TcpClient {
state: TcpClientState,
+ jid: Jid,
}
enum TcpClientState {
@@ -18,10 +20,11 @@ enum TcpClientState {
}
impl TcpClient {
- pub fn connect(addr: &SocketAddr, handle: &Handle) -> Self {
+ pub fn connect(jid: Jid, addr: &SocketAddr, handle: &Handle) -> Self {
let tcp_stream_new = TcpStream::connect(addr, handle);
TcpClient {
state: TcpClientState::Connecting(tcp_stream_new),
+ jid,
}
}
}
@@ -34,7 +37,7 @@ impl Future for TcpClient {
let (new_state, result) = match self.state {
TcpClientState::Connecting(ref mut tcp_stream_new) => {
let tcp_stream = try_ready!(tcp_stream_new.poll());
- let start = XMPPStream::from_stream(tcp_stream, "spaceboyz.net".to_owned());
+ let start = XMPPStream::from_stream(tcp_stream, self.jid.clone());
let new_state = TcpClientState::Start(start);
(new_state, Ok(Async::NotReady))
},
@@ -5,6 +5,7 @@ use tokio_io::{AsyncRead, AsyncWrite};
use tokio_io::codec::Framed;
use xml;
use sasl::common::Credentials;
+use jid::Jid;
use xmpp_codec::*;
use stream_start::*;
@@ -14,15 +15,23 @@ use client_auth::ClientAuth;
pub const NS_XMPP_STREAM: &str = "http://etherx.jabber.org/streams";
pub struct XMPPStream<S> {
+ pub jid: Jid,
pub stream: Framed<S, XMPPCodec>,
pub stream_attrs: HashMap<String, String>,
pub stream_features: xml::Element,
}
impl<S: AsyncRead + AsyncWrite> XMPPStream<S> {
- pub fn from_stream(stream: S, to: String) -> StreamStart<S> {
+ pub fn new(jid: Jid,
+ stream: Framed<S, XMPPCodec>,
+ stream_attrs: HashMap<String, String>,
+ stream_features: xml::Element) -> Self {
+ XMPPStream { jid, stream, stream_attrs, stream_features }
+ }
+
+ pub fn from_stream(stream: S, jid: Jid) -> StreamStart<S> {
let xmpp_stream = AsyncRead::framed(stream, XMPPCodec::new());
- StreamStart::from_stream(xmpp_stream, to)
+ StreamStart::from_stream(xmpp_stream, jid)
}
pub fn into_inner(self) -> S {
@@ -30,10 +39,7 @@ impl<S: AsyncRead + AsyncWrite> XMPPStream<S> {
}
pub fn restart(self) -> StreamStart<S> {
- let to = self.stream_attrs.get("from")
- .map(|s| s.to_owned())
- .unwrap_or_else(|| "".to_owned());
- Self::from_stream(self.into_inner(), to.clone())
+ Self::from_stream(self.stream.into_inner(), self.jid)
}
pub fn can_starttls(&self) -> bool {
@@ -46,7 +52,7 @@ impl<S: AsyncRead + AsyncWrite> XMPPStream<S> {
StartTlsClient::from_stream(self)
}
- pub fn auth(self, username: &str, password: &str) -> Result<ClientAuth<S>, String> {
+ pub fn auth(self, username: String, password: String) -> Result<ClientAuth<S>, String> {
let creds = Credentials::default()
.with_username(username)
.with_password(password);