From 2f5aa124cacae454e4b49c2ecbc7ca72bdf63d1c Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Tue, 29 Jun 2021 22:52:45 +0200 Subject: [PATCH 1/5] XEP-0157: Parse contact address stanza --- src/xmpp/iq.c | 26 ++++++++++++++++++++++---- src/xmpp/stanza.c | 31 +++++++++++++++++++++++++++++++ src/xmpp/stanza.h | 3 +++ 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c index beecb97e..7af477e6 100644 --- a/src/xmpp/iq.c +++ b/src/xmpp/iq.c @@ -2308,6 +2308,8 @@ _disco_info_response_id_handler(xmpp_stanza_t* const stanza, void* const userdat GSList* features = NULL; while (child) { const char* stanza_name = xmpp_stanza_get_name(child); + const char* child_type = xmpp_stanza_get_type(child); + if (g_strcmp0(stanza_name, STANZA_NAME_FEATURE) == 0) { const char* var = xmpp_stanza_get_attribute(child, STANZA_ATTR_VAR); if (var) { @@ -2315,10 +2317,9 @@ _disco_info_response_id_handler(xmpp_stanza_t* const stanza, void* const userdat } } else if (g_strcmp0(stanza_name, STANZA_NAME_IDENTITY) == 0) { const char* name = xmpp_stanza_get_attribute(child, STANZA_ATTR_NAME); - const char* type = xmpp_stanza_get_type(child); const char* category = xmpp_stanza_get_attribute(child, STANZA_ATTR_CATEGORY); - if (name || category || type) { + if (name || category || child_type) { DiscoIdentity* identity = malloc(sizeof(struct disco_identity_t)); if (identity) { @@ -2332,8 +2333,8 @@ _disco_info_response_id_handler(xmpp_stanza_t* const stanza, void* const userdat } else { identity->category = NULL; } - if (type) { - identity->type = strdup(type); + if (child_type) { + identity->type = strdup(child_type); } else { identity->type = NULL; } @@ -2341,6 +2342,23 @@ _disco_info_response_id_handler(xmpp_stanza_t* const stanza, void* const userdat identities = g_slist_append(identities, identity); } } + } else if (g_strcmp0(child_type, STANZA_TYPE_RESULT) == 0) { + /* + DataForm* form = form_create(child); + ProfConfWin* confwin = (ProfConfWin*)wins_new_config(from, form, NULL, NULL, NULL); + confwin_handle_configuration(confwin, form); + */ + /*g_hash_table_new () with field var='security-addresses' as key + * a list of xmpp:security@shakespeare.lit as value + */ + stanza_get_service_contact_addresses(connection_get_ctx(), child); + /* + char* text; + size_t text_size; + xmpp_stanza_to_text(child, &text, &text_size); + cons_show(text); + free(text); + */ } child = xmpp_stanza_get_next(child); diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c index 235a7dee..96c47dc7 100644 --- a/src/xmpp/stanza.c +++ b/src/xmpp/stanza.c @@ -2838,3 +2838,34 @@ stanza_create_muc_register_nick(xmpp_ctx_t* ctx, const char* const id, const cha return iq; } + +void +stanza_get_service_contact_addresses(xmpp_ctx_t* ctx, xmpp_stanza_t* stanza) +{ + xmpp_stanza_t* fields = xmpp_stanza_get_children(stanza); + while (fields) { + const char* child_name = xmpp_stanza_get_name(fields); + const char* child_type = xmpp_stanza_get_type(fields); + + if (g_strcmp0(child_name, STANZA_NAME_FIELD) == 0 && g_strcmp0(child_type, STANZA_TYPE_LIST_MULTI) == 0) { + // key + const char* var = xmpp_stanza_get_attribute(fields, STANZA_ATTR_VAR ); + var = var; + + // values + xmpp_stanza_t* values = xmpp_stanza_get_children(fields); + if (values) { + const char* value_name = xmpp_stanza_get_name(values); + if (value_name && (g_strcmp0(value_name, STANZA_NAME_VALUE) == 0)) { + char* value_text = xmpp_stanza_get_text(values); + if (value_text) { + //add to list + xmpp_free(ctx, value_text); + } + } + } + } + + fields = xmpp_stanza_get_next(fields); + } +} diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h index 5effaf3e..7856a739 100644 --- a/src/xmpp/stanza.h +++ b/src/xmpp/stanza.h @@ -162,6 +162,7 @@ #define STANZA_TYPE_SUBMIT "submit" #define STANZA_TYPE_CANCEL "cancel" #define STANZA_TYPE_MODIFY "modify" +#define STANZA_TYPE_LIST_MULTI "list-multi" #define STANZA_ATTR_TO "to" #define STANZA_ATTR_FROM "from" @@ -388,6 +389,8 @@ char* stanza_get_muc_destroy_reason(xmpp_stanza_t* stanza); const char* stanza_get_actor(xmpp_stanza_t* stanza); char* stanza_get_reason(xmpp_stanza_t* stanza); +void stanza_get_service_contact_addresses(xmpp_ctx_t* ctx, xmpp_stanza_t* stanza); + Resource* stanza_resource_from_presence(XMPPPresence* presence); XMPPPresence* stanza_parse_presence(xmpp_stanza_t* stanza, int* err); void stanza_free_presence(XMPPPresence* presence); From ef96bea82e945d2c00426cac21b6578fdce62eb2 Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Wed, 30 Jun 2021 10:42:36 +0200 Subject: [PATCH 2/5] XEP-0157: Print contact addresses --- src/ui/console.c | 14 ++++++++++++++ src/ui/ui.h | 1 + src/xmpp/iq.c | 19 +++---------------- src/xmpp/stanza.c | 13 ++++++++++--- src/xmpp/stanza.h | 2 +- 5 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/ui/console.c b/src/ui/console.c index ad13f0cc..f3993424 100644 --- a/src/ui/console.c +++ b/src/ui/console.c @@ -837,6 +837,20 @@ cons_show_disco_items(GSList* items, const char* const jid) cons_alert(NULL); } +static void _cons_print_contact_information_item(gpointer key, gpointer value, gpointer userdata) +{ + cons_show("%s: %s", (char*)key, (char*)value); +} + +void +cons_show_disco_contact_information(GHashTable* addresses) +{ + cons_show(""); + cons_show("Server contact information:"); + + g_hash_table_foreach(addresses, _cons_print_contact_information_item, NULL); +} + void cons_show_status(const char* const barejid) { diff --git a/src/ui/ui.h b/src/ui/ui.h index 0c58b09c..441c9adf 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -276,6 +276,7 @@ void cons_show_bookmarks(const GList* list); void cons_show_bookmarks_ignore(gchar** list, gsize len); void cons_show_disco_items(GSList* items, const char* const jid); void cons_show_disco_info(const char* from, GSList* identities, GSList* features); +void cons_show_disco_contact_information(GHashTable* addresses); void cons_show_room_invite(const char* const invitor, const char* const room, const char* const reason); void cons_check_version(gboolean not_available_msg); void cons_show_typing(const char* const barejid); diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c index 7af477e6..19b620e2 100644 --- a/src/xmpp/iq.c +++ b/src/xmpp/iq.c @@ -2343,22 +2343,9 @@ _disco_info_response_id_handler(xmpp_stanza_t* const stanza, void* const userdat } } } else if (g_strcmp0(child_type, STANZA_TYPE_RESULT) == 0) { - /* - DataForm* form = form_create(child); - ProfConfWin* confwin = (ProfConfWin*)wins_new_config(from, form, NULL, NULL, NULL); - confwin_handle_configuration(confwin, form); - */ - /*g_hash_table_new () with field var='security-addresses' as key - * a list of xmpp:security@shakespeare.lit as value - */ - stanza_get_service_contact_addresses(connection_get_ctx(), child); - /* - char* text; - size_t text_size; - xmpp_stanza_to_text(child, &text, &text_size); - cons_show(text); - free(text); - */ + GHashTable *adr = stanza_get_service_contact_addresses(connection_get_ctx(), child); + cons_show_disco_contact_information(adr); + g_hash_table_destroy(adr); } child = xmpp_stanza_get_next(child); diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c index 96c47dc7..27e6d647 100644 --- a/src/xmpp/stanza.c +++ b/src/xmpp/stanza.c @@ -2839,9 +2839,11 @@ stanza_create_muc_register_nick(xmpp_ctx_t* ctx, const char* const id, const cha return iq; } -void +GHashTable* stanza_get_service_contact_addresses(xmpp_ctx_t* ctx, xmpp_stanza_t* stanza) { + GHashTable* addresses = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + xmpp_stanza_t* fields = xmpp_stanza_get_children(stanza); while (fields) { const char* child_name = xmpp_stanza_get_name(fields); @@ -2850,22 +2852,27 @@ stanza_get_service_contact_addresses(xmpp_ctx_t* ctx, xmpp_stanza_t* stanza) if (g_strcmp0(child_name, STANZA_NAME_FIELD) == 0 && g_strcmp0(child_type, STANZA_TYPE_LIST_MULTI) == 0) { // key const char* var = xmpp_stanza_get_attribute(fields, STANZA_ATTR_VAR ); - var = var; // values xmpp_stanza_t* values = xmpp_stanza_get_children(fields); - if (values) { + while (values) { const char* value_name = xmpp_stanza_get_name(values); if (value_name && (g_strcmp0(value_name, STANZA_NAME_VALUE) == 0)) { char* value_text = xmpp_stanza_get_text(values); if (value_text) { //add to list + g_hash_table_insert(addresses, g_strdup(var), g_strdup(value_text)); + xmpp_free(ctx, value_text); } } + + values = xmpp_stanza_get_next(values); } } fields = xmpp_stanza_get_next(fields); } + + return addresses; } diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h index 7856a739..aeddf6a2 100644 --- a/src/xmpp/stanza.h +++ b/src/xmpp/stanza.h @@ -389,7 +389,7 @@ char* stanza_get_muc_destroy_reason(xmpp_stanza_t* stanza); const char* stanza_get_actor(xmpp_stanza_t* stanza); char* stanza_get_reason(xmpp_stanza_t* stanza); -void stanza_get_service_contact_addresses(xmpp_ctx_t* ctx, xmpp_stanza_t* stanza); +GHashTable* stanza_get_service_contact_addresses(xmpp_ctx_t* ctx, xmpp_stanza_t* stanza); Resource* stanza_resource_from_presence(XMPPPresence* presence); XMPPPresence* stanza_parse_presence(xmpp_stanza_t* stanza, int* err); From 817a6bff54217e12444cb2d6dba1c0741918e578 Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Wed, 30 Jun 2021 11:07:02 +0200 Subject: [PATCH 3/5] XEP-0157: Print all available addresses --- src/ui/console.c | 11 ++++++++--- src/xmpp/stanza.c | 23 ++++++++++++++++++----- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/ui/console.c b/src/ui/console.c index f3993424..59e24891 100644 --- a/src/ui/console.c +++ b/src/ui/console.c @@ -837,9 +837,14 @@ cons_show_disco_items(GSList* items, const char* const jid) cons_alert(NULL); } -static void _cons_print_contact_information_item(gpointer key, gpointer value, gpointer userdata) +static void _cons_print_contact_information_item(gpointer data, gpointer user_data) { - cons_show("%s: %s", (char*)key, (char*)value); + cons_show("%s: %s", (char*)user_data, (char*)data); +} + +static void _cons_print_contact_information_hashlist_item(gpointer key, gpointer value, gpointer userdata) +{ + g_slist_foreach((GSList*)value, _cons_print_contact_information_item, key); } void @@ -848,7 +853,7 @@ cons_show_disco_contact_information(GHashTable* addresses) cons_show(""); cons_show("Server contact information:"); - g_hash_table_foreach(addresses, _cons_print_contact_information_item, NULL); + g_hash_table_foreach(addresses, _cons_print_contact_information_hashlist_item, NULL); } void diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c index 27e6d647..604d4003 100644 --- a/src/xmpp/stanza.c +++ b/src/xmpp/stanza.c @@ -2839,10 +2839,18 @@ stanza_create_muc_register_nick(xmpp_ctx_t* ctx, const char* const id, const cha return iq; } +static void +_contact_addresses_list_free(GSList* list) +{ + if (list) { + g_slist_free_full(list, g_free); + } +} + GHashTable* stanza_get_service_contact_addresses(xmpp_ctx_t* ctx, xmpp_stanza_t* stanza) { - GHashTable* addresses = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + GHashTable* addresses = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)_contact_addresses_list_free); xmpp_stanza_t* fields = xmpp_stanza_get_children(stanza); while (fields) { @@ -2850,18 +2858,18 @@ stanza_get_service_contact_addresses(xmpp_ctx_t* ctx, xmpp_stanza_t* stanza) const char* child_type = xmpp_stanza_get_type(fields); if (g_strcmp0(child_name, STANZA_NAME_FIELD) == 0 && g_strcmp0(child_type, STANZA_TYPE_LIST_MULTI) == 0) { - // key + // extract key (eg 'admin-addresses') const char* var = xmpp_stanza_get_attribute(fields, STANZA_ATTR_VAR ); - // values + // extract values (a list of contact addresses eg mailto:xmpp@shakespeare.lit, xmpp:admins@shakespeare.lit) xmpp_stanza_t* values = xmpp_stanza_get_children(fields); + GSList* val_list = NULL; while (values) { const char* value_name = xmpp_stanza_get_name(values); if (value_name && (g_strcmp0(value_name, STANZA_NAME_VALUE) == 0)) { char* value_text = xmpp_stanza_get_text(values); if (value_text) { - //add to list - g_hash_table_insert(addresses, g_strdup(var), g_strdup(value_text)); + val_list = g_slist_append(val_list, g_strdup(value_text)); xmpp_free(ctx, value_text); } @@ -2869,6 +2877,11 @@ stanza_get_service_contact_addresses(xmpp_ctx_t* ctx, xmpp_stanza_t* stanza) values = xmpp_stanza_get_next(values); } + + // add to list + if (g_slist_length(val_list) > 0) { + g_hash_table_insert(addresses, g_strdup(var), val_list); + } } fields = xmpp_stanza_get_next(fields); From c847a8d6629e4a6ca326b0f3def3fe2aba0ed467 Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Wed, 30 Jun 2021 11:24:38 +0200 Subject: [PATCH 4/5] command: Mention xep-0157 in /disco info --- src/command/cmd_defs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c index f5b111ac..e04ba2a1 100644 --- a/src/command/cmd_defs.c +++ b/src/command/cmd_defs.c @@ -869,7 +869,8 @@ static struct cmd_t command_defs[] = { "/disco items []") CMD_DESC( "Find out information about an entities supported services. " - "Calling with no arguments will query the server you are currently connected to.") + "Calling with no arguments will query the server you are currently connected to. " + "This includes discovering contact addresses for XMPP services (XEP-0157).") CMD_ARGS( { "info []", "List protocols and features supported by an entity." }, { "items []", "List items associated with an entity." }) From 3d5e59895b05ed611860aa55569ecfa893b73d64 Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Wed, 30 Jun 2021 11:30:02 +0200 Subject: [PATCH 5/5] Adjust contact addresses output to the rest of disco info Format the output of cons_show_disco_contact_information() so that it matches cons_show_disco_info(). --- src/ui/console.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ui/console.c b/src/ui/console.c index 59e24891..a99769b1 100644 --- a/src/ui/console.c +++ b/src/ui/console.c @@ -839,12 +839,13 @@ cons_show_disco_items(GSList* items, const char* const jid) static void _cons_print_contact_information_item(gpointer data, gpointer user_data) { - cons_show("%s: %s", (char*)user_data, (char*)data); + cons_show(" %s", (char*)data); } static void _cons_print_contact_information_hashlist_item(gpointer key, gpointer value, gpointer userdata) { - g_slist_foreach((GSList*)value, _cons_print_contact_information_item, key); + cons_show(" %s:", (char*)key); + g_slist_foreach((GSList*)value, _cons_print_contact_information_item, NULL); } void