From 973a05d15a9843f2e8f6dff598f2161367885994 Mon Sep 17 00:00:00 2001 From: Paul Fariello Date: Tue, 16 Apr 2019 20:44:39 +0320 Subject: Handle presence received before roster Presence of contact not found in roster are filtered out. But sometimes roster is received after a first few presences. We choose to store presences until we receive roster and then process this presences. Fixes #1050 --- src/event/server_events.c | 1 + src/xmpp/roster_list.c | 43 +++++++++++++++++++++++++++++++++++++++++++ src/xmpp/roster_list.h | 1 + 3 files changed, 45 insertions(+) diff --git a/src/event/server_events.c b/src/event/server_events.c index 36db8ebe..0e84a3e3 100644 --- a/src/event/server_events.c +++ b/src/event/server_events.c @@ -115,6 +115,7 @@ sv_ev_roster_received(void) ui_show_roster(); } + roster_process_pending_presence(); char *account_name = session_get_account_name(); #ifdef HAVE_LIBGPGME diff --git a/src/xmpp/roster_list.c b/src/xmpp/roster_list.c index 5ebdc08f..81a51581 100644 --- a/src/xmpp/roster_list.c +++ b/src/xmpp/roster_list.c @@ -67,7 +67,15 @@ typedef struct prof_roster_t { GHashTable *group_count; } ProfRoster; +typedef struct pending_presence { + char *barejid; + Resource *resource; + GDateTime *last_activity; +} ProfPendingPresence; + static ProfRoster *roster = NULL; +static gboolean roster_received = FALSE; +static GSList *roster_pending_presence = NULL; static gboolean _key_equals(void *key1, void *key2); static gboolean _datetimes_equal(GDateTime *dt1, GDateTime *dt2); @@ -87,6 +95,9 @@ roster_create(void) roster->name_to_barejid = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); roster->groups_ac = autocomplete_new(); roster->group_count = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); + + roster_received = FALSE; + roster_pending_presence = NULL; } void @@ -114,6 +125,18 @@ roster_update_presence(const char *const barejid, Resource *resource, GDateTime assert(barejid != NULL); assert(resource != NULL); + if (!roster_received) { + ProfPendingPresence *presence = malloc(sizeof(ProfPendingPresence)); + presence->barejid = strdup(barejid); + presence->resource = resource; + presence->last_activity = last_activity; + if (last_activity) { + g_date_time_ref(last_activity); + } + roster_pending_presence = g_slist_append(roster_pending_presence, presence); + return FALSE; + } + PContact contact = roster_get_contact(barejid); if (contact == NULL) { return FALSE; @@ -664,3 +687,23 @@ roster_compare_presence(PContact a, PContact b) return roster_compare_name(a, b); } } + +void +roster_process_pending_presence(void) +{ + roster_received = TRUE; + + GSList *iter; + for (iter = roster_pending_presence; iter != NULL; iter = iter->next) { + ProfPendingPresence *presence = iter->data; + roster_update_presence(presence->barejid, presence->resource, presence->last_activity); + free(presence->barejid); + /* seems like resource isn't free on the calling side */ + if (presence->last_activity) { + g_date_time_unref(presence->last_activity); + } + } + + g_slist_free(roster_pending_presence); + roster_pending_presence = NULL; +} diff --git a/src/xmpp/roster_list.h b/src/xmpp/roster_list.h index 5120043c..57a932be 100644 --- a/src/xmpp/roster_list.h +++ b/src/xmpp/roster_list.h @@ -72,5 +72,6 @@ GSList* roster_get_contacts_by_presence(const char *const presence); char* roster_get_msg_display_name(const char *const barejid, const char *const resource); gint roster_compare_name(PContact a, PContact b); gint roster_compare_presence(PContact a, PContact b); +void roster_process_pending_presence(void); #endif -- cgit 1.4.1-2-gfad0 From 6d39f49f57a75deb378eb961ac6cfc2fc3741f4b Mon Sep 17 00:00:00 2001 From: Paul Fariello Date: Wed, 17 Apr 2019 06:40:11 +0320 Subject: Fix server_event unit tests roster_update_presence now requires that roster_process_pending_presence() has been called. Otherwise presence are set to pending and not processed yet. --- tests/unittests/test_server_events.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/unittests/test_server_events.c b/tests/unittests/test_server_events.c index a00eedfd..282c1ffe 100644 --- a/tests/unittests/test_server_events.c +++ b/tests/unittests/test_server_events.c @@ -21,6 +21,7 @@ void console_shows_online_presence_when_set_online(void **state) prefs_set_string(PREF_STATUSES_CONSOLE, "online"); plugins_init(); roster_create(); + roster_process_pending_presence(); char *barejid = "test1@server"; roster_add(barejid, "bob", NULL, "both", FALSE); Resource *resource = resource_new("resource", RESOURCE_ONLINE, NULL, 10); @@ -40,6 +41,7 @@ void console_shows_online_presence_when_set_all(void **state) prefs_set_string(PREF_STATUSES_CONSOLE, "all"); plugins_init(); roster_create(); + roster_process_pending_presence(); char *barejid = "test1@server"; roster_add(barejid, "bob", NULL, "both", FALSE); Resource *resource = resource_new("resource", RESOURCE_ONLINE, NULL, 10); @@ -59,6 +61,7 @@ void console_shows_dnd_presence_when_set_all(void **state) prefs_set_string(PREF_STATUSES_CONSOLE, "all"); plugins_init(); roster_create(); + roster_process_pending_presence(); char *barejid = "test1@server"; roster_add(barejid, "bob", NULL, "both", FALSE); Resource *resource = resource_new("resource", RESOURCE_ONLINE, NULL, 10); @@ -77,6 +80,7 @@ void handle_offline_removes_chat_session(void **state) { plugins_init(); roster_create(); + roster_process_pending_presence(); chat_sessions_init(); char *barejid = "friend@server.chat.com"; char *resource = "home"; @@ -100,6 +104,7 @@ void handle_offline_removes_chat_session(void **state) void lost_connection_clears_chat_sessions(void **state) { roster_create(); + roster_process_pending_presence(); chat_sessions_init(); chat_session_recipient_active("bob@server.org", "laptop", FALSE); chat_session_recipient_active("steve@server.org", "mobile", FALSE); -- cgit 1.4.1-2-gfad0