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