2017-04-01 17:15:37 +01:00
|
|
|
use jid::Jid;
|
|
|
|
|
use transport::{Transport, PlainTransport};
|
|
|
|
|
use error::Error;
|
|
|
|
|
use ns;
|
2017-05-27 20:33:56 +02:00
|
|
|
use plugin::{Plugin, PluginInit, PluginProxyBinding, PluginContainer, PluginRef};
|
2017-05-27 18:41:54 +02:00
|
|
|
use event::{Dispatcher, ReceiveElement, SendElement, Propagation, Priority, Event};
|
2017-04-01 17:15:37 +01:00
|
|
|
use connection::{Connection, Component2S};
|
2017-05-02 17:21:26 +01:00
|
|
|
use sha_1::{Sha1, Digest};
|
2017-04-01 17:15:37 +01:00
|
|
|
|
|
|
|
|
use minidom::Element;
|
|
|
|
|
|
2017-12-28 06:04:50 +01:00
|
|
|
use quick_xml::events::Event as XmlEvent;
|
2017-04-01 17:15:37 +01:00
|
|
|
|
2017-12-28 06:04:50 +01:00
|
|
|
use std::str;
|
2017-05-02 17:21:26 +01:00
|
|
|
use std::fmt::Write;
|
2017-05-25 00:22:40 +01:00
|
|
|
use std::sync::{Mutex, Arc};
|
|
|
|
|
|
2017-04-01 17:15:37 +01:00
|
|
|
/// A builder for `Component`s.
|
|
|
|
|
pub struct ComponentBuilder {
|
|
|
|
|
jid: Jid,
|
|
|
|
|
secret: String,
|
|
|
|
|
host: Option<String>,
|
|
|
|
|
port: u16,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ComponentBuilder {
|
|
|
|
|
/// Creates a new builder for an XMPP component that will connect to `jid` with default parameters.
|
|
|
|
|
pub fn new(jid: Jid) -> ComponentBuilder {
|
|
|
|
|
ComponentBuilder {
|
|
|
|
|
jid: jid,
|
|
|
|
|
secret: "".to_owned(),
|
|
|
|
|
host: None,
|
|
|
|
|
port: 5347,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Sets the host to connect to.
|
|
|
|
|
pub fn host(mut self, host: String) -> ComponentBuilder {
|
|
|
|
|
self.host = Some(host);
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Sets the port to connect to.
|
|
|
|
|
pub fn port(mut self, port: u16) -> ComponentBuilder {
|
|
|
|
|
self.port = port;
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Sets the password to use.
|
|
|
|
|
pub fn password<P: Into<String>>(mut self, password: P) -> ComponentBuilder {
|
|
|
|
|
self.secret = password.into();
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Connects to the server and returns a `Component` when succesful.
|
|
|
|
|
pub fn connect(self) -> Result<Component, Error> {
|
|
|
|
|
let host = &self.host.unwrap_or(self.jid.domain.clone());
|
|
|
|
|
let mut transport = PlainTransport::connect(host, self.port)?;
|
|
|
|
|
Component2S::init(&mut transport, &self.jid.domain, "stream_opening")?;
|
2017-05-27 18:41:54 +02:00
|
|
|
let dispatcher = Arc::new(Dispatcher::new());
|
2017-05-25 00:22:40 +01:00
|
|
|
let transport = Arc::new(Mutex::new(transport));
|
2017-05-27 20:33:56 +02:00
|
|
|
let plugin_container = Arc::new(PluginContainer::new());
|
2017-04-01 17:15:37 +01:00
|
|
|
let mut component = Component {
|
2017-05-29 03:14:26 +01:00
|
|
|
jid: self.jid.clone(),
|
2017-05-27 18:41:54 +02:00
|
|
|
transport: transport.clone(),
|
2017-05-29 03:14:26 +01:00
|
|
|
binding: PluginProxyBinding::new(dispatcher.clone(), plugin_container.clone(), self.jid),
|
2017-05-27 20:33:56 +02:00
|
|
|
plugin_container: plugin_container,
|
2017-05-25 00:22:40 +01:00
|
|
|
dispatcher: dispatcher,
|
2017-04-01 17:15:37 +01:00
|
|
|
};
|
2017-05-27 18:41:54 +02:00
|
|
|
component.dispatcher.register(Priority::Default, move |evt: &SendElement| {
|
|
|
|
|
let mut t = transport.lock().unwrap();
|
|
|
|
|
t.write_element(&evt.0).unwrap();
|
|
|
|
|
Propagation::Continue
|
|
|
|
|
});
|
2017-04-01 17:15:37 +01:00
|
|
|
component.connect(self.secret)?;
|
|
|
|
|
Ok(component)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// An XMPP component.
|
|
|
|
|
pub struct Component {
|
|
|
|
|
jid: Jid,
|
2017-05-25 00:22:40 +01:00
|
|
|
transport: Arc<Mutex<PlainTransport>>,
|
2017-05-27 20:33:56 +02:00
|
|
|
plugin_container: Arc<PluginContainer>,
|
2017-04-01 17:15:37 +01:00
|
|
|
binding: PluginProxyBinding,
|
2017-05-27 18:41:54 +02:00
|
|
|
dispatcher: Arc<Dispatcher>,
|
2017-04-01 17:15:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Component {
|
|
|
|
|
/// Returns a reference to the `Jid` associated with this `Component`.
|
|
|
|
|
pub fn jid(&self) -> &Jid {
|
|
|
|
|
&self.jid
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Registers a plugin.
|
2017-05-25 00:22:40 +01:00
|
|
|
pub fn register_plugin<P: Plugin + PluginInit + 'static>(&mut self, mut plugin: P) {
|
|
|
|
|
let binding = self.binding.clone();
|
|
|
|
|
plugin.bind(binding);
|
2017-05-27 20:33:56 +02:00
|
|
|
let p = Arc::new(plugin);
|
2017-05-27 18:41:54 +02:00
|
|
|
P::init(&self.dispatcher, p.clone());
|
2017-05-27 20:33:56 +02:00
|
|
|
self.plugin_container.register(p);
|
2017-04-01 17:15:37 +01:00
|
|
|
}
|
|
|
|
|
|
2017-05-27 18:41:54 +02:00
|
|
|
pub fn register_handler<E, F>(&mut self, pri: Priority, func: F)
|
|
|
|
|
where
|
|
|
|
|
E: Event,
|
|
|
|
|
F: Fn(&E) -> Propagation + 'static {
|
|
|
|
|
self.dispatcher.register(pri, func);
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-27 20:33:56 +02:00
|
|
|
/// Returns the plugin given by the type parameter, if it exists, else panics.
|
|
|
|
|
pub fn plugin<P: Plugin>(&self) -> PluginRef<P> {
|
|
|
|
|
self.plugin_container.get::<P>().unwrap()
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-01 17:15:37 +01:00
|
|
|
/// Returns the next event and flush the send queue.
|
2017-05-25 00:22:40 +01:00
|
|
|
pub fn main(&mut self) -> Result<(), Error> {
|
2017-05-27 18:41:54 +02:00
|
|
|
self.dispatcher.flush_all();
|
2017-04-01 17:15:37 +01:00
|
|
|
loop {
|
2017-05-25 00:22:40 +01:00
|
|
|
let elem = self.read_element()?;
|
2017-05-27 18:41:54 +02:00
|
|
|
self.dispatcher.dispatch(ReceiveElement(elem));
|
|
|
|
|
self.dispatcher.flush_all();
|
2017-04-01 17:15:37 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-25 00:22:40 +01:00
|
|
|
fn read_element(&self) -> Result<Element, Error> {
|
|
|
|
|
self.transport.lock().unwrap().read_element()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn write_element(&self, elem: &Element) -> Result<(), Error> {
|
|
|
|
|
self.transport.lock().unwrap().write_element(elem)
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-01 17:15:37 +01:00
|
|
|
fn connect(&mut self, secret: String) -> Result<(), Error> {
|
|
|
|
|
let mut sid = String::new();
|
|
|
|
|
loop {
|
2017-12-28 06:04:50 +01:00
|
|
|
let mut transport = self.transport.lock().unwrap();
|
|
|
|
|
let e = transport.read_event()?;
|
2017-04-01 17:15:37 +01:00
|
|
|
match e {
|
2017-12-28 06:04:50 +01:00
|
|
|
XmlEvent::Start(ref e) => {
|
|
|
|
|
let mut attributes = e.attributes()
|
|
|
|
|
.map(|o| {
|
|
|
|
|
let o = o?;
|
|
|
|
|
let key = str::from_utf8(o.key)?;
|
|
|
|
|
let value = str::from_utf8(&o.value)?;
|
|
|
|
|
Ok((key, value))
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
.collect::<Result<Vec<(&str, &str)>, Error>>()?;
|
|
|
|
|
for &(name, value) in &attributes {
|
|
|
|
|
if name == "id" {
|
|
|
|
|
sid = value.to_owned();
|
2017-04-01 17:15:37 +01:00
|
|
|
}
|
|
|
|
|
}
|
2017-12-28 06:19:07 +01:00
|
|
|
},
|
|
|
|
|
_ => (),
|
2017-04-01 17:15:37 +01:00
|
|
|
}
|
2017-12-28 06:04:50 +01:00
|
|
|
break
|
2017-04-01 17:15:37 +01:00
|
|
|
}
|
|
|
|
|
let concatenated = format!("{}{}", sid, secret);
|
2017-05-02 17:21:26 +01:00
|
|
|
let mut hasher = Sha1::default();
|
|
|
|
|
hasher.input(concatenated.as_bytes());
|
2017-04-01 17:15:37 +01:00
|
|
|
let mut handshake = String::new();
|
2017-05-02 17:21:26 +01:00
|
|
|
for byte in hasher.result() {
|
|
|
|
|
write!(handshake, "{:02x}", byte)?;
|
2017-04-01 17:15:37 +01:00
|
|
|
}
|
|
|
|
|
let mut elem = Element::builder("handshake")
|
|
|
|
|
.ns(ns::COMPONENT_ACCEPT)
|
|
|
|
|
.build();
|
|
|
|
|
elem.append_text_node(handshake);
|
2017-05-25 00:22:40 +01:00
|
|
|
self.write_element(&elem)?;
|
2017-04-01 17:15:37 +01:00
|
|
|
loop {
|
2017-05-25 00:22:40 +01:00
|
|
|
let n = self.read_element()?;
|
2017-04-01 17:15:37 +01:00
|
|
|
if n.is("handshake", ns::COMPONENT_ACCEPT) {
|
|
|
|
|
return Ok(());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|