summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathon Jongsma <jonathon.jongsma@collabora.co.uk>2009-10-06 22:11:39 -0500
committerJonathon Jongsma <jonathon.jongsma@collabora.co.uk>2009-10-20 22:32:44 -0500
commit431ca31a7a584a32c39be9ad2d2f998f59ef8441 (patch)
tree0c8951d82ecec2b85900ae1f11285de1eaaa88e7
parent191ec53348cd8ca859f42e2a95e9761f7bda1bfc (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.c60
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);
}