1extern crate futures;
2extern crate tokio_core;
3extern crate tokio_xmpp;
4extern crate jid;
5extern crate minidom;
6
7use std::env::args;
8use std::process::exit;
9use tokio_core::reactor::Core;
10use futures::{Future, Stream, Sink, future};
11use tokio_xmpp::Client;
12use minidom::Element;
13
14fn main() {
15 let args: Vec<String> = args().collect();
16 if args.len() != 3 {
17 println!("Usage: {} <jid> <password>", args[0]);
18 exit(1);
19 }
20 let jid = &args[1];
21 let password = &args[2];
22
23 // tokio_core context
24 let mut core = Core::new().unwrap();
25 // Client instance
26 let client = Client::new(jid, password, core.handle()).unwrap();
27
28 // Make the two interfaces for sending and receiving independent
29 // of each other so we can move one into a closure.
30 let (sink, stream) = client.split();
31 // Wrap sink in Option so that we can take() it for the send(self)
32 // to consume and return it back when ready.
33 let mut sink = Some(sink);
34 let mut send = move |stanza| {
35 sink = Some(
36 sink.take().
37 expect("sink")
38 .send(stanza)
39 .wait()
40 .expect("sink.send")
41 );
42 };
43 // Main loop, processes events
44 let done = stream.for_each(|event| {
45 if event.is_online() {
46 println!("Online!");
47
48 let presence = make_presence();
49 send(presence);
50 } else if let Some(stanza) = event.as_stanza() {
51 if stanza.name() == "message" &&
52 stanza.attr("type") != Some("error") {
53 // This is a message we'll echo
54 let from = stanza.attr("from");
55 let body = stanza.get_child("body", "jabber:client")
56 .map(|el| el.text());
57
58 match (from, body) {
59 (Some(from), Some(body)) => {
60 let reply = make_reply(from, body);
61 send(reply);
62 },
63 _ => (),
64 };
65 }
66 }
67
68 Box::new(future::ok(()))
69 });
70
71 // Start polling `done`
72 match core.run(done) {
73 Ok(_) => (),
74 Err(e) => {
75 println!("Fatal: {}", e);
76 ()
77 }
78 }
79}
80
81// Construct a <presence/>
82fn make_presence() -> Element {
83 Element::builder("presence")
84 .append(Element::builder("status")
85 .append("chat")
86 .build())
87 .append(Element::builder("show")
88 .append("Echoing messages")
89 .build())
90 .build()
91}
92
93// Construct a chat <message/>
94fn make_reply(to: &str, body: String) -> Element {
95 Element::builder("message")
96 .attr("type", "chat")
97 .attr("to", to)
98 .append(Element::builder("body")
99 .append(body)
100 .build())
101 .build()
102}