extern crate libc;
extern crate strophe;
use std::{env, mem, ptr, str};
use std::ffi::{CStr, CString};
use libc::*;
use strophe::*;
extern "C" fn reply_handler(conn: *const xmpp_conn_t,
stanza: *const xmpp_stanza_t,
userdata: *const c_void) -> i32 {
unsafe {
let stanza_type = ptr_to_str(xmpp_stanza_get_type(stanza));
if stanza_type != "error" {
let query = xmpp_stanza_get_child_by_name(stanza, str_to_ptr("query"));
println!("Roster:");
let mut item = xmpp_stanza_get_children(query);
while !item.is_null() {
let jid = get_stanza_attr(item, "jid").unwrap();
let sub = get_stanza_attr(item, "subscription").unwrap();
if let Some(name) = get_stanza_attr(item, "name") {
println!("\t {} ({}) sub={}", name, jid, sub);
} else {
println!("\t {} sub={}", jid, sub);
}
item = xmpp_stanza_get_next(item);
}
} else {
println!("error: query failed");
}
xmpp_disconnect(conn);
return 0;
}
}
extern "C" fn conn_handler(conn: *const xmpp_conn_t,
status: xmpp_conn_event_t,
error: i32,
stream_error: *const xmpp_stream_error_t,
userdata: *const c_void) {
unsafe {
let ctx: *mut xmpp_ctx_t = mem::transmute(userdata);
if status != XMPP_CONN_CONNECT {
println!("disconnected");
xmpp_stop(ctx);
return;
}
let iq = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(iq, str_to_ptr("iq"));
xmpp_stanza_set_type(iq, str_to_ptr("get"));
xmpp_stanza_set_id(iq, str_to_ptr("roster1"));
let query = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(query, str_to_ptr("query"));
xmpp_stanza_set_ns(query, str_to_ptr(XMPP_NS_ROSTER));
xmpp_stanza_add_child(iq, query);
xmpp_stanza_release(query);
xmpp_id_handler_add(conn,
Some(reply_handler),
str_to_ptr("roster1"),
mem::transmute(ctx));
xmpp_send(conn, iq);
xmpp_stanza_release(iq);
}
}
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() < 3 {
println!("usage: ./roster <jid> <pwd>");
return;
}
let jid = args[1].clone();
let pwd = args[2].clone();
unsafe {
xmpp_initialize();
let ctx = xmpp_ctx_new(ptr::null(), ptr::null());
let conn = xmpp_conn_new(ctx);
xmpp_conn_set_jid(conn, str_to_ptr(jid));
xmpp_conn_set_pass(conn, str_to_ptr(pwd));
xmpp_connect_client(conn,
ptr::null(),
0,
Some(conn_handler),
ctx as *const c_void);
xmpp_run(ctx);
xmpp_conn_release(conn);
xmpp_ctx_free(ctx);
xmpp_shutdown();
}
}
fn get_stanza_attr<'a>(item: *const xmpp_stanza_t,
attr: &str) -> Option<&'a str> {
let res = unsafe { xmpp_stanza_get_attribute(item, str_to_ptr(attr)) };
if !res.is_null() {
Some(ptr_to_str(res))
} else {
None
}
}
fn str_to_ptr<T: Into<Vec<u8>>>(input: T) -> *const i8 {
CString::new(input).unwrap().as_bytes_with_nul().as_ptr() as *const i8
}
fn ptr_to_str<'a>(ptr: *const c_char) -> &'a str {
unsafe { str::from_utf8(CStr::from_ptr(ptr).to_bytes()).unwrap() }
}