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