#![allow(unused_variables)] extern crate libc; extern crate strophe; use std::{env, mem, ptr, str}; use std::ffi::{CStr, CString}; use libc::*; use strophe::*; /* * Example printing out the user's roster * * Rust version of the original roster.c example file * https://github.com/strophe/libstrophe/blob/master/examples/roster.c */ 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; } // create iq stanza for the request 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")); // create query to request the roster 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); // release query stanza because it belongs to iq now xmpp_stanza_release(query); // register reply handler xmpp_id_handler_add(conn, Some(reply_handler), str_to_ptr("roster1"), mem::transmute(ctx)); // send the stanza xmpp_send(conn, iq); // release the iq stanza xmpp_stanza_release(iq); } } fn main() { let args: Vec = env::args().collect(); if args.len() < 3 { println!("usage: ./roster "); return; } let jid = args[1].clone(); let pwd = args[2].clone(); unsafe { // initialize library xmpp_initialize(); // create a context let ctx = xmpp_ctx_new(ptr::null(), ptr::null()); // create a connection let conn = xmpp_conn_new(ctx); // setup authentication information xmpp_conn_set_jid(conn, str_to_ptr(jid)); xmpp_conn_set_pass(conn, str_to_ptr(pwd)); // initialize the connection xmpp_connect_client(conn, ptr::null(), 0, Some(conn_handler), ctx as *const c_void); // start the event loop xmpp_run(ctx); // release the connection and context xmpp_conn_release(conn); xmpp_ctx_free(ctx); // shutdown library 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>>(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() } }