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/command.c32
-rw-r--r--src/command/commands.c39
-rw-r--r--src/server_events.c27
-rw-r--r--src/server_events.h5
-rw-r--r--src/ui/core.c61
-rw-r--r--src/ui/ui.h5
-rw-r--r--src/xmpp/iq.c137
-rw-r--r--src/xmpp/stanza.c68
-rw-r--r--src/xmpp/stanza.h4
-rw-r--r--src/xmpp/xmpp.h3
10 files changed, 363 insertions, 18 deletions
diff --git a/src/command/command.c b/src/command/command.c
index 5f44b6d4..daa86d76 100644
--- a/src/command/command.c
+++ b/src/command/command.c
@@ -2277,23 +2277,45 @@ static char *
 _room_autocomplete(char *input, int *size)
 {
     char *result = NULL;
+    gboolean parse_result;
 
-    result = autocomplete_param_with_ac(input, size, "/room affiliation set", room_affiliation_ac, TRUE);
+    char *recipient = ui_current_recipient();
+    Autocomplete nick_ac = muc_roster_ac(recipient);
+
+    input[*size] = '\0';
+    gchar **args = parse_args(input, 4, 4, &parse_result);
+
+    if ((strncmp(input, "/room", 5) == 0) && (parse_result == TRUE)) {
+        GString *beginning = g_string_new("/room ");
+        g_string_append(beginning, args[0]);
+        g_string_append(beginning, " ");
+        g_string_append(beginning, args[1]);
+        g_string_append(beginning, " ");
+        g_string_append(beginning, args[2]);
+
+        result = autocomplete_param_with_ac(input, size, beginning->str, nick_ac, TRUE);
+        g_string_free(beginning, TRUE);
+        if (result != NULL) {
+            return result;
+        }
+    }
+
+    result = autocomplete_param_with_ac(input, size, "/room role set", room_role_ac, TRUE);
     if (result != NULL) {
         return result;
     }
 
-    result = autocomplete_param_with_ac(input, size, "/room affiliation list", room_affiliation_ac, TRUE);
+    result = autocomplete_param_with_ac(input, size, "/room role list", room_role_ac, TRUE);
     if (result != NULL) {
         return result;
     }
 
-    result = autocomplete_param_with_ac(input, size, "/room role set", room_role_ac, TRUE);
+    result = autocomplete_param_with_ac(input, size, "/room affiliation set", room_affiliation_ac, TRUE);
     if (result != NULL) {
         return result;
     }
 
-    result = autocomplete_param_with_ac(input, size, "/room role list", room_role_ac, TRUE);
+    result = autocomplete_param_with_ac(input, size, "/room affiliation list", room_affiliation_ac, TRUE);
     if (result != NULL) {
         return result;
     }
@@ -2313,8 +2335,6 @@ _room_autocomplete(char *input, int *size)
         return result;
     }
 
