about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/command/cmd_ac.c24
-rw-r--r--src/command/cmd_defs.c6
-rw-r--r--src/command/cmd_funcs.c5
-rw-r--r--src/profanity.c3
-rw-r--r--src/xmpp/form.c1
-rw-r--r--src/xmpp/message.c46
-rw-r--r--src/xmpp/stanza.c73
-rw-r--r--src/xmpp/stanza.h8
-rw-r--r--src/xmpp/xmpp.h1
9 files changed, 155 insertions, 12 deletions
diff --git a/src/command/cmd_ac.c b/src/command/cmd_ac.c
index 40c8d7ed..a2d949eb 100644
--- a/src/command/cmd_ac.c
+++ b/src/command/cmd_ac.c
@@ -206,7 +206,8 @@ static Autocomplete rooms_list_ac;
 static Autocomplete rooms_cache_ac;
 static Autocomplete affiliation_ac;
 static Autocomplete role_ac;
-static Autocomplete privilege_cmd_ac;
+static Autocomplete affiliation_cmd_ac;
+static Autocomplete role_cmd_ac;
 static Autocomplete subject_ac;
 static Autocomplete form_ac;
 static Autocomplete form_field_multi_ac;
@@ -752,9 +753,14 @@ cmd_ac_init(void)
     autocomplete_add(role_ac, "visitor");
     autocomplete_add(role_ac, "none");
 
-    privilege_cmd_ac = autocomplete_new();
-    autocomplete_add(privilege_cmd_ac, "list");
-    autocomplete_add(privilege_cmd_ac, "set");
+    affiliation_cmd_ac = autocomplete_new();
+    autocomplete_add(affiliation_cmd_ac, "list");
+    autocomplete_add(affiliation_cmd_ac, "request");
+    autocomplete_add(affiliation_cmd_ac, "set");
+
+    role_cmd_ac = autocomplete_new();
+    autocomplete_add(role_cmd_ac, "list");
+    autocomplete_add(role_cmd_ac, "set");
 
     subject_ac = autocomplete_new();
     autocomplete_add(subject_ac, "set");
@@ -1300,7 +1306,8 @@ cmd_ac_reset(ProfWin* window)
     autocomplete_reset(rooms_cache_ac);
     autocomplete_reset(affiliation_ac);
     autocomplete_reset(role_ac);
-    autocomplete_reset(privilege_cmd_ac);
+    autocomplete_reset(affiliation_cmd_ac);
+    autocomplete_reset(role_cmd_ac);
     autocomplete_reset(subject_ac);
     autocomplete_reset(form_ac);
     autocomplete_reset(form_field_multi_ac);
@@ -1457,7 +1464,8 @@ cmd_ac_uninit(void)
     autocomplete_free(rooms_cache_ac);
     autocomplete_free(affiliation_ac);
     autocomplete_free(role_ac);
-    autocomplete_free(privilege_cmd_ac);
+    autocomplete_free(affiliation_cmd_ac);
+    autocomplete_free(role_cmd_ac);
     autocomplete_free(subject_ac);
     autocomplete_free(form_ac);
     autocomplete_free(form_field_multi_ac);
@@ -3106,7 +3114,7 @@ _affiliation_autocomplete(ProfWin* window, const char* const input, gboolean pre
         return result;
     }
 
-    result = autocomplete_param_with_ac(input, "/affiliation", privilege_cmd_ac, TRUE, previous);
+    result = autocomplete_param_with_ac(input, "/affiliation", affiliation_cmd_ac, TRUE, previous);
     if (result) {
         return result;
     }
@@ -3156,7 +3164,7 @@ _role_autocomplete(ProfWin* window, const char* const input, gboolean previous)
         return result;
     }
 
-    result = autocomplete_param_with_ac(input, "/role", privilege_cmd_ac, TRUE, previous);
+    result = autocomplete_param_with_ac(input, "/role", role_cmd_ac, TRUE, previous);
     if (result) {
         return result;
     }
diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c
index 49a2a7db..55f58b49 100644
--- a/src/command/cmd_defs.c
+++ b/src/command/cmd_defs.c
@@ -694,13 +694,15 @@ static struct cmd_t command_defs[] = {
               CMD_TAG_GROUPCHAT)
       CMD_SYN(
               "/affiliation set <affiliation> <jid> [<reason>]",
-              "/affiliation list [<affiliation>]")
+              "/affiliation list [<affiliation>]",
+              "/affiliation request")
       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." })
+              { "list [<affiliation>]", "List all users with the specified affiliation, or all if none specified." },
+              { "request", "Request voice."})
       CMD_NOEXAMPLES
     },
 
diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c
index 6faa64b8..657850e2 100644
--- a/src/command/cmd_funcs.c
+++ b/src/command/cmd_funcs.c
@@ -4161,6 +4161,11 @@ cmd_affiliation(ProfWin* window, const char* const command, gchar** args)
         }
     }
 
+    if (g_strcmp0(cmd, "request") == 0) {
+        message_request_voice(mucwin->roomjid);
+        return TRUE;
+    }
+
     cons_bad_cmd_usage(command);
     return TRUE;
 }
diff --git a/src/profanity.c b/src/profanity.c
index c15146b4..eb829bad 100644
--- a/src/profanity.c
+++ b/src/profanity.c
@@ -91,12 +91,13 @@ static void _shutdown(void);
 static void _connect_default(const char* const account);
 
 pthread_mutex_t lock;
