From 26a182945fcdada1f15e49ba7912f7b8ea88cd87 Mon Sep 17 00:00:00 2001 From: James Booth Date: Mon, 5 Feb 2018 20:01:54 +0000 Subject: [PATCH] Add /rooms cache --- src/command/cmd_ac.c | 44 ++++++++++++++++++++++++++------ src/command/cmd_defs.c | 9 ++++--- src/command/cmd_funcs.c | 26 +++++++++++++++++-- src/config/preferences.c | 4 +++ src/config/preferences.h | 1 + src/ui/console.c | 11 ++++++++ src/ui/ui.h | 1 + src/xmpp/iq.c | 26 ++++++++++++++++++- src/xmpp/xmpp.h | 1 + tests/unittests/ui/stub_ui.c | 1 + tests/unittests/xmpp/stub_xmpp.c | 1 + 11 files changed, 111 insertions(+), 14 deletions(-) diff --git a/src/command/cmd_ac.c b/src/command/cmd_ac.c index 069e883e..a0226d31 100644 --- a/src/command/cmd_ac.c +++ b/src/command/cmd_ac.c @@ -162,7 +162,9 @@ static Autocomplete alias_ac; static Autocomplete aliases_ac; static Autocomplete join_property_ac; static Autocomplete room_ac; -static Autocomplete rooms_ac; +static Autocomplete rooms_all_ac; +static Autocomplete rooms_list_ac; +static Autocomplete rooms_cache_ac; static Autocomplete affiliation_ac; static Autocomplete role_ac; static Autocomplete privilege_cmd_ac; @@ -593,9 +595,19 @@ cmd_ac_init(void) autocomplete_add(room_ac, "destroy"); autocomplete_add(room_ac, "config"); - rooms_ac = autocomplete_new(); - autocomplete_add(rooms_ac, "service"); - autocomplete_add(rooms_ac, "filter"); + rooms_all_ac = autocomplete_new(); + autocomplete_add(rooms_all_ac, "service"); + autocomplete_add(rooms_all_ac, "filter"); + autocomplete_add(rooms_all_ac, "cache"); + + rooms_list_ac = autocomplete_new(); + autocomplete_add(rooms_list_ac, "service"); + autocomplete_add(rooms_list_ac, "filter"); + + rooms_cache_ac = autocomplete_new(); + autocomplete_add(rooms_cache_ac, "on"); + autocomplete_add(rooms_cache_ac, "off"); + autocomplete_add(rooms_cache_ac, "clear"); affiliation_ac = autocomplete_new(); autocomplete_add(affiliation_ac, "owner"); @@ -1011,7 +1023,9 @@ cmd_ac_reset(ProfWin *window) autocomplete_reset(aliases_ac); autocomplete_reset(join_property_ac); autocomplete_reset(room_ac); - autocomplete_reset(rooms_ac); + autocomplete_reset(rooms_all_ac); + autocomplete_reset(rooms_list_ac); + autocomplete_reset(rooms_cache_ac); autocomplete_reset(affiliation_ac); autocomplete_reset(role_ac); autocomplete_reset(privilege_cmd_ac); @@ -1131,7 +1145,9 @@ cmd_ac_uninit(void) autocomplete_free(aliases_ac); autocomplete_free(join_property_ac); autocomplete_free(room_ac); - autocomplete_free(rooms_ac); + autocomplete_free(rooms_all_ac); + autocomplete_free(rooms_list_ac); + autocomplete_free(rooms_cache_ac); autocomplete_free(affiliation_ac); autocomplete_free(role_ac); autocomplete_free(privilege_cmd_ac); @@ -3111,16 +3127,28 @@ _rooms_autocomplete(ProfWin *window, const char *const input, gboolean previous) gboolean space_at_end = g_str_has_suffix(input, " "); int num_args = g_strv_length(args); if (num_args <= 1) { - found = autocomplete_param_with_ac(input, "/rooms", rooms_ac, TRUE, previous); + found = autocomplete_param_with_ac(input, "/rooms", rooms_all_ac, TRUE, previous); if (found) { g_strfreev(args); return found; } } + if ((num_args == 1 && g_strcmp0(args[0], "cache") == 0 && space_at_end) || + (num_args == 2 && g_strcmp0(args[0], "cache") == 0)) { + found = autocomplete_param_with_ac(input, "/rooms cache", rooms_cache_ac, TRUE, previous); + if (found) { + g_strfreev(args); + return found; + } + } + if ((num_args >= 2) && g_strcmp0(args[0], "cache") == 0) { + g_strfreev(args); + return NULL; + } if ((num_args == 2 && space_at_end) || (num_args == 3 && !space_at_end)) { GString *beginning = g_string_new("/rooms"); g_string_append_printf(beginning, " %s %s", args[0], args[1]); - found = autocomplete_param_with_ac(input, beginning->str, rooms_ac, TRUE, previous); + found = autocomplete_param_with_ac(input, beginning->str, rooms_list_ac, TRUE, previous); g_string_free(beginning, TRUE); if (found) { g_strfreev(args); diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c index 1bad76cf..8bc670be 100644 --- a/src/command/cmd_defs.c +++ b/src/command/cmd_defs.c @@ -797,14 +797,17 @@ static struct cmd_t command_defs[] = "/rooms", "/rooms filter ", "/rooms service ", - "/rooms service filter ") + "/rooms service filter ", + "/rooms cache on|off|clear") CMD_DESC( "List the chat rooms available at the specified conference service. " "If no argument is supplied, the account preference 'muc.service' is used, 'conference.' by default. " "The filter argument only shows rooms that contain the provided text, case insensitive.") CMD_ARGS( - { "service ", "The conference service to query." }, - { "filter ", "The text to filter results by."}) + { "service ", "The conference service to query." }, + { "filter ", "The text to filter results by."}, + { "cache on|off", "Enable or disable caching of rooms list response."}, + { "cache clear", "Clear the rooms response cache if enabled."}) CMD_EXAMPLES( "/rooms", "/rooms filter development", diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index bde86835..023327ed 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -2876,7 +2876,7 @@ cmd_roster(ProfWin *window, const char *const command, gchar **args) if (conn_status == JABBER_CONNECTED) { rosterwin_roster(); } - return TRUE; + return TRUE; } else { cons_bad_cmd_usage(command); return TRUE; @@ -2888,7 +2888,7 @@ cmd_roster(ProfWin *window, const char *const command, gchar **args) if (conn_status == JABBER_CONNECTED) { rosterwin_roster(); } - return TRUE; + return TRUE; } else { cons_bad_cmd_usage(command); return TRUE; @@ -4410,6 +4410,28 @@ cmd_rooms(ProfWin *window, const char *const command, gchar **args) return TRUE; } filter = g_strdup(args[1]); + } else if (g_strcmp0(args[0], "cache") == 0) { + if (g_strv_length(args) != 2) { + cons_bad_cmd_usage(command); + cons_show(""); + return TRUE; + } else if (g_strcmp0(args[1], "on") == 0) { + prefs_set_boolean(PREF_ROOM_LIST_CACHE, TRUE); + cons_show("Rooms list cache enabled."); + return TRUE; + } else if (g_strcmp0(args[1], "off") == 0) { + prefs_set_boolean(PREF_ROOM_LIST_CACHE, FALSE); + cons_show("Rooms list cache disabled."); + return TRUE; + } else if (g_strcmp0(args[1], "clear") == 0) { + iq_rooms_cache_clear(); + cons_show("Rooms list cache cleared."); + return TRUE; + } else { + cons_bad_cmd_usage(command); + cons_show(""); + return TRUE; + } } else { cons_bad_cmd_usage(command); cons_show(""); diff --git a/src/config/preferences.c b/src/config/preferences.c index 65281505..d935061c 100644 --- a/src/config/preferences.c +++ b/src/config/preferences.c @@ -1615,6 +1615,7 @@ _get_group(preference_t pref) case PREF_PGP_LOG: return PREF_GROUP_PGP; case PREF_BOOKMARK_INVITE: + case PREF_ROOM_LIST_CACHE: return PREF_GROUP_MUC; case PREF_PLUGINS_SOURCEPATH: return PREF_GROUP_PLUGINS; @@ -1822,6 +1823,8 @@ _get_key(preference_t pref) return "bookmark.invite"; case PREF_PLUGINS_SOURCEPATH: return "sourcepath"; + case PREF_ROOM_LIST_CACHE: + return "rooms.cache"; default: return NULL; } @@ -1870,6 +1873,7 @@ _get_default_boolean(preference_t pref) case PREF_NOTIFY_MENTION_WHOLE_WORD: case PREF_TRAY_READ: case PREF_BOOKMARK_INVITE: + case PREF_ROOM_LIST_CACHE: return TRUE; default: return FALSE; diff --git a/src/config/preferences.h b/src/config/preferences.h index e8f26e52..6eb2241d 100644 --- a/src/config/preferences.h +++ b/src/config/preferences.h @@ -143,6 +143,7 @@ typedef enum { PREF_CONSOLE_CHAT, PREF_BOOKMARK_INVITE, PREF_PLUGINS_SOURCEPATH, + PREF_ROOM_LIST_CACHE, } preference_t; typedef struct prof_alias_t { diff --git a/src/ui/console.c b/src/ui/console.c index 4123cd0d..c32b47f8 100644 --- a/src/ui/console.c +++ b/src/ui/console.c @@ -1247,6 +1247,16 @@ cons_occupants_setting(void) cons_show("Occupants size (/occupants) : %d", size); } +void +cons_rooms_cache_setting(void) +{ + if (prefs_get_boolean(PREF_ROOM_LIST_CACHE)) { + cons_show("Room list cache (/rooms cache) : ON"); + } else { + cons_show("Room list cache (/rooms cache) : OFF"); + } +} + void cons_autoconnect_setting(void) { @@ -1906,6 +1916,7 @@ cons_show_connection_prefs(void) cons_reconnect_setting(); cons_autoping_setting(); cons_autoconnect_setting(); + cons_rooms_cache_setting(); cons_alert(); } diff --git a/src/ui/ui.h b/src/ui/ui.h index 1fb88ec9..9168f58a 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -316,6 +316,7 @@ void cons_autoaway_setting(void); void cons_reconnect_setting(void); void cons_autoping_setting(void); void cons_autoconnect_setting(void); +void cons_room_cache_setting(void); void cons_inpblock_setting(void); void cons_winpos_setting(void); void cons_show_contact_online(PContact contact, Resource *resource, GDateTime *last_activity); diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c index 25fd98b8..9bceb859 100644 --- a/src/xmpp/iq.c +++ b/src/xmpp/iq.c @@ -133,6 +133,7 @@ static void _item_destroy(DiscoItem *item); static gboolean autoping_wait = FALSE; static GTimer *autoping_time = NULL; static GHashTable *id_handlers; +static GHashTable *rooms_cache = NULL; static int _iq_handler(xmpp_conn_t *const conn, xmpp_stanza_t *const stanza, void *const userdata) @@ -236,6 +237,7 @@ iq_handlers_init(void) g_hash_table_destroy(id_handlers); } id_handlers = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL); + rooms_cache = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)xmpp_stanza_release); } void @@ -296,9 +298,25 @@ iq_set_autoping(const int seconds) xmpp_timed_handler_add(conn, _autoping_timed_send, millis, ctx); } +void +iq_rooms_cache_clear(void) +{ + if (rooms_cache) { + g_hash_table_remove_all(rooms_cache); + } +} + void iq_room_list_request(gchar *conferencejid, gchar *filter) { + if (g_hash_table_contains(rooms_cache, conferencejid)) { + log_debug("Rooms request cached for: %s", conferencejid); + _room_list_id_handler(g_hash_table_lookup(rooms_cache, conferencejid), filter); + return; + } + + log_debug("Rooms request not cached for: %s", conferencejid); + xmpp_ctx_t * const ctx = connection_get_ctx(); char *id = create_unique_id("confreq"); xmpp_stanza_t *iq = stanza_create_disco_items_iq(ctx, id, conferencejid); @@ -905,6 +923,10 @@ _room_list_id_handler(xmpp_stanza_t *const stanza, void *const userdata) const char *id = xmpp_stanza_get_id(stanza); const char *from = xmpp_stanza_get_from(stanza); + if (prefs_get_boolean(PREF_ROOM_LIST_CACHE) && !g_hash_table_contains(rooms_cache, from)) { + g_hash_table_insert(rooms_cache, strdup(from), xmpp_stanza_copy(stanza)); + } + log_debug("Response to query: %s", id); xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); @@ -981,7 +1003,9 @@ _room_list_id_handler(xmpp_stanza_t *const stanza, void *const userdata) cons_show(" No rooms found matching filter: %s", filter); } - g_pattern_spec_free(glob); + if (glob) { + g_pattern_spec_free(glob); + } g_free(filter); return 0; diff --git a/src/xmpp/xmpp.h b/src/xmpp/xmpp.h index 9ff1b0c1..d4a29196 100644 --- a/src/xmpp/xmpp.h +++ b/src/xmpp/xmpp.h @@ -161,6 +161,7 @@ gboolean presence_sub_request_exists(const char *const bare_jid); void iq_enable_carbons(void); void iq_disable_carbons(void); void iq_send_software_version(const char *const fulljid); +void iq_rooms_cache_clear(void); void iq_room_list_request(gchar *conferencejid, gchar *filter); void iq_disco_info_request(gchar *jid); void iq_disco_items_request(gchar *jid); diff --git a/tests/unittests/ui/stub_ui.c b/tests/unittests/ui/stub_ui.c index f2d8c5d7..51e8d84a 100644 --- a/tests/unittests/ui/stub_ui.c +++ b/tests/unittests/ui/stub_ui.c @@ -445,6 +445,7 @@ void cons_autoaway_setting(void) {} void cons_reconnect_setting(void) {} void cons_autoping_setting(void) {} void cons_autoconnect_setting(void) {} +void cons_rooms_cache_setting(void) {} void cons_inpblock_setting(void) {} void cons_winpos_setting(void) {} void cons_tray_setting(void) {} diff --git a/tests/unittests/xmpp/stub_xmpp.c b/tests/unittests/xmpp/stub_xmpp.c index e5c3d9ad..45db6649 100644 --- a/tests/unittests/xmpp/stub_xmpp.c +++ b/tests/unittests/xmpp/stub_xmpp.c @@ -204,6 +204,7 @@ void iq_room_role_set(const char * const room, const char * const nick, char *ro void iq_room_role_list(const char * const room, char *role) {} void iq_last_activity_request(gchar *jid) {} void iq_autoping_check(void) {} +void iq_rooms_cache_clear(void) {} // caps functions void caps_add_feature(char *feature) {}