-    char *recipient = ui_current_recipient();
-    Autocomplete nick_ac = muc_roster_ac(recipient);
     if (nick_ac != NULL) {
         result = autocomplete_param_with_ac(input, size, "/room kick", nick_ac, TRUE);
         if (result != NULL) {
diff --git a/src/command/commands.c b/src/command/commands.c
index 7678f2c1..f1fff045 100644
--- a/src/command/commands.c
+++ b/src/command/commands.c
@@ -2237,7 +2237,44 @@ cmd_room(gchar **args, struct cmd_help_t help)
     }
 
     if (g_strcmp0(args[0], "role") == 0) {
-        cons_show("/room role...");
+        char *cmd = args[1];
+        if (cmd == NULL) {
+            cons_show("Usage: %s", help.usage);
+            return TRUE;
+        }
+
+        char *role = args[2];
+        if ((g_strcmp0(role, "visitor") != 0) &&
+                (g_strcmp0(role, "participant") != 0) &&
+                (g_strcmp0(role, "moderator") != 0) &&
+                (g_strcmp0(role, "none") != 0)) {
+            cons_show("Usage: %s", help.usage);
+            return TRUE;
+        }
+
+        if (g_strcmp0(cmd, "list") == 0) {
+            if (g_strcmp0(role, "none") == 0) {
+                win_save_print(window, '!', NULL, 0, 0, "", "Cannot list users with no role.");
+            } else if (g_strcmp0(role, "visitor") == 0) {
+                win_save_print(window, '!', NULL, 0, 0, "", "Cannot list users with visitor role.");
+            } else {
+                iq_room_role_list(room, role);
+            }
+            return TRUE;
+        }
+
+        if (g_strcmp0(cmd, "set") == 0) {
+            char *nick = args[3];
+            if (nick == NULL) {
+                cons_show("Usage: %s", help.usage);
+                return TRUE;
+            } else {
+                char *reason = args[4];
+                iq_room_role_set(room, nick, role, reason);
+                return TRUE;
+            }
+        }
+
         return TRUE;
     }
 
diff --git a/src/server_events.c b/src/server_events.c
index 0bb017b8..3c2620b1 100644
--- a/src/server_events.c
+++ b/src/server_events.c
@@ -197,6 +197,33 @@ handle_room_affiliation_list(const char * const room, const char * const affilia
 }
 
 void
+handle_room_role_set_error(const char * const room, const char * const nick, const char * const role,
+    const char * const error)
+{
+    log_debug("Error setting role %s list for room %s, user %s: %s", role, room, nick, error);
+    ui_handle_room_role_set_error(room, nick, role, error);
+}
+
+void
+handle_room_role_set(const char * const room, const char * const nick, const char * const role)
+{
+    ui_handle_room_role_set(room, nick, role);
+}
+
+void
+handle_room_role_list_result_error(const char * const room, const char * const role, const char * const error)
+{
+    log_debug("Error retrieving %s list for room %s: %s", role, room, error);
+    ui_handle_room_role_list_error(room, role, error);
+}
+
+void
+handle_room_role_list(const char * const room, const char * const role, GSList *nicks)
+{
+    ui_handle_room_role_list(room, role, nicks);
+}
+
+void
 handle_room_affiliation_set_error(const char * const room, const char * const jid, const char * const affiliation,
     const char * const error)
 {
diff --git a/src/server_events.h b/src/server_events.h
index 92988bd9..56b01965 100644
--- a/src/server_events.h
+++ b/src/server_events.h
@@ -65,6 +65,11 @@ void handle_room_affiliation_list(const char * const room, const char * const af
 void handle_room_affiliation_set_error(const char * const room, const char * const jid, const char * const affiliation,
     const char * const error);
 void handle_room_affiliation_set(const char * const room, const char * const jid, const char * const affiliation);
+void handle_room_role_list_result_error(const char * const from, const char * const role, const char * const error);
+void handle_room_role_list(const char * const from, const char * const role, GSList *nicks);
+void handle_room_role_set_error(const char * const room, const char * const nick, const char * const role,
+    const char * const error);
+void handle_room_role_set(const char * const from, const char * const nick, const char * const role);
 void handle_room_kick_result_error(const char * const room, const char * const nick, const char * const error);
 void handle_duck_result(const char * const result);
 void handle_incoming_message(char *from, char *message, gboolean priv);
diff --git a/src/ui/core.c b/src/ui/core.c
index a0712142..5269e96b 100644
--- a/src/ui/core.c
+++ b/src/ui/core.c
@@ -1894,6 +1894,44 @@ _ui_handle_room_affiliation_list(const char * const room, const char * const aff
 }
 
 static void
+_ui_handle_room_role_list_error(const char * const room, const char * const role, const char * const error)
+{
+    ProfWin *window = wins_get_by_recipient(room);
+    if (window) {
+        win_save_vprint(window, '!', NULL, 0, COLOUR_ERROR, "", "Error retrieving %s list: %s", role, error);
+    }
+}
+
+static void
+_ui_handle_room_role_list(const char * const room, const char * const role, GSList *nicks)
+{
+    ProfWin *window = wins_get_by_recipient(room);
+    if (window) {
+        if (nicks) {
+            win_save_vprint(window, '!', NULL, 0, 0, "", "Role: %s", role);
+            GSList *curr_nick = nicks;
+            while (curr_nick) {
+                char *nick = curr_nick->data;
+                Occupant *occupant = muc_roster_item(room, nick);
+                if (occupant) {
+                    if (occupant->jid) {
+                        win_save_vprint(window, '!', NULL, 0, 0, "", "  %s (%s)", nick, occupant->jid);
+                    } else {
+                        win_save_vprint(window, '!', NULL, 0, 0, "", "  %s", nick);
+                    }
+                } else {
+                    win_save_vprint(window, '!', NULL, 0, 0, "", "  %s", nick);
+                }
+                curr_nick = g_slist_next(curr_nick);
+            }
+            win_save_print(window, '!', NULL, 0, 0, "", "");
+        } else {
+            win_save_vprint(window, '!', NULL, 0, 0, "", "No occupants found with role: %s", role);
+        }
+    }
+}
+
+static void
 _ui_handle_room_affiliation_set_error(const char * const room, const char * const jid, const char * const affiliation,
     const char * const error)
 {
@@ -1913,6 +1951,25 @@ _ui_handle_room_affiliation_set(const char * const room, const char * const jid,
 }
 
 static void
+_ui_handle_room_role_set_error(const char * const room, const char * const nick, const char * const role,
+    const char * const error)
+{
+    ProfWin *window = wins_get_by_recipient(room);
+    if (window) {
+        win_save_vprint(window, '!', NULL, 0, COLOUR_ERROR, "", "Error setting %s role for %s: %s", role, nick, error);
+    }
+}
+
+static void
+_ui_handle_room_role_set(const char * const room, const char * const nick, const char * const role)
+{
+    ProfWin *window = wins_get_by_recipient(room);
+    if (window) {
+        win_save_vprint(window, '!', NULL, 0, 0, "", "Role for %s set: %s", nick, role);
+    }
+}
+
+static void
 _ui_status(void)
 {
     char *recipient = ui_current_recipient();
@@ -2870,5 +2927,9 @@ ui_init_module(void)
     ui_room_kicked = _ui_room_kicked;
     ui_leave_room = _ui_leave_room;
     ui_room_member_kicked = _ui_room_member_kicked;
+    ui_handle_room_role_set_error = _ui_handle_room_role_set_error;
+    ui_handle_room_role_set = _ui_handle_room_role_set;
+    ui_handle_room_role_list_error = _ui_handle_room_role_list_error;
+    ui_handle_room_role_list = _ui_handle_room_role_list;
 }
 
diff --git a/src/ui/ui.h b/src/ui/ui.h
index dafcceac..f987bdbb 100644
--- a/src/ui/ui.h
+++ b/src/ui/ui.h
@@ -180,6 +180,11 @@ void (*ui_handle_room_affiliation_list)(const char * const room, const char * co
 void (*ui_handle_room_affiliation_set_error)(const char * const room, const char * const jid,
     const char * const affiliation, const char * const error);
 void (*ui_handle_room_affiliation_set)(const char * const room, const char * const jid, const char * const affiliation);
+void (*ui_handle_room_role_set_error)(const char * const room, const char * const nick, const char * const role,
+    const char * const error);
+void (*ui_handle_room_role_set)(const char * const room, const char * const nick, const char * const role);
+void (*ui_handle_room_role_list_error)(const char * const room, const char * const role, const char * const error);
+void (*ui_handle_room_role_list)(const char * const room, const char * const role, GSList *nicks);
 void (*ui_handle_room_kick_error)(const char * const room, const char * const nick, const char * const error);
 void (*ui_show_form)(ProfWin *window, const char * const room, DataForm *form);
 void (*ui_show_form_field)(ProfWin *window, DataForm *form, char *tag);
diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c
index c24e4ecc..b9a646af 100644
--- a/src/xmpp/iq.c
+++ b/src/xmpp/iq.c
@@ -84,6 +84,10 @@ static int _room_affiliation_list_result_handler(xmpp_conn_t * const conn,
     xmpp_stanza_t * const stanza, void * const userdata);
 static int _room_affiliation_set_result_handler(xmpp_conn_t * const conn,
     xmpp_stanza_t * const stanza, void * const userdata);
+static int _room_role_set_result_handler(xmpp_conn_t * const conn,
+    xmpp_stanza_t * const stanza, void * const userdata);
+static int _room_role_list_result_handler(xmpp_conn_t * const conn,
+    xmpp_stanza_t * const stanza, void * const userdata);
 static int _room_kick_result_handler(xmpp_conn_t * const conn,
     xmpp_stanza_t * const stanza, void * const userdata);
 static int _manual_pong_handler(xmpp_conn_t *const conn,
@@ -309,9 +313,9 @@ _iq_room_kick_occupant(const char * const room, const char * const nick, const c
     xmpp_stanza_release(iq);
 }
 
-struct affiliation_set_t {
-    char *jid;
-    char *affiliation;
+struct privilege_set_t {
+    char *item;
+    char *privilege;
 };
 
 static void
@@ -324,9 +328,9 @@ _iq_room_affiliation_set(const char * const room, const char * const jid, char *
 
     char *id = xmpp_stanza_get_id(iq);
 
-    struct affiliation_set_t *affiliation_set = malloc(sizeof(struct affiliation_set_t));
-    affiliation_set->jid = strdup(jid);
-    affiliation_set->affiliation = strdup(affiliation);
+    struct privilege_set_t *affiliation_set = malloc(sizeof(struct privilege_set_t));
+    affiliation_set->item = strdup(jid);
+    affiliation_set->privilege = strdup(affiliation);
 
     xmpp_id_handler_add(conn, _room_affiliation_set_result_handler, id, affiliation_set);
 
@@ -335,6 +339,40 @@ _iq_room_affiliation_set(const char * const room, const char * const jid, char *
 }
 
 static void
+_iq_room_role_set(const char * const room, const char * const nick, char *role,
+    const char * const reason)
+{
+    xmpp_conn_t * const conn = connection_get_conn();
+    xmpp_ctx_t * const ctx = connection_get_ctx();
+    xmpp_stanza_t *iq = stanza_create_room_role_set_iq(ctx, room, nick, role, reason);
+
+    char *id = xmpp_stanza_get_id(iq);
+
+    struct privilege_set_t *role_set = malloc(sizeof(struct privilege_set_t));
+    role_set->item = strdup(nick);
+    role_set->privilege = strdup(role);
+
+    xmpp_id_handler_add(conn, _room_role_set_result_handler, id, role_set);
+
+    xmpp_send(conn, iq);
+    xmpp_stanza_release(iq);
+}
+
+static void
+_iq_room_role_list(const char * const room, char *role)
+{
+    xmpp_conn_t * const conn = connection_get_conn();
+    xmpp_ctx_t * const ctx = connection_get_ctx();
+    xmpp_stanza_t *iq = stanza_create_room_role_list_iq(ctx, room, role);
+
+    char *id = xmpp_stanza_get_id(iq);
+    xmpp_id_handler_add(conn, _room_role_list_result_handler, id, strdup(role));
+
+    xmpp_send(conn, iq);
+    xmpp_stanza_release(iq);
+}
+
+static void
 _iq_send_ping(const char * const target)
 {
     xmpp_conn_t * const conn = connection_get_conn();
@@ -841,7 +879,7 @@ static int _room_affiliation_set_result_handler(xmpp_conn_t * const conn, xmpp_s
     const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID);
     const char *type = xmpp_stanza_get_type(stanza);
     const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM);
-    struct affiliation_set_t *affiliation_set = (struct affiliation_set_t *)userdata;
+    struct privilege_set_t *affiliation_set = (struct privilege_set_t *)userdata;
 
     if (id != NULL) {
         log_debug("IQ affiliation set handler fired, id: %s.", id);
@@ -852,19 +890,49 @@ static int _room_affiliation_set_result_handler(xmpp_conn_t * const conn, xmpp_s
     // handle error responses
     if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) {
         char *error_message = stanza_get_error_message(stanza);
-        handle_room_affiliation_set_error(from, affiliation_set->jid, affiliation_set->affiliation, error_message);
+        handle_room_affiliation_set_error(from, affiliation_set->item, affiliation_set->privilege, error_message);
         free(error_message);
     } else {
-        handle_room_affiliation_set(from, affiliation_set->jid, affiliation_set->affiliation);
+        handle_room_affiliation_set(from, affiliation_set->item, affiliation_set->privilege);
     }
 
-    free(affiliation_set->jid);
-    free(affiliation_set->affiliation);
+    free(affiliation_set->item);
+    free(affiliation_set->privilege);
     free(affiliation_set);
 
     return 0;
 }
 
+static int _room_role_set_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
+    void * const userdata)
+{
+    const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID);
+    const char *type = xmpp_stanza_get_type(stanza);
+    const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM);
+    struct privilege_set_t *role_set = (struct privilege_set_t *)userdata;
+
+    if (id != NULL) {
+        log_debug("IQ role set handler fired, id: %s.", id);
+    } else {
+        log_debug("IQ role set handler fired.");
+    }
+
+    // handle error responses
+    if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) {
+        char *error_message = stanza_get_error_message(stanza);
+        handle_room_role_set_error(from, role_set->item, role_set->privilege, error_message);
+        free(error_message);
+    } else {
+        handle_room_role_set(from, role_set->item, role_set->privilege);
+    }
+
+    free(role_set->item);
+    free(role_set->privilege);
+    free(role_set);
+
+    return 0;
+}
+
 static int
 _room_affiliation_list_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata)
 {
@@ -911,6 +979,51 @@ _room_affiliation_list_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t *
 }
 
 static int
+_room_role_list_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata)
+{
+    const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID);
+    const char *type = xmpp_stanza_get_type(stanza);
+    const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM);
+    char *role = (char *)userdata;
+
+    if (id != NULL) {
+        log_debug("IQ role list result handler fired, id: %s.", id);
+    } else {
+        log_debug("IQ role list result handler fired.");
+    }
+
+    // handle error responses
+    if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) {
+        char *error_message = stanza_get_error_message(stanza);
+        handle_room_role_list_result_error(from, role, error_message);
+        free(error_message);
+        free(role);
+        return 0;
+    }
+    GSList *nicks = NULL;
+
+    xmpp_stanza_t *query = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_ADMIN);
+    if (query) {
+        xmpp_stanza_t *child = xmpp_stanza_get_children(query);
+        while (child) {
+            char *name = xmpp_stanza_get_name(child);
+            if (g_strcmp0(name, "item") == 0) {
+                char *nick = xmpp_stanza_get_attribute(child, STANZA_ATTR_NICK);
+                if (nick) {
+                    nicks = g_slist_insert_sorted(nicks, nick, (GCompareFunc)g_strcmp0);
+                }
+            }
+            child = xmpp_stanza_get_next(child);
+        }
+    }
+
+    handle_room_role_list(from, role, nicks);
+    free(role);
+
+    return 0;
+}
+
+static int
 _room_config_submit_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
     void * const userdata)
 {
@@ -1141,5 +1254,7 @@ iq_init_module(void)
     iq_room_info_request = _iq_room_info_request;
     iq_room_affiliation_set = _iq_room_affiliation_set;
     iq_room_affiliation_list = _iq_room_affiliation_list;
+    iq_room_role_set = _iq_room_role_set;
     iq_room_kick_occupant = _iq_room_kick_occupant;
+    iq_room_role_list = _iq_room_role_list;
 }
