From fde0a0d1c65ff61eb3d5bb9c07d6974d4fdac1f6 Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Thu, 18 Mar 2021 20:32:12 +0100 Subject: Add support to register with a room `/affiliation register` can now be used to register a nickname with a MUC. Tested with a server without forms. Couldn't find a server which supports forms yet. Implements https://github.com/profanity-im/profanity/issues/1210 --- src/command/cmd_ac.c | 1 + src/command/cmd_defs.c | 6 ++- src/command/cmd_funcs.c | 5 ++ src/xmpp/iq.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++ src/xmpp/stanza.c | 15 ++++++ src/xmpp/stanza.h | 7 ++- src/xmpp/xmpp.h | 1 + 7 files changed, 154 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/command/cmd_ac.c b/src/command/cmd_ac.c index a2d949eb..a4338143 100644 --- a/src/command/cmd_ac.c +++ b/src/command/cmd_ac.c @@ -756,6 +756,7 @@ cmd_ac_init(void) affiliation_cmd_ac = autocomplete_new(); autocomplete_add(affiliation_cmd_ac, "list"); autocomplete_add(affiliation_cmd_ac, "request"); + autocomplete_add(affiliation_cmd_ac, "register"); autocomplete_add(affiliation_cmd_ac, "set"); role_cmd_ac = autocomplete_new(); diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c index 55f58b49..c756c169 100644 --- a/src/command/cmd_defs.c +++ b/src/command/cmd_defs.c @@ -695,14 +695,16 @@ static struct cmd_t command_defs[] = { CMD_SYN( "/affiliation set []", "/affiliation list []", - "/affiliation request") + "/affiliation request", + "/affiliation register") CMD_DESC( "Manage room affiliations. " "Affiliation may be one of owner, admin, member, outcast or none.") CMD_ARGS( { "set []", "Set the affiliation of user with jid, with an optional reason." }, { "list []", "List all users with the specified affiliation, or all if none specified." }, - { "request", "Request voice."}) + { "request", "Request voice."}, + { "register", "Register your nickname with the MUC."}) CMD_NOEXAMPLES }, diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index 657850e2..07a444f7 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -4166,6 +4166,11 @@ cmd_affiliation(ProfWin* window, const char* const command, gchar** args) return TRUE; } + if (g_strcmp0(cmd, "register") == 0) { + iq_muc_register_nick(mucwin->roomjid); + return TRUE; + } + cons_bad_cmd_usage(command); return TRUE; } diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c index b866128b..bcbb715b 100644 --- a/src/xmpp/iq.c +++ b/src/xmpp/iq.c @@ -2659,3 +2659,128 @@ _register_change_password_result_id_handler(xmpp_stanza_t* const stanza, void* c } return 0; } + +static int +_muc_register_nick_response_handler(xmpp_stanza_t* const stanza, void* const userdata) +{ + const char* type = xmpp_stanza_get_type(stanza); + if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { + xmpp_stanza_t* error = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_ERROR); + const char* errtype = xmpp_stanza_get_type(error); + if (errtype) { + if (g_strcmp0(errtype, STANZA_TYPE_CANCEL) == 0) { + // find reason + xmpp_stanza_t* reason = xmpp_stanza_get_child_by_name_and_ns(stanza, STANZA_NAME_CONFLICT, STANZA_NS_STANZAS); + if (reason) { + cons_show_error("Error while registering nickname: nick already registered with MUC"); + log_debug("Error while registering nickname: nick already registered with MUC"); + } else { + xmpp_stanza_t* reason = xmpp_stanza_get_child_by_name_and_ns(stanza, STANZA_NAME_SERVICE_UNAVAILABLE, STANZA_NS_STANZAS); + if (reason) { + cons_show_error("Error while registering nickname: registration not supported by MUC"); + log_debug("Error while registering nickname: registration not supported by MUC"); + } + } + } else if (g_strcmp0(errtype, STANZA_TYPE_MODIFY) == 0) { + xmpp_stanza_t* reason = xmpp_stanza_get_child_by_name_and_ns(stanza, STANZA_NAME_BAD_REQUEST, STANZA_NS_STANZAS); + if (reason) { + cons_show_error("Error while registering nickname: invalid form"); + log_debug("Error while registering nickname: invalid form"); + } + } + } + } else if (g_strcmp0(type, STANZA_TYPE_RESULT) == 0) { + cons_show("Registration request succesfully received"); + log_debug("Registration request succesfully received"); + } + + return 0; +} + +void +iq_submit_muc_register_nick_form(ProfConfWin* confwin) +{ + char* id = connection_create_stanza_id(); + xmpp_ctx_t* const ctx = connection_get_ctx(); + + xmpp_stanza_t* iq = stanza_create_muc_register_nick(ctx, id, confwin->roomjid, NULL, confwin->form); + + iq_id_handler_add(id, _muc_register_nick_response_handler, NULL, NULL); + free(id); + + iq_send_stanza(iq); + xmpp_stanza_release(iq); +} + +static int +_muc_register_nick_handler(xmpp_stanza_t* const stanza, void* const userdata) +{ + const char* type = xmpp_stanza_get_type(stanza); + + // error case + if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { + xmpp_stanza_t* error = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_ERROR); + const char* errtype = xmpp_stanza_get_type(error); + if (errtype) { + if (g_strcmp0(errtype, STANZA_TYPE_CANCEL) == 0) { + // find reason + xmpp_stanza_t* reason = xmpp_stanza_get_child_by_name_and_ns(stanza, STANZA_NAME_ITEM_NOT_FOUND, STANZA_NS_STANZAS); + if (reason) { + cons_show_error("Error while registering nickname: room does not exist"); + log_debug("Error while registering nickname: room does not exist"); + } else { + xmpp_stanza_t* reason = xmpp_stanza_get_child_by_name_and_ns(stanza, STANZA_NAME_NOT_ALLOWED, STANZA_NS_STANZAS); + if (reason) { + cons_show_error("Error while registering nickname: not allowed to register"); + log_debug("Error while registering nickname: not allowed to register"); + } + } + } + } + } else if (g_strcmp0(type, STANZA_TYPE_RESULT) == 0) { + xmpp_stanza_t* query = xmpp_stanza_get_child_by_name_and_ns(stanza, STANZA_NAME_QUERY, STANZA_NS_REGISTER); + if (query) { + // user might already be registered + xmpp_stanza_t* username = xmpp_stanza_get_child_by_name(query, STANZA_NAME_USERNAME); + if (username) { + const char* value = xmpp_stanza_get_text(username); + cons_show("User already registered: %s", value); + } else { + xmpp_stanza_t* x_st = xmpp_stanza_get_child_by_name_and_ns(query, STANZA_NAME_X, STANZA_NS_DATA); + + if (x_st) { + const char* from = xmpp_stanza_get_from(stanza); + + DataForm* form = form_create(x_st); + ProfConfWin* confwin = (ProfConfWin*)wins_new_config(from, form, iq_submit_muc_register_nick_form, NULL, NULL); + confwin_handle_configuration(confwin, form); + } + } + } + } + return 0; +} + +void +iq_muc_register_nick(const char* const roomjid) +{ + xmpp_ctx_t* const ctx = connection_get_ctx(); + + char* id = connection_create_stanza_id(); + + xmpp_stanza_t* iq = xmpp_iq_new(ctx, STANZA_TYPE_GET, id); + xmpp_stanza_set_to(iq, roomjid); + + xmpp_stanza_t* query = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(query, STANZA_NAME_QUERY); + xmpp_stanza_set_ns(query, STANZA_NS_REGISTER); + xmpp_stanza_add_child(iq, query); + + iq_id_handler_add(id, _muc_register_nick_handler, NULL, NULL); + free(id); + + iq_send_stanza(iq); + + xmpp_stanza_release(iq); + xmpp_stanza_release(query); +} diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c index 32892311..9145f9ec 100644 --- a/src/xmpp/stanza.c +++ b/src/xmpp/stanza.c @@ -2828,3 +2828,18 @@ stanza_create_approve_voice(xmpp_ctx_t* ctx, const char* const id, const char* c return message; } + +xmpp_stanza_t* +stanza_create_muc_register_nick(xmpp_ctx_t* ctx, const char* const id, const char* const jid, const char* const node, DataForm* form) +{ + xmpp_stanza_t* iq = xmpp_iq_new(ctx, STANZA_TYPE_SET, id); + + xmpp_stanza_set_to(iq, jid); + + xmpp_stanza_t* x = form_create_submission(form); + + xmpp_stanza_add_child(iq, x); + xmpp_stanza_release(x); + + return iq; +} diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h index 0115942a..06b2815a 100644 --- a/src/xmpp/stanza.h +++ b/src/xmpp/stanza.h @@ -159,6 +159,8 @@ #define STANZA_TYPE_ERROR "error" #define STANZA_TYPE_RESULT "result" #define STANZA_TYPE_SUBMIT "submit" +#define STANZA_TYPE_CANCEL "cancel" +#define STANZA_TYPE_MODIFY "modify" #define STANZA_ATTR_TO "to" #define STANZA_ATTR_FROM "from" @@ -393,13 +395,10 @@ XMPPCaps* stanza_parse_caps(xmpp_stanza_t* const stanza); void stanza_free_caps(XMPPCaps* caps); xmpp_stanza_t* stanza_create_avatar_retrieve_data_request(xmpp_ctx_t* ctx, const char* stanza_id, const char* const item_id, const char* const jid); - xmpp_stanza_t* stanza_create_mam_iq(xmpp_ctx_t* ctx, const char* const jid, const char* const startdate, const char* const lastid); - xmpp_stanza_t* stanza_change_password(xmpp_ctx_t* ctx, const char* const user, const char* const password); - xmpp_stanza_t* stanza_request_voice(xmpp_ctx_t* ctx, const char* const room); - xmpp_stanza_t* stanza_create_approve_voice(xmpp_ctx_t* ctx, const char* const id, const char* const jid, const char* const node, DataForm* form); +xmpp_stanza_t* stanza_create_muc_register_nick(xmpp_ctx_t* ctx, const char* const id, const char* const jid, const char* const node, DataForm* form); #endif diff --git a/src/xmpp/xmpp.h b/src/xmpp/xmpp.h index 5f4efece..4229ddae 100644 --- a/src/xmpp/xmpp.h +++ b/src/xmpp/xmpp.h @@ -259,6 +259,7 @@ void iq_command_list(const char* const target); void iq_command_exec(const char* const target, const char* const command); void iq_mam_request(ProfChatWin* win); void iq_register_change_password(const char* const user, const char* const password); +void iq_muc_register_nick(const char* const roomjid); EntityCapabilities* caps_lookup(const char* const jid); void caps_close(void); -- cgit 1.4.1-2-gfad0