about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorMichael Vetter <jubalh@iodoru.org>2021-03-18 20:32:12 +0100
committerMichael Vetter <jubalh@iodoru.org>2021-03-25 11:05:58 +0100
commitfde0a0d1c65ff61eb3d5bb9c07d6974d4fdac1f6 (patch)
tree5665fcc576e40222f0ed1e3e9bb1d2ba55b31b89
parent064174efa3604404fd1b8a5c34cf69ed93ab12dc (diff)
downloadprofani-tty-fde0a0d1c65ff61eb3d5bb9c07d6974d4fdac1f6.tar.gz
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
-rw-r--r--src/command/cmd_ac.c1
-rw-r--r--src/command/cmd_defs.c6
-rw-r--r--src/command/cmd_funcs.c5
-rw-r--r--src/xmpp/iq.c125
-rw-r--r--src/xmpp/stanza.c15
-rw-r--r--src/xmpp/stanza.h7
-rw-r--r--src/xmpp/xmpp.h1
-rw-r--r--tests/unittests/xmpp/stub_xmpp.c10
8 files changed, 164 insertions, 6 deletions
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> <jid> [<reason>]",
               "/affiliation list [<affiliation>]",
-              "/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 <affiliation> <jid> [<reason>]", "Set the affiliation of user with jid, with an optional reason." },
               { "list [<affiliation>]", "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);
diff --git a/tests/unittests/xmpp/stub_xmpp.c b/tests/unittests/xmpp/stub_xmpp.c
index 93dac12a..cffaae7f 100644
--- a/tests/unittests/xmpp/stub_xmpp.c
+++ b/tests/unittests/xmpp/stub_xmpp.c
@@ -409,15 +409,22 @@ iq_register_change_password(const char* const user, const char* const password)
 {
 }
 
+void
+iq_muc_register_nick(const char* const roomjid)
+{
+}
+
 // caps functions
 void
 caps_add_feature(char* feature)
 {
 }
+
 void
 caps_remove_feature(char* feature)
 {
 }
+
 EntityCapabilities*
 caps_lookup(const char* const jid)
 {
@@ -428,14 +435,17 @@ void
 caps_close(void)
 {
 }
+
 void
 caps_destroy(EntityCapabilities* caps)
 {
 }
+
 void
 caps_reset_ver(void)
 {
 }
+
 gboolean
 caps_jid_has_feature(const char* const jid, const char* const feature)
 {