-static gboolean cont = TRUE;
 static gboolean force_quit = FALSE;
 
 void
 prof_run(char* log_level, char* account_name, char* config_file, char* log_file, char* theme_name)
 {
+    gboolean cont = TRUE;
+
     _init(log_level, config_file, log_file, theme_name);
     plugins_on_start();
     _connect_default(account_name);
diff --git a/src/xmpp/form.c b/src/xmpp/form.c
index a1fa31d4..dc8c583c 100644
--- a/src/xmpp/form.c
+++ b/src/xmpp/form.c
@@ -447,6 +447,7 @@ form_tag_exists(DataForm* form, const char* const tag)
     GList* curr = tags;
     while (curr) {
         if (g_strcmp0(curr->data, tag) == 0) {
+            g_list_free(tags);
             return TRUE;
         }
         curr = g_list_next(curr);
diff --git a/src/xmpp/message.c b/src/xmpp/message.c
index ab899407..54be543c 100644
--- a/src/xmpp/message.c
+++ b/src/xmpp/message.c
@@ -64,6 +64,7 @@
 #include "xmpp/stanza.h"
 #include "xmpp/connection.h"
 #include "xmpp/xmpp.h"
+#include "xmpp/form.h"
 
 #ifdef HAVE_OMEMO
 #include "xmpp/omemo.h"
@@ -91,6 +92,7 @@ static xmpp_stanza_t* _handle_carbons(xmpp_stanza_t* const stanza);
 static void _send_message_stanza(xmpp_stanza_t* const stanza);
 static gboolean _handle_mam(xmpp_stanza_t* const stanza);
 static void _handle_pubsub(xmpp_stanza_t* const stanza, xmpp_stanza_t* const event);
+static gboolean _handle_form(xmpp_stanza_t* const stanza);
 
 #ifdef HAVE_LIBGPGME
 static xmpp_stanza_t* _openpgp_signcrypt(xmpp_ctx_t* ctx, const char* const to, const char* const text);
@@ -170,6 +172,11 @@ _message_handler(xmpp_conn_t* const conn, xmpp_stanza_t* const stanza, void* con
     } else if (type == NULL || g_strcmp0(type, STANZA_TYPE_CHAT) != 0 || g_strcmp0(type, STANZA_TYPE_NORMAL) != 0) {
         // type: chat, normal (==NULL)
 
+        // XEP-0045: Multi-User Chat 8.6 Voice Requests
+        if (_handle_form(stanza)) {
+            return 1;
+        }
+
         // XEP-0313: Message Archive Management
         if (_handle_mam(stanza)) {
             return 1;
@@ -249,6 +256,33 @@ _message_handler(xmpp_conn_t* const conn, xmpp_stanza_t* const stanza, void* con
 }
 
 void
+message_muc_submit_voice_approve(ProfConfWin* confwin)
+{
+    xmpp_ctx_t* const ctx = connection_get_ctx();
+    xmpp_stanza_t* message = stanza_create_approve_voice(ctx, NULL, confwin->roomjid, NULL, confwin->form);
+
+    _send_message_stanza(message);
+    xmpp_stanza_release(message);
+}
+
+static gboolean
+_handle_form(xmpp_stanza_t* const stanza)
+{
+    xmpp_stanza_t* result = xmpp_stanza_get_child_by_name_and_ns(stanza, STANZA_NAME_X, STANZA_NS_DATA);
+    if (!result) {
+        return FALSE;
+    }
+
+    const char* const stanza_from = xmpp_stanza_get_from(stanza);
+
+    DataForm* form = form_create(result);
+    ProfConfWin* confwin = (ProfConfWin*)wins_new_config(stanza_from, form, message_muc_submit_voice_approve, NULL, NULL);
+    confwin_handle_configuration(confwin, form);
+
+    return TRUE;
+}
+
+void
 message_handlers_init(void)
 {
     xmpp_conn_t* const conn = connection_get_conn();
@@ -1560,3 +1594,15 @@ _openpgp_signcrypt(xmpp_ctx_t* ctx, const char* const to, const char* const text
     return signcrypt;
 }
 #endif // HAVE_LIBGPGME
+
+void
+message_request_voice(const char* const roomjid)
+{
+    xmpp_ctx_t* const ctx = connection_get_ctx();
+    xmpp_stanza_t* stanza = stanza_request_voice(ctx, roomjid);
+
+    log_debug("Requesting voice in %s", roomjid);
+
+    _send_message_stanza(stanza);
+    xmpp_stanza_release(stanza);
+}
diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c
index 86bd0d91..32892311 100644
--- a/src/xmpp/stanza.c
+++ b/src/xmpp/stanza.c
@@ -2755,3 +2755,76 @@ stanza_change_password(xmpp_ctx_t* ctx, const char* const user, const char* cons
 
     return iq;
 }
+
+xmpp_stanza_t*
+stanza_request_voice(xmpp_ctx_t* ctx, const char* const room)
+{
+    char* id = connection_create_stanza_id();
+    xmpp_stanza_t* message = xmpp_message_new(ctx, NULL, room, id);
+    free(id);
+
+    xmpp_stanza_t* request_voice_st = xmpp_stanza_new(ctx);
+    xmpp_stanza_set_name(request_voice_st, STANZA_NAME_X);
+    xmpp_stanza_set_type(request_voice_st, STANZA_TYPE_SUBMIT);
+    xmpp_stanza_set_ns(request_voice_st, STANZA_NS_DATA);
+
+    xmpp_stanza_t* form_type = xmpp_stanza_new(ctx);
+    xmpp_stanza_set_name(form_type, STANZA_NAME_FIELD);
+    xmpp_stanza_set_attribute(form_type, STANZA_ATTR_VAR, "FORM_TYPE");
+
+    xmpp_stanza_t* value_request = xmpp_stanza_new(ctx);
+    xmpp_stanza_set_name(value_request, STANZA_NAME_VALUE);
+
+    xmpp_stanza_t* request_text = xmpp_stanza_new(ctx);
+    xmpp_stanza_set_text(request_text, STANZA_NS_VOICEREQUEST);
+
+    xmpp_stanza_add_child(value_request, request_text);
+    xmpp_stanza_release(request_text);
+
+    xmpp_stanza_add_child(form_type, value_request);
+    xmpp_stanza_release(value_request);
+
+    xmpp_stanza_add_child(request_voice_st, form_type);
+    xmpp_stanza_release(form_type);
+
+    xmpp_stanza_t* request_role = xmpp_stanza_new(ctx);
+    xmpp_stanza_set_name(request_role, STANZA_NAME_FIELD);
+    xmpp_stanza_set_attribute(request_role, STANZA_ATTR_VAR, "muc#role");
+    xmpp_stanza_set_attribute(request_role, STANZA_ATTR_TYPE, "list-single");
+    xmpp_stanza_set_attribute(request_role, STANZA_ATTR_LABEL, "Requested role");
+
+    xmpp_stanza_t* value_role = xmpp_stanza_new(ctx);
+    xmpp_stanza_set_name(value_role, STANZA_NAME_VALUE);
+
+    xmpp_stanza_t* role_text = xmpp_stanza_new(ctx);
+    xmpp_stanza_set_text(role_text, "participant");
+
+    xmpp_stanza_add_child(value_role, role_text);
+    xmpp_stanza_release(role_text);
+
+    xmpp_stanza_add_child(request_role, value_role);
+    xmpp_stanza_release(value_role);
+
+    xmpp_stanza_add_child(request_voice_st, request_role);
+    xmpp_stanza_release(request_role);
+
+    xmpp_stanza_add_child(message, request_voice_st);
+    xmpp_stanza_release(request_voice_st);
+
+    return message;
+}
+
+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)
+{
+    char* stid = connection_create_stanza_id();
+    xmpp_stanza_t* message = xmpp_message_new(ctx, NULL, jid, stid);
+    free(stid);
+
+    xmpp_stanza_t* x = form_create_submission(form);
+
+    xmpp_stanza_add_child(message, x);
+    xmpp_stanza_release(x);
+
+    return message;
+}
diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h
index 35f38055..0115942a 100644
--- a/src/xmpp/stanza.h
+++ b/src/xmpp/stanza.h
@@ -158,6 +158,7 @@
 #define STANZA_TYPE_SET          "set"
 #define STANZA_TYPE_ERROR        "error"
 #define STANZA_TYPE_RESULT       "result"
+#define STANZA_TYPE_SUBMIT       "submit"
 
 #define STANZA_ATTR_TO             "to"
 #define STANZA_ATTR_FROM           "from"
@@ -186,6 +187,7 @@
 #define STANZA_ATTR_FILENAME       "filename"
 #define STANZA_ATTR_SIZE           "size"
 #define STANZA_ATTR_CONTENTTYPE    "content-type"
+#define STANZA_ATTR_LABEL          "label"
 
 #define STANZA_TEXT_AWAY   "away"
 #define STANZA_TEXT_DND    "dnd"
@@ -233,6 +235,7 @@
 #define STANZA_NS_EXT_GAJIM_BOOKMARKS     "xmpp:gajim.org/bookmarks"
 #define STANZA_NS_RSM                     "http://jabber.org/protocol/rsm"
 #define STANZA_NS_REGISTER                "jabber:iq:register"
+#define STANZA_NS_VOICEREQUEST            "http://jabber.org/protocol/muc#request"
 
 #define STANZA_DATAFORM_SOFTWARE "urn:xmpp:dataforms:softwareinfo"
 
@@ -338,7 +341,6 @@ xmpp_stanza_t* stanza_create_command_config_submit_iq(xmpp_ctx_t* ctx, const cha
 void stanza_attach_publish_options_va(xmpp_ctx_t* const ctx, xmpp_stanza_t* const iq, int count, ...);
 void stanza_attach_publish_options(xmpp_ctx_t* const ctx, xmpp_stanza_t* const iq, const char* const option, const char* const value);
 
-
 xmpp_stanza_t* stanza_create_omemo_devicelist_request(xmpp_ctx_t* ctx, const char* const id, const char* const jid);
 xmpp_stanza_t* stanza_create_omemo_devicelist_subscribe(xmpp_ctx_t* ctx, const char* const jid);
 xmpp_stanza_t* stanza_create_omemo_devicelist_publish(xmpp_ctx_t* ctx, GList* const ids);
@@ -396,4 +398,8 @@ xmpp_stanza_t* stanza_create_mam_iq(xmpp_ctx_t* ctx, const char* const jid, cons
 
 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);
+
 #endif
diff --git a/src/xmpp/xmpp.h b/src/xmpp/xmpp.h
index d4d32836..5f4efece 100644
--- a/src/xmpp/xmpp.h
+++ b/src/xmpp/xmpp.h
@@ -214,6 +214,7 @@ void message_send_composing(const char* const jid);
 void message_send_paused(const char* const jid);
 void message_send_gone(const char* const jid);
 void message_send_invite(const char* const room, const char* const contact, const char* const reason);
+void message_request_voice(const char* const roomjid);
 
 bool message_is_sent_by_us(const ProfMessage* const message, bool checkOID);