component.rs

  1use jid::Jid;
  2use transport::{Transport, PlainTransport};
  3use error::Error;
  4use ns;
  5use plugin::{Plugin, PluginProxyBinding};
  6use event::AbstractEvent;
  7use connection::{Connection, Component2S};
  8use sha_1::{Sha1, Digest};
  9
 10use minidom::Element;
 11
 12use xml::reader::XmlEvent as ReaderEvent;
 13
 14use std::fmt::Write;
 15use std::sync::mpsc::{Receiver, channel};
 16
 17/// A builder for `Component`s.
 18pub struct ComponentBuilder {
 19    jid: Jid,
 20    secret: String,
 21    host: Option<String>,
 22    port: u16,
 23}
 24
 25impl ComponentBuilder {
 26    /// Creates a new builder for an XMPP component that will connect to `jid` with default parameters.
 27    pub fn new(jid: Jid) -> ComponentBuilder {
 28        ComponentBuilder {
 29            jid: jid,
 30            secret: "".to_owned(),
 31            host: None,
 32            port: 5347,
 33        }
 34    }
 35
 36    /// Sets the host to connect to.
 37    pub fn host(mut self, host: String) -> ComponentBuilder {
 38        self.host = Some(host);
 39        self
 40    }
 41
 42    /// Sets the port to connect to.
 43    pub fn port(mut self, port: u16) -> ComponentBuilder {
 44        self.port = port;
 45        self
 46    }
 47
 48    /// Sets the password to use.
 49    pub fn password<P: Into<String>>(mut self, password: P) -> ComponentBuilder {
 50        self.secret = password.into();
 51        self
 52    }
 53
 54    /// Connects to the server and returns a `Component` when succesful.
 55    pub fn connect(self) -> Result<Component, Error> {
 56        let host = &self.host.unwrap_or(self.jid.domain.clone());
 57        let mut transport = PlainTransport::connect(host, self.port)?;
 58        Component2S::init(&mut transport, &self.jid.domain, "stream_opening")?;
 59        let (sender_out, sender_in) = channel();
 60        let (dispatcher_out, dispatcher_in) = channel();
 61        let mut component = Component {
 62            jid: self.jid,
 63            transport: transport,
 64            plugins: Vec::new(),
 65            binding: PluginProxyBinding::new(sender_out, dispatcher_out),
 66            sender_in: sender_in,
 67            dispatcher_in: dispatcher_in,
 68        };
 69        component.connect(self.secret)?;
 70        Ok(component)
 71    }
 72}
 73
 74/// An XMPP component.
 75pub struct Component {
 76    jid: Jid,
 77    transport: PlainTransport,
 78    plugins: Vec<Box<Plugin>>,
 79    binding: PluginProxyBinding,
 80    sender_in: Receiver<Element>,
 81    dispatcher_in: Receiver<AbstractEvent>,
 82}
 83
 84impl Component {
 85    /// Returns a reference to the `Jid` associated with this `Component`.
 86    pub fn jid(&self) -> &Jid {
 87        &self.jid
 88    }
 89
 90    /// Registers a plugin.
 91    pub fn register_plugin<P: Plugin + 'static>(&mut self, mut plugin: P) {
 92        plugin.bind(self.binding.clone());
 93        self.plugins.push(Box::new(plugin));
 94    }
 95
 96    /// Returns the plugin given by the type parameter, if it exists, else panics.
 97    pub fn plugin<P: Plugin>(&self) -> &P {
 98        for plugin in &self.plugins {
 99            let any = plugin.as_any();
100            if let Some(ret) = any.downcast_ref::<P>() {
101                return ret;
102            }
103        }
104        panic!("plugin does not exist!");
105    }
106
107    /// Returns the next event and flush the send queue.
108    pub fn next_event(&mut self) -> Result<AbstractEvent, Error> {
109        self.flush_send_queue()?;
110        loop {
111            if let Ok(evt) = self.dispatcher_in.try_recv() {
112                return Ok(evt);
113            }
114            let elem = self.transport.read_element()?;
115            for plugin in self.plugins.iter_mut() {
116                plugin.handle(&elem);
117                // TODO: handle plugin return
118            }
119            self.flush_send_queue()?;
120        }
121    }
122
123    /// Flushes the send queue, sending all queued up stanzas.
124    pub fn flush_send_queue(&mut self) -> Result<(), Error> { // TODO: not sure how great of an
125                                                              //       idea it is to flush in this
126                                                              //       manner…
127        while let Ok(elem) = self.sender_in.try_recv() {
128            self.transport.write_element(&elem)?;
129        }
130        Ok(())
131    }
132
133    fn connect(&mut self, secret: String) -> Result<(), Error> {
134        // TODO: this is very ugly
135        let mut sid = String::new();
136        loop {
137            let e = self.transport.read_event()?;
138            match e {
139                ReaderEvent::StartElement { attributes, .. } => {
140                    for attribute in attributes {
141                        if attribute.name.namespace == None && attribute.name.local_name == "id" {
142                            sid = attribute.value;
143                        }
144                    }
145                    break;
146                },
147                _ => (),
148            }
149        }
150        let concatenated = format!("{}{}", sid, secret);
151        let mut hasher = Sha1::default();
152        hasher.input(concatenated.as_bytes());
153        let mut handshake = String::new();
154        for byte in hasher.result() {
155            write!(handshake, "{:02x}", byte)?;
156        }
157        let mut elem = Element::builder("handshake")
158                               .ns(ns::COMPONENT_ACCEPT)
159                               .build();
160        elem.append_text_node(handshake);
161        self.transport.write_element(&elem)?;
162        loop {
163            let n = self.transport.read_element()?;
164            if n.is("handshake", ns::COMPONENT_ACCEPT) {
165                return Ok(());
166            }
167        }
168    }
169}