From 965f048b18f7f7456bcb59dca841784aad3bfa11 Mon Sep 17 00:00:00 2001 From: James Booth Date: Mon, 6 Oct 2014 21:42:09 +0100 Subject: [PATCH] Implemented setting and listing roles --- src/command/command.c | 38 +++++++++--- src/command/commands.c | 39 +++++++++++- src/server_events.c | 27 ++++++++ src/server_events.h | 5 ++ src/ui/core.c | 61 ++++++++++++++++++ src/ui/ui.h | 5 ++ src/xmpp/iq.c | 137 +++++++++++++++++++++++++++++++++++++---- src/xmpp/stanza.c | 68 ++++++++++++++++++++ src/xmpp/stanza.h | 4 ++ src/xmpp/xmpp.h | 3 + 10 files changed, 366 insertions(+), 21 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,15 +2277,27 @@ 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); - if (result != NULL) { - return result; - } + char *recipient = ui_current_recipient(); + Autocomplete nick_ac = muc_roster_ac(recipient); - result = autocomplete_param_with_ac(input, size, "/room affiliation list", room_affiliation_ac, TRUE); - if (result != NULL) { - return result; + 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); @@ -2298,6 +2310,16 @@ _room_autocomplete(char *input, int *size) return result; } + 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 affiliation list", room_affiliation_ac, TRUE); + if (result != NULL) { + return result; + } + result = autocomplete_param_with_ac(input, size, "/room affiliation", room_cmd_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 @@ -196,6 +196,33 @@ handle_room_affiliation_list(const char * const room, const char * const affilia ui_handle_room_affiliation_list(room, affiliation, jids); } +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 @@ -1893,6 +1893,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) @@ -1912,6 +1950,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) { @@ -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); @@ -334,6 +338,40 @@ _iq_room_affiliation_set(const char * const room, const char * const jid, char * xmpp_stanza_release(iq); } +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) { @@ -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) { @@ -910,6 +978,51 @@ _room_affiliation_list_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * return 0; } +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 @@ -578,6 +578,33 @@ stanza_create_room_affiliation_list_iq(xmpp_ctx_t *ctx, const char * const room, return iq; } +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) @@ -619,6 +646,47 @@ stanza_create_room_affiliation_set_iq(xmpp_ctx_t *ctx, const char * const room, return iq; } +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);