#include #include #include #include #include #include #include #include #include #include // the state of limox typedef enum { DISCONNECTED, // initial state CONNECTING, // connection was requested but is not yet established CONNECTED, // there is an active XMPP connetion to the server SUSPENDED // not connected, but there is an open XMPP stream to be // reconnected (see XEP-0198 for details) } limox_state_t; // these variables stay initialized for the whole runtime static limox_state_t state; static xmpp_log_t* log; static xmpp_ctx_t* ctx; // these variables stay initialized while the application is not disconnected static xmpp_conn_t* conn; static long flags; // this variable stays initialized while the connection is suspended static xmpp_sm_state_t* sm_state; static int message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata) { // local variables xmpp_stanza_t* body; const char* content; body = xmpp_stanza_get_child_by_name(stanza, "body"); if (body == NULL) { printf("DEBUG: Got message stanza of type char without body!\n"); return 1; } content = xmpp_stanza_get_text(body); gui_add_message(xmpp_stanza_get_from(stanza), content); return 1; } static int roster_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata) { printf("DEBUG: Received roster.\n"); // iterate over roster result xmpp_stanza_t* query = xmpp_stanza_get_child_by_name(stanza, "query"); for (xmpp_stanza_t* item = xmpp_stanza_get_children(query); item; item = xmpp_stanza_get_next(item)) { add_roster_item(xmpp_stanza_get_attribute(item, "jid"), xmpp_stanza_get_attribute(item, "subscription"), xmpp_stanza_get_attribute(item, "name")); } return 1; } static void conn_handler(xmpp_conn_t *conn, xmpp_conn_event_t status,int error, xmpp_stream_error_t *stream_error, void *userdata) { switch (status) { case XMPP_CONN_CONNECT: printf("DEBUG: Got XMPP_CONN_CONNECT\n"); // add handler for stanzas xmpp_handler_add(conn, message_handler, NULL, "message", "chat", NULL); // add handler for roster response xmpp_handler_add(conn, roster_handler, "jabber:iq:roster", "iq", "result", NULL); // send initial presence xmpp_stanza_t* presence; presence = xmpp_presence_new(ctx); xmpp_send(conn, presence); xmpp_stanza_release(presence); // send roster request xmpp_stanza_t* iq = xmpp_iq_new(ctx, "get", "initial_roster"); xmpp_stanza_t* query = xmpp_stanza_new(ctx); xmpp_stanza_set_name(query, "query"); xmpp_stanza_set_ns(query, XMPP_NS_ROSTER); xmpp_stanza_add_child(iq, query); xmpp_stanza_release(query); xmpp_send(conn, iq); xmpp_stanza_release(iq); break; case XMPP_CONN_RAW_CONNECT: printf("DEBUG: Got XMPP_CONN_RAW_CONNECT\n"); break; case XMPP_CONN_DISCONNECT: printf("DEBUG: Got XMPP_CONN_DISCONNECT\n"); break; case XMPP_CONN_FAIL: printf("DEBUG: Got XMPP_CONN_FAIL\n"); break; default: printf("DEBUG: Got unknown connection status '%d'!\n", status); exit(1); } } void limox_init(void) { printf("limox_init()\n"); xmpp_initialize(); log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG); // or NULL for silence ctx = xmpp_ctx_new(NULL, log); state = DISCONNECTED; } static void delay(unsigned long int micros) { unsigned long int now = clock(); while ((clock() - now) < micros) {} } void limox_run_once(void) { if (state == CONNECTING) { if (xmpp_connect_client(conn, NULL, 0, conn_handler, NULL) == XMPP_EOK) { state = CONNECTED; } else { limox_disconnect(); } } if (state != DISCONNECTED) { xmpp_run_once(ctx, 200); } // TODO This delay is useless. But without it this function gets only // called once by GTK. This could be a GTK bug. delay(10000); } void limox_quit(void) { printf("limox_quit()\n"); limox_disconnect(); // TODO is it possible to free xmpp_log_t ? log = NULL; xmpp_ctx_free(ctx); xmpp_shutdown(); } void limox_connect(const char* jid, const char* password) { printf("limox_connect()\n"); conn = xmpp_conn_new(ctx); flags = 0; flags |= XMPP_CONN_FLAG_MANDATORY_TLS; xmpp_conn_set_flags(conn, flags); xmpp_conn_set_jid(conn, jid); xmpp_conn_set_pass(conn, password); state = CONNECTING; } void limox_disconnect(void) { printf("limox_disconnect()\n"); if (sm_state) { xmpp_free_sm_state(sm_state); sm_state = NULL; } if (conn != NULL && xmpp_conn_is_connected(conn)) { xmpp_disconnect(conn); while (xmpp_conn_is_connected(conn)) { xmpp_run_once(ctx, 200); // TODO avoid with additional // state "disconnecting" } if (!xmpp_conn_release(conn)) { printf("DEBUG: Could not free connection!\n"); } } flags = 0; state = DISCONNECTED; }