\ No newline at end of file
diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c
index 07e96659..03b81bf3 100644
--- a/src/xmpp/stanza.c
+++ b/src/xmpp/stanza.c
@@ -579,6 +579,33 @@ stanza_create_room_affiliation_list_iq(xmpp_ctx_t *ctx, const char * const room,
 }
 
 xmpp_stanza_t *
+stanza_create_room_role_list_iq(xmpp_ctx_t *ctx, const char * const room, const char * const role)
+{
+    xmpp_stanza_t *iq = xmpp_stanza_new(ctx);
+    xmpp_stanza_set_name(iq, STANZA_NAME_IQ);
+    xmpp_stanza_set_type(iq, STANZA_TYPE_GET);
+    xmpp_stanza_set_attribute(iq, STANZA_ATTR_TO, room);
+    char *id = create_unique_id("role_get");
+    xmpp_stanza_set_id(iq, id);
+    free(id);
+
+    xmpp_stanza_t *query = xmpp_stanza_new(ctx);
+    xmpp_stanza_set_name(query, STANZA_NAME_QUERY);
+    xmpp_stanza_set_ns(query, STANZA_NS_MUC_ADMIN);
+
+    xmpp_stanza_t *item = xmpp_stanza_new(ctx);
+    xmpp_stanza_set_name(item, STANZA_NAME_ITEM);
+    xmpp_stanza_set_attribute(item, "role", role);
+
+    xmpp_stanza_add_child(query, item);
+    xmpp_stanza_release(item);
+    xmpp_stanza_add_child(iq, query);
+    xmpp_stanza_release(query);
+
+    return iq;
+}
+
+xmpp_stanza_t *
 stanza_create_room_affiliation_set_iq(xmpp_ctx_t *ctx, const char * const room, const char * const jid,
     const char * const affiliation, const char * const reason)
 {
@@ -620,6 +647,47 @@ stanza_create_room_affiliation_set_iq(xmpp_ctx_t *ctx, const char * const room,
 }
 
 xmpp_stanza_t *
+stanza_create_room_role_set_iq(xmpp_ctx_t * const ctx, const char * const room, const char * const nick,
+    const char * const role, const char * const reason)
+{
+    xmpp_stanza_t *iq = xmpp_stanza_new(ctx);
+    xmpp_stanza_set_name(iq, STANZA_NAME_IQ);
+    xmpp_stanza_set_type(iq, STANZA_TYPE_SET);
+    xmpp_stanza_set_attribute(iq, STANZA_ATTR_TO, room);
+    char *id = create_unique_id("role_set");
+    xmpp_stanza_set_id(iq, id);
+    free(id);
+
+    xmpp_stanza_t *query = xmpp_stanza_new(ctx);
+    xmpp_stanza_set_name(query, STANZA_NAME_QUERY);
+    xmpp_stanza_set_ns(query, STANZA_NS_MUC_ADMIN);
+
+    xmpp_stanza_t *item = xmpp_stanza_new(ctx);
+    xmpp_stanza_set_name(item, STANZA_NAME_ITEM);
+    xmpp_stanza_set_attribute(item, "role", role);
+    xmpp_stanza_set_attribute(item, STANZA_ATTR_NICK, nick);
+
+    if (reason) {
+        xmpp_stanza_t *reason_st = xmpp_stanza_new(ctx);
+        xmpp_stanza_set_name(reason_st, STANZA_NAME_REASON);
+        xmpp_stanza_t *reason_text = xmpp_stanza_new(ctx);
+        xmpp_stanza_set_text(reason_text, reason);
+        xmpp_stanza_add_child(reason_st, reason_text);
+        xmpp_stanza_release(reason_text);
+
+        xmpp_stanza_add_child(item, reason_st);
+        xmpp_stanza_release(reason_st);
+    }
+
+    xmpp_stanza_add_child(query, item);
+    xmpp_stanza_release(item);
+    xmpp_stanza_add_child(iq, query);
+    xmpp_stanza_release(query);
+
+    return iq;
+}
+
+xmpp_stanza_t *
 stanza_create_room_kick_iq(xmpp_ctx_t * const ctx, const char * const room, const char * const nick,
     const char * const reason)
 {
diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h
index ae673848..56aea01b 100644
--- a/src/xmpp/stanza.h
+++ b/src/xmpp/stanza.h
@@ -210,6 +210,10 @@ xmpp_stanza_t* stanza_create_room_affiliation_list_iq(xmpp_ctx_t *ctx, const cha
     const char * const affiliation);
 xmpp_stanza_t* stanza_create_room_affiliation_set_iq(xmpp_ctx_t *ctx, const char * const room, const char * const jid,
     const char * const affiliation, const char * const reason);
+xmpp_stanza_t* stanza_create_room_role_set_iq(xmpp_ctx_t * const ctx, const char * const room, const char * const jid,
+    const char * const role, const char * const reason);
+xmpp_stanza_t* stanza_create_room_role_list_iq(xmpp_ctx_t *ctx, const char * const room, const char * const role);
+
 xmpp_stanza_t* stanza_create_room_subject_message(xmpp_ctx_t *ctx, const char * const room, const char * const subject);
 xmpp_stanza_t* stanza_create_room_kick_iq(xmpp_ctx_t * const ctx, const char * const room, const char * const nick,
     const char * const reason);
diff --git a/src/xmpp/xmpp.h b/src/xmpp/xmpp.h
index fc75a7ec..798cb339 100644
--- a/src/xmpp/xmpp.h
+++ b/src/xmpp/xmpp.h
@@ -198,6 +198,9 @@ void (*iq_room_affiliation_list)(const char * const room, char *affiliation);
 void (*iq_room_affiliation_set)(const char * const room, const char * const jid, char *affiliation,
     const char * const reason);
 void (*iq_room_kick_occupant)(const char * const room, const char * const nick, const char * const reason);
+void (*iq_room_role_set)(const char * const room, const char * const nick, char *role,
+    const char * const reason);
+void (*iq_room_role_list)(const char * const room, char *role);
 
 // caps functions
 Capabilities* (*caps_lookup)(const char * const jid);