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 mut elem = Element::builder("auth")
145 .ns(ns::SASL)
146 .attr("mechanism", "PLAIN")
147 .build();
148 elem.append_text_node(base64::encode(&auth));
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}