1use xml;
2use jid::Jid;
3use transport::{Transport, PlainTransport};
4use error::Error;
5use ns;
6use plugin::{Plugin, PluginInit, PluginProxyBinding};
7use event::{Dispatcher, ReceiveElement};
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(Mutex::new(Dispatcher::new()));
65 let transport = Arc::new(Mutex::new(transport));
66 let mut component = Component {
67 jid: self.jid,
68 transport: transport,
69 plugins: HashMap::new(),
70 binding: PluginProxyBinding::new(dispatcher.clone()),
71 dispatcher: dispatcher,
72 };
73 component.connect(self.secret)?;
74 Ok(component)
75 }
76}
77
78/// An XMPP component.
79pub struct Component {
80 jid: Jid,
81 transport: Arc<Mutex<PlainTransport>>,
82 plugins: HashMap<TypeId, Arc<Box<Plugin>>>,
83 binding: PluginProxyBinding,
84 dispatcher: Arc<Mutex<Dispatcher>>,
85}
86
87impl Component {
88 /// Returns a reference to the `Jid` associated with this `Component`.
89 pub fn jid(&self) -> &Jid {
90 &self.jid
91 }
92
93 /// Registers a plugin.
94 pub fn register_plugin<P: Plugin + PluginInit + 'static>(&mut self, mut plugin: P) {
95 let binding = self.binding.clone();
96 plugin.bind(binding);
97 let p = Arc::new(Box::new(plugin) as Box<Plugin>);
98 {
99 let mut disp = self.dispatcher.lock().unwrap();
100 P::init(&mut disp, p.clone());
101 }
102 if self.plugins.insert(TypeId::of::<P>(), p).is_some() {
103 panic!("registering a plugin that's already registered");
104 }
105 }
106
107 /// Returns the plugin given by the type parameter, if it exists, else panics.
108 pub fn plugin<P: Plugin>(&self) -> &P {
109 self.plugins.get(&TypeId::of::<P>())
110 .expect("the requested plugin was not registered")
111 .as_any()
112 .downcast_ref::<P>()
113 .expect("plugin downcast failure (should not happen!!)")
114 }
115
116 /// Returns the next event and flush the send queue.
117 pub fn main(&mut self) -> Result<(), Error> {
118 self.dispatcher.lock().unwrap().flush_all();
119 loop {
120 let elem = self.read_element()?;
121 {
122 let mut disp = self.dispatcher.lock().unwrap();
123 disp.dispatch(ReceiveElement(elem));
124 disp.flush_all();
125 }
126 }
127 }
128
129 fn read_element(&self) -> Result<Element, Error> {
130 self.transport.lock().unwrap().read_element()
131 }
132
133 fn write_element(&self, elem: &Element) -> Result<(), Error> {
134 self.transport.lock().unwrap().write_element(elem)
135 }
136
137 fn read_event(&self) -> Result<xml::reader::XmlEvent, Error> {
138 self.transport.lock().unwrap().read_event()
139 }
140
141 fn connect(&mut self, secret: String) -> Result<(), Error> {
142 let mut sid = String::new();
143 loop {
144 let e = self.read_event()?;
145 match e {
146 ReaderEvent::StartElement { attributes, .. } => {
147 for attribute in attributes {
148 if attribute.name.namespace == None && attribute.name.local_name == "id" {
149 sid = attribute.value;
150 }
151 }
152 break;
153 },
154 _ => (),
155 }
156 }
157 let concatenated = format!("{}{}", sid, secret);
158 let mut hasher = Sha1::default();
159 hasher.input(concatenated.as_bytes());
160 let mut handshake = String::new();
161 for byte in hasher.result() {
162 write!(handshake, "{:02x}", byte)?;
163 }
164 let mut elem = Element::builder("handshake")
165 .ns(ns::COMPONENT_ACCEPT)
166 .build();
167 elem.append_text_node(handshake);
168 self.write_element(&elem)?;
169 loop {
170 let n = self.read_element()?;
171 if n.is("handshake", ns::COMPONENT_ACCEPT) {
172 return Ok(());
173 }
174 }
175 }
176}