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