client.rs

  1use jid::Jid;
  2use transport::{Transport, SslTransport};
  3use error::Error;
  4use ns;
  5use plugin::{Plugin, PluginProxyBinding};
  6use event::AbstractEvent;
  7use connection::{Connection, C2S};
  8
  9use base64;
 10
 11use minidom::Element;
 12
 13use xml::reader::XmlEvent as ReaderEvent;
 14
 15use std::sync::mpsc::{Receiver, channel};
 16
 17pub struct ClientBuilder {
 18    jid: Jid,
 19    host: Option<String>,
 20    port: u16,
 21}
 22
 23impl ClientBuilder {
 24    pub fn new(jid: Jid) -> ClientBuilder {
 25        ClientBuilder {
 26            jid: jid,
 27            host: None,
 28            port: 5222,
 29        }
 30    }
 31
 32    pub fn host(mut self, host: String) -> ClientBuilder {
 33        self.host = Some(host);
 34        self
 35    }
 36
 37    pub fn port(mut self, port: u16) -> ClientBuilder {
 38        self.port = port;
 39        self
 40    }
 41
 42    pub fn connect(self) -> Result<Client, Error> {
 43        let host = &self.host.unwrap_or(self.jid.domain.clone());
 44        let mut transport = SslTransport::connect(host, self.port)?;
 45        C2S::init(&mut transport, &self.jid.domain, "before_sasl")?;
 46        let (sender_out, sender_in) = channel();
 47        let (dispatcher_out, dispatcher_in) = channel();
 48        Ok(Client {
 49            jid: self.jid,
 50            transport: transport,
 51            plugins: Vec::new(),
 52            binding: PluginProxyBinding::new(sender_out, dispatcher_out),
 53            sender_in: sender_in,
 54            dispatcher_in: dispatcher_in,
 55        })
 56    }
 57}
 58
 59pub struct Client {
 60    jid: Jid,
 61    transport: SslTransport,
 62    plugins: Vec<Box<Plugin>>,
 63    binding: PluginProxyBinding,
 64    sender_in: Receiver<Element>,
 65    dispatcher_in: Receiver<AbstractEvent>,
 66}
 67
 68impl Client {
 69    pub fn jid(&self) -> &Jid {
 70        &self.jid
 71    }
 72
 73    pub fn register_plugin<P: Plugin + 'static>(&mut self, mut plugin: P) {
 74        plugin.bind(self.binding.clone());
 75        self.plugins.push(Box::new(plugin));
 76    }
 77
 78    pub fn plugin<P: Plugin>(&self) -> &P {
 79        for plugin in &self.plugins {
 80            let any = plugin.as_any();
 81            if let Some(ret) = any.downcast_ref::<P>() {
 82                return ret;
 83            }
 84        }
 85        panic!("plugin does not exist!");
 86    }
 87
 88    pub fn next_event(&mut self) -> Result<AbstractEvent, Error> {
 89        self.flush_send_queue()?;
 90        loop {
 91            if let Ok(evt) = self.dispatcher_in.try_recv() {
 92                return Ok(evt);
 93            }
 94            let elem = self.transport.read_element()?;
 95            for plugin in self.plugins.iter_mut() {
 96                plugin.handle(&elem);
 97                // TODO: handle plugin return
 98            }
 99            self.flush_send_queue()?;
100        }
101    }
102
103    pub fn flush_send_queue(&mut self) -> Result<(), Error> { // TODO: not sure how great of an
104                                                              //       idea it is to flush in this
105                                                              //       manner…
106        while let Ok(elem) = self.sender_in.try_recv() {
107            self.transport.write_element(&elem)?;
108        }
109        Ok(())
110    }
111
112    pub fn connect_plain(&mut self, password: &str) -> Result<(), Error> {
113        // TODO: this is very ugly
114        loop {
115            let e = self.transport.read_event().unwrap();
116            match e {
117                ReaderEvent::StartElement { .. } => {
118                    break;
119                },
120                _ => (),
121            }
122        }
123        let mut did_sasl = false;
124        loop {
125            let n = self.transport.read_element().unwrap();
126            if n.is("features", ns::STREAM) {
127                if did_sasl {
128                    let mut elem = Element::builder("iq")
129                                           .attr("id", "bind")
130                                           .attr("type", "set")
131                                           .build();
132                    let bind = Element::builder("bind")
133                                       .ns(ns::BIND)
134                                       .build();
135                    elem.append_child(bind);
136                    self.transport.write_element(&elem)?;
137                }
138                else {
139                    let mut auth = Vec::new();
140                    auth.push(0);
141                    auth.extend(self.jid.node.as_ref().expect("JID has no node").bytes());
142                    auth.push(0);
143                    auth.extend(password.bytes());
144                    let elem = Element::builder("auth")
145                                       .text(base64::encode(&auth))
146                                       .ns(ns::SASL)
147                                       .attr("mechanism", "PLAIN")
148                                       .build();
149                    self.transport.write_element(&elem)?;
150                    did_sasl = true;
151                }
152            }
153            else if n.is("success", ns::SASL) {
154                self.transport.reset_stream();
155                C2S::init(&mut self.transport, &self.jid.domain, "after_sasl")?;
156                loop {
157                    let e = self.transport.read_event()?;
158                    match e {
159                        ReaderEvent::StartElement { .. } => {
160                            break;
161                        },
162                        _ => (),
163                    }
164                }
165            }
166            else if n.is("iq", ns::CLIENT) && n.has_child("bind", ns::BIND) {
167                return Ok(());
168            }
169        }
170    }
171}