diff options
author | Jonathon Jongsma <jonathon.jongsma@collabora.co.uk> | 2009-10-06 22:11:39 -0500 |
---|---|---|
committer | Jonathon Jongsma <jonathon.jongsma@collabora.co.uk> | 2009-10-20 22:32:44 -0500 |
commit | 431ca31a7a584a32c39be9ad2d2f998f59ef8441 (patch) | |
tree | 0c8951d82ecec2b85900ae1f11285de1eaaa88e7 | |
parent | 191ec53348cd8ca859f42e2a95e9761f7bda1bfc (diff) |
Attempt to work around the WHO vs WHOIS presence issue
Only WHOIS returns the status message, so this commit is a hack to attempt to
prevent WHO responses from overwriting a more-specific status update with a less
specific one (with no status message). In essence, we cache the last presence
status for a contact, and when we get a new status for that contact, we use the
following algorithm:
- check to see if the presences are equal
- if they are not equal, use the new presence
- if they are equal, check whether the cached data has more information
- if so, re-use the cached presence data
- if not, use the new presence
It's not perfect, but it doesn't seem too bad in practice.
-rw-r--r-- | src/idle-contact-manager.c | 60 |
1 files changed, 44 insertions, 16 deletions
diff --git a/src/idle-contact-manager.c b/src/idle-contact-manager.c index 864adec..4f44855 100644 --- a/src/idle-contact-manager.c +++ b/src/idle-contact-manager.c @@ -39,18 +39,26 @@ enum { }; typedef struct { - IdlePresenceStatus presence; + TpPresenceStatus *presence; GTimeVal update_time; } ContactPresenceUpdate; -ContactPresenceUpdate* _contact_presence_update_new(IdlePresenceStatus status) +/* takes ownership of presence */ +ContactPresenceUpdate* _contact_presence_update_new(IdlePresenceStatus status, GHashTable *params) { - ContactPresenceUpdate* pres_update = g_new(ContactPresenceUpdate, 1); - pres_update->presence = status; + ContactPresenceUpdate* pres_update = g_slice_new(ContactPresenceUpdate); + pres_update->presence = tp_presence_status_new (status, params); g_get_current_time(&pres_update->update_time); return pres_update; } +static void +_contact_presence_update_free (ContactPresenceUpdate *update) +{ + tp_presence_status_free (update->presence); + g_slice_free (ContactPresenceUpdate, update); +} + typedef struct _IdleContactManagerPrivate IdleContactManagerPrivate; struct _IdleContactManagerPrivate { @@ -83,12 +91,11 @@ idle_contact_manager_init(IdleContactManager* obj) priv->pending_presence_updates = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, - (GDestroyNotify) - tp_presence_status_free); + (GDestroyNotify) tp_presence_status_free); priv->cached_presences = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, - (GDestroyNotify) g_free); + (GDestroyNotify) _contact_presence_update_free); priv->presence = IDLE_PRESENCE_OFFLINE; } @@ -272,9 +279,9 @@ idle_contact_manager_get_statuses(IdleContactManager *self, ContactPresenceUpdate *cached_presence = g_hash_table_lookup (priv->cached_presences, GUINT_TO_POINTER(handle)); - /* return our cached status if we have one, else assume - * available */ - ps->index = cached_presence ? cached_presence->presence : IDLE_PRESENCE_AVAILABLE; + /* return our cached status if we have one, else assume the contact is + * available for now and query the actual status */ + ps->index = cached_presence ? cached_presence->presence->index : IDLE_PRESENCE_AVAILABLE; GTimeVal cur_time; g_get_current_time(&cur_time); @@ -452,7 +459,6 @@ static void update_contact_presence(IdleContactManager* mgr, TpHandle contact, IdlePresenceStatus presence, const char* message) { IdleContactManagerPrivate *priv = IDLE_CONTACT_MANAGER_GET_PRIVATE(mgr); GHashTable *params = NULL; - TpPresenceStatus *pres_status; if (message != NULL) { GValue *message_val; @@ -466,15 +472,37 @@ update_contact_presence(IdleContactManager* mgr, TpHandle contact, IdlePresenceS g_hash_table_insert (params, "message", message_val); } - pres_status = tp_presence_status_new (presence, params); + /* IRC presence is a messy business. Depending on which command you use to + * query the presence (WHO vs WHOIS, etc), you might get the status message + * or you might not. Because of this, we want to avoid overwriting a status + * message if one exists + */ + ContactPresenceUpdate* cached_update = + g_hash_table_lookup(priv->cached_presences, GUINT_TO_POINTER (contact)); + + IDLE_DEBUG ("cached presence update: %p (%i, %p)", cached_update, cached_update ? cached_update->presence->index : 255, + cached_update ? cached_update->presence->optional_arguments : NULL); + IDLE_DEBUG ("params: %p", params); + + if (cached_update && (cached_update->presence->index == presence) + && (cached_update->presence->optional_arguments != NULL) && (params == NULL)) { + /* simply update the cached update's time */ + IDLE_DEBUG ("Updating current time on the cached update"); + g_get_current_time(&cached_update->update_time); + } else { + /* pending presence updates will be signalled when we get the ENDOFWHO + * message */ + g_hash_table_insert(priv->pending_presence_updates, GUINT_TO_POINTER(contact), + tp_presence_status_new (presence, params)); + + IDLE_DEBUG ("Inserting a new update into cached_presences"); + g_hash_table_insert(priv->cached_presences, GUINT_TO_POINTER(contact), + _contact_presence_update_new(presence, params)); + } if (params) g_hash_table_destroy (params); - g_hash_table_insert(priv->pending_presence_updates, GUINT_TO_POINTER(contact), pres_status); - g_hash_table_insert(priv->cached_presences, GUINT_TO_POINTER(contact), - _contact_presence_update_new(presence)); - _ensure_cache_limit(mgr); } |