From b377b8aa01f32fa5e6d59a64c84dfe8b50a6e63c Mon Sep 17 00:00:00 2001 From: xengineering Date: Sun, 20 Nov 2022 10:49:03 +0100 Subject: Introduce dummy as second XMPP implementation It is currently evaluated if it is worth a trial to drop libstrophe as a dependency and use a raw TCP connection and a XML library like expat to implement the XMPP part. This would have the following advantages: - fewer dependencies - learning more about XMPP itself and less about libstrophe - slower, but maybe easier implementation (XMPP doc is far more readable / extensive) Because of these reasons the `limox_sdl2` version was switched to a dummy XMPP implementation `xmpp.c` which acts now as a test field for XMPP hacking. --- meson.build | 4 +- net.c | 228 ------------------------------------------------------------ strophe.c | 228 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ xmpp.c | 14 ++++ 4 files changed, 244 insertions(+), 230 deletions(-) delete mode 100644 net.c create mode 100644 strophe.c create mode 100644 xmpp.c diff --git a/meson.build b/meson.build index e683f16..8a21907 100644 --- a/meson.build +++ b/meson.build @@ -2,5 +2,5 @@ project('LimoX', 'c') gtkdep = dependency('gtk4') strophedep = dependency('libstrophe') sdl2dep = dependency('sdl2') -executable('limox', ['main.c', 'gtk.c', 'net.c', 'data.c'], dependencies : [gtkdep, strophedep]) -executable('limox_sdl2', ['main.c', 'sdl2.c', 'net.c', 'data.c'], dependencies : [sdl2dep, strophedep]) +executable('limox', ['main.c', 'gtk.c', 'strophe.c', 'data.c'], dependencies : [gtkdep, strophedep]) +executable('limox_sdl2', ['main.c', 'sdl2.c', 'xmpp.c', 'data.c'], dependencies : [sdl2dep]) diff --git a/net.c b/net.c deleted file mode 100644 index c037bc1..0000000 --- a/net.c +++ /dev/null @@ -1,228 +0,0 @@ - - -#include -#include -#include -#include -#include - -#include - -#include "gui.h" -#include "net.h" -#include "data.h" - - -// the state of net -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) -} net_state_t; - - -// these variables stay initialized for the whole runtime -static net_state_t state; -static xmpp_ctx_t* ctx; - -// these variables stay initialized while the application is not disconnected -static xmpp_conn_t* conn; -static long flags; - - -static int message_handler(xmpp_conn_t* conn, xmpp_stanza_t* stanza, - void* userdata) { - - xmpp_stanza_t* body = xmpp_stanza_get_child_by_name(stanza, "body"); - if (body == NULL) { - fprintf(stderr, "DEBUG: Got message stanza of type char without body!\n"); - return 1; - } - - const char* content = xmpp_stanza_get_text(body); - const char* sender = xmpp_stanza_get_from(stanza); - - data_add_incoming_message(sender, content); - - return 1; -} - -static int roster_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, - void *userdata) { - - // 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)) { - - data_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) { - - // FIXME handle error and stream_error (this could be a major bug) - // this implements at least debugging: - if (error != 0) { - fprintf(stderr, "conn_handler got error=%d\n", error); - } - if (stream_error != NULL) { - fprintf(stderr, "conn_handler got stream_error of type %d\n", - stream_error->type); - } - - switch (status) { - - case XMPP_CONN_CONNECT: - fprintf(stderr, "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: - fprintf(stderr, "DEBUG: Got XMPP_CONN_RAW_CONNECT\n"); - break; - - case XMPP_CONN_DISCONNECT: - fprintf(stderr, "DEBUG: Got XMPP_CONN_DISCONNECT\n"); - break; - - case XMPP_CONN_FAIL: - fprintf(stderr, "DEBUG: Got XMPP_CONN_FAIL\n"); - break; - - default: - fprintf(stderr, "DEBUG: Got unknown connection status '%d'!\n", status); - exit(1); - } -} - -void net_init(void) { - - fprintf(stderr, "net_init()\n"); - - xmpp_initialize(); - ctx = xmpp_ctx_new(NULL, xmpp_get_default_logger(XMPP_LEVEL_DEBUG)); - - state = DISCONNECTED; - -} - -static void delay(unsigned long int micros) { - - unsigned long int now = clock(); - while ((clock() - now) < micros) {} - -} - -void net_run_once(void) { - - if (state == CONNECTING) { - if (xmpp_connect_client(conn, NULL, 0, conn_handler, NULL) - == XMPP_EOK) { - state = CONNECTED; - } else { - net_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 net_quit(void) { - - fprintf(stderr, "net_quit()\n"); - - net_disconnect(); - xmpp_shutdown(); - -} - -void net_connect(const char* jid, const char* password) { - - fprintf(stderr, "net_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 net_disconnect(void) { - - fprintf(stderr, "net_disconnect()\n"); - - 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)) { - fprintf(stderr, "DEBUG: Could not free connection!\n"); - } - } - - flags = 0; - state = DISCONNECTED; - -} - -void net_send_message(const char* sender, const char* content, - const char* recipient) { - - if (xmpp_conn_is_connected(conn)) { - char* uuid = xmpp_uuid_gen(ctx); - xmpp_stanza_t* msg = xmpp_message_new(ctx, "chat", recipient, uuid); - xmpp_stanza_set_from(msg, sender); - xmpp_message_set_body(msg, content); - xmpp_send(conn, msg); - } else { - fprintf(stderr, "net_send_message() called while not connected\n"); - } - -} diff --git a/strophe.c b/strophe.c new file mode 100644 index 0000000..c037bc1 --- /dev/null +++ b/strophe.c @@ -0,0 +1,228 @@ + + +#include +#include +#include +#include +#include + +#include + +#include "gui.h" +#include "net.h" +#include "data.h" + + +// the state of net +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) +} net_state_t; + + +// these variables stay initialized for the whole runtime +static net_state_t state; +static xmpp_ctx_t* ctx; + +// these variables stay initialized while the application is not disconnected +static xmpp_conn_t* conn; +static long flags; + + +static int message_handler(xmpp_conn_t* conn, xmpp_stanza_t* stanza, + void* userdata) { + + xmpp_stanza_t* body = xmpp_stanza_get_child_by_name(stanza, "body"); + if (body == NULL) { + fprintf(stderr, "DEBUG: Got message stanza of type char without body!\n"); + return 1; + } + + const char* content = xmpp_stanza_get_text(body); + const char* sender = xmpp_stanza_get_from(stanza); + + data_add_incoming_message(sender, content); + + return 1; +} + +static int roster_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, + void *userdata) { + + // 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)) { + + data_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) { + + // FIXME handle error and stream_error (this could be a major bug) + // this implements at least debugging: + if (error != 0) { + fprintf(stderr, "conn_handler got error=%d\n", error); + } + if (stream_error != NULL) { + fprintf(stderr, "conn_handler got stream_error of type %d\n", + stream_error->type); + } + + switch (status) { + + case XMPP_CONN_CONNECT: + fprintf(stderr, "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: + fprintf(stderr, "DEBUG: Got XMPP_CONN_RAW_CONNECT\n"); + break; + + case XMPP_CONN_DISCONNECT: + fprintf(stderr, "DEBUG: Got XMPP_CONN_DISCONNECT\n"); + break; + + case XMPP_CONN_FAIL: + fprintf(stderr, "DEBUG: Got XMPP_CONN_FAIL\n"); + break; + + default: + fprintf(stderr, "DEBUG: Got unknown connection status '%d'!\n", status); + exit(1); + } +} + +void net_init(void) { + + fprintf(stderr, "net_init()\n"); + + xmpp_initialize(); + ctx = xmpp_ctx_new(NULL, xmpp_get_default_logger(XMPP_LEVEL_DEBUG)); + + state = DISCONNECTED; + +} + +static void delay(unsigned long int micros) { + + unsigned long int now = clock(); + while ((clock() - now) < micros) {} + +} + +void net_run_once(void) { + + if (state == CONNECTING) { + if (xmpp_connect_client(conn, NULL, 0, conn_handler, NULL) + == XMPP_EOK) { + state = CONNECTED; + } else { + net_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 net_quit(void) { + + fprintf(stderr, "net_quit()\n"); + + net_disconnect(); + xmpp_shutdown(); + +} + +void net_connect(const char* jid, const char* password) { + + fprintf(stderr, "net_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 net_disconnect(void) { + + fprintf(stderr, "net_disconnect()\n"); + + 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)) { + fprintf(stderr, "DEBUG: Could not free connection!\n"); + } + } + + flags = 0; + state = DISCONNECTED; + +} + +void net_send_message(const char* sender, const char* content, + const char* recipient) { + + if (xmpp_conn_is_connected(conn)) { + char* uuid = xmpp_uuid_gen(ctx); + xmpp_stanza_t* msg = xmpp_message_new(ctx, "chat", recipient, uuid); + xmpp_stanza_set_from(msg, sender); + xmpp_message_set_body(msg, content); + xmpp_send(conn, msg); + } else { + fprintf(stderr, "net_send_message() called while not connected\n"); + } + +} diff --git a/xmpp.c b/xmpp.c new file mode 100644 index 0000000..d9645d1 --- /dev/null +++ b/xmpp.c @@ -0,0 +1,14 @@ + + +#include + + +void net_init(void) +{ + printf("net_init()\n"); +} + +void net_quit(void) +{ + printf("net_quit()\n"); +} -- cgit v1.2.3-70-g09d2