From 321ff571505355c07cd8a57a39bef22d9d95f64c Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Wed, 18 Mar 2026 20:05:04 +0100 Subject: [PATCH] feat(omemo): suppress repetitive missing device ID warnings When sending OMEMO messages, we print a warning message for every participant without a device ID on every single send: ``` Can't find a OMEMO device id for my@jid.org ``` This clutters the UI due to the high volume of repetitive information. This is solved by tracking suppressed warnings within the window structure. A warning for a specific JID and type is only shown once per window context. Suppression state is stored in the base ProfWin structure and managed via helper functions (win_warn_needed, win_warn_sent). The state is lazily initialized to save resources and automatically cleaned up when the window is closed. Warnings are explicitly reset when an OMEMO session is started or ended to ensure users see fresh alerts when toggling encryption. --- src/command/cmd_funcs.c | 5 +++++ src/omemo/omemo.c | 7 +++++- src/ui/win_types.h | 1 + src/ui/window.c | 42 ++++++++++++++++++++++++++++++++++++ src/ui/window.h | 4 ++++ tests/unittests/ui/stub_ui.c | 16 ++++++++++++++ 6 files changed, 74 insertions(+), 1 deletion(-) diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index 107b1caf..05d03227 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -57,6 +57,7 @@ #include "plugins/plugins.h" #include "ui/inputwin.h" #include "ui/ui.h" +#include "ui/window.h" #include "ui/window_list.h" #include "xmpp/avatar.h" #include "xmpp/chat_session.h" @@ -8456,6 +8457,7 @@ cmd_omemo_start(ProfWin* window, const char* const command, gchar** args) win_println((ProfWin*)chatwin, THEME_DEFAULT, "!", "Initiating OMEMO session with %s...", chatwin->barejid); omemo_start_session(chatwin->barejid); chatwin->is_omemo = TRUE; + win_clear_warned_jids((ProfWin*)chatwin); } else if (window->type == WIN_MUC) { ProfMucWin* mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); @@ -8471,6 +8473,7 @@ cmd_omemo_start(ProfWin* window, const char* const command, gchar** args) win_println((ProfWin*)mucwin, THEME_DEFAULT, "!", "Initiating OMEMO session in %s...", mucwin->roomjid); omemo_start_muc_sessions(mucwin->roomjid); mucwin->is_omemo = TRUE; + win_clear_warned_jids((ProfWin*)mucwin); } else { win_println(window, THEME_DEFAULT, "!", "MUC must be non-anonymous (i.e. be configured to present real jid to anyone) and members-only in order to support OMEMO."); } @@ -8589,6 +8592,7 @@ cmd_omemo_end(ProfWin* window, const char* const command, gchar** args) chatwin->is_omemo = FALSE; accounts_add_omemo_state(session_get_account_name(), chatwin->barejid, FALSE); + win_clear_warned_jids((ProfWin*)chatwin); } else if (window->type == WIN_MUC) { ProfMucWin* mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); @@ -8600,6 +8604,7 @@ cmd_omemo_end(ProfWin* window, const char* const command, gchar** args) mucwin->is_omemo = FALSE; accounts_add_omemo_state(session_get_account_name(), mucwin->roomjid, FALSE); + win_clear_warned_jids((ProfWin*)mucwin); } else { win_println(window, THEME_DEFAULT, "-", "You must be in a regular chat window to start an OMEMO session."); return TRUE; diff --git a/src/omemo/omemo.c b/src/omemo/omemo.c index bfd984a3..54dba460 100644 --- a/src/omemo/omemo.c +++ b/src/omemo/omemo.c @@ -30,6 +30,7 @@ #include "omemo/omemo.h" #include "omemo/store.h" #include "ui/ui.h" +#include "ui/window.h" #include "ui/window_list.h" #include "xmpp/connection.h" #include "xmpp/muc.h" @@ -822,7 +823,11 @@ omemo_on_message_send(ProfWin* win, const char* const message, gboolean request_ recipient_device_id = g_hash_table_lookup(omemo_ctx.device_list, recipients_iter->data); if (!recipient_device_id) { log_warning("[OMEMO][SEND] cannot find device ids for %s", recipients_iter->data); - win_println(win, THEME_ERROR, "!", "Can't find a OMEMO device id for %s.\n", recipients_iter->data); + + if (win_warn_needed(win, "omemo_no_device", recipients_iter->data)) { + win_println(win, THEME_ERROR, "!", "Can't find a OMEMO device id for %s.", recipients_iter->data); + win_warn_sent(win, "omemo_no_device", recipients_iter->data); + } continue; } diff --git a/src/ui/win_types.h b/src/ui/win_types.h index 2f83eb60..dddab862 100644 --- a/src/ui/win_types.h +++ b/src/ui/win_types.h @@ -133,6 +133,7 @@ typedef struct prof_win_t ProfLayout* layout; Autocomplete urls_ac; Autocomplete quotes_ac; + GHashTable* warned_jids; } ProfWin; typedef struct prof_console_win_t diff --git a/src/ui/window.c b/src/ui/window.c index 178a2c0b..a2fc10ea 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -557,6 +557,10 @@ win_free(ProfWin* window) } free(window->layout); + if (window->warned_jids) { + g_hash_table_destroy(window->warned_jids); + } + switch (window->type) { case WIN_CHAT: { @@ -609,6 +613,44 @@ win_free(ProfWin* window) free(window); } +gboolean +win_warn_needed(ProfWin* window, const char* const type, const char* const jid) +{ + if (!window || !type || !jid) { + return TRUE; + } + + if (!window->warned_jids) { + return TRUE; + } + + auto_gchar gchar* key = g_strdup_printf("%s:%s", type, jid); + return !g_hash_table_contains(window->warned_jids, key); +} + +void +win_warn_sent(ProfWin* window, const char* const type, const char* const jid) +{ + if (!window || !type || !jid) { + return; + } + + if (!window->warned_jids) { + window->warned_jids = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); + } + + gchar* key = g_strdup_printf("%s:%s", type, jid); + g_hash_table_insert(window->warned_jids, key, GINT_TO_POINTER(1)); +} + +void +win_clear_warned_jids(ProfWin* window) +{ + if (window && window->warned_jids) { + g_hash_table_remove_all(window->warned_jids); + } +} + void win_page_up(ProfWin* window, int scroll_size) { diff --git a/src/ui/window.h b/src/ui/window.h index 026392ee..08e3e8e3 100644 --- a/src/ui/window.h +++ b/src/ui/window.h @@ -59,6 +59,10 @@ void win_update_entry_message(ProfWin* window, const char* const id, const char* gboolean win_has_active_subwin(ProfWin* window); +gboolean win_warn_needed(ProfWin* window, const char* const type, const char* const jid); +void win_warn_sent(ProfWin* window, const char* const type, const char* const jid); +void win_clear_warned_jids(ProfWin* window); + void win_page_up(ProfWin* window, int scroll_size); void win_page_down(ProfWin* window, int scroll_size); void win_sub_page_down(ProfWin* window); diff --git a/tests/unittests/ui/stub_ui.c b/tests/unittests/ui/stub_ui.c index 4beb6200..2d0a200a 100644 --- a/tests/unittests/ui/stub_ui.c +++ b/tests/unittests/ui/stub_ui.c @@ -1318,6 +1318,22 @@ win_refresh_with_subwin(ProfWin* window) { } +gboolean +win_warn_needed(ProfWin* window, const char* const type, const char* const jid) +{ + return TRUE; +} + +void +win_warn_sent(ProfWin* window, const char* const type, const char* const jid) +{ +} + +void +win_clear_warned_jids(ProfWin* window) +{ +} + void win_println(ProfWin* window, theme_item_t theme, const char* ch, const char* const message, ...) {