[telepathy-gabble/telepathy-gabble-0.8] Bug #23684: Automatically request a vCard after the server replied with the error resource-constraint
Alban Crequy
alban.crequy at collabora.co.uk
Thu Sep 24 08:57:58 PDT 2009
---
src/vcard-manager.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 64 insertions(+), 4 deletions(-)
diff --git a/src/vcard-manager.c b/src/vcard-manager.c
index 9b3b96d..1b9f145 100644
--- a/src/vcard-manager.c
+++ b/src/vcard-manager.c
@@ -40,6 +40,11 @@
#define DEFAULT_REQUEST_TIMEOUT 180
#define VCARD_CACHE_ENTRY_TTL 60
+/* When the server reply with XMPP_ERROR_RESOURCE_CONSTRAINT, wait
+ * REQUEST_WAIT_DELAY seconds before allowing a vCard request to be sent to
+ * the same recipient */
+#define REQUEST_WAIT_DELAY (5 * 60)
+
static const gchar *NO_ALIAS = "none";
/* signal enum */
@@ -146,6 +151,12 @@ struct _GabbleVCardCacheEntry
/* List of (GabbleVCardManagerRequest *) borrowed from priv->requests */
GSList *pending_requests;
+ /* When requests for this entry receive an error of type "wait", we suspend
+ * further requests and retry again after REQUEST_WAIT_DELAY seconds.
+ * 0 if not suspended.
+ */
+ guint suspended_timer_id;
+
/* VCard node for this entry (owned reference), or NULL if there's no node */
LmMessageNode *vcard_node;
@@ -175,6 +186,8 @@ static void cache_entry_free (void *data);
static gint cache_entry_compare (gconstpointer a, gconstpointer b);
static void manager_patch_vcard (
GabbleVCardManager *self, LmMessageNode *vcard_node);
+static void cache_entry_ensure_queued (GabbleVCardManagerRequest *request,
+ guint timeout);
static void
gabble_vcard_manager_init (GabbleVCardManager *obj)
@@ -403,6 +416,13 @@ cache_entry_attempt_to_free (GabbleVCardCacheEntry *entry)
return;
}
+ if (entry->suspended_timer_id != 0)
+ {
+ DEBUG ("Not freeing vCard cache entry %p: it has suspended requests",
+ entry);
+ return;
+ }
+
if (entry->handle == base->self_handle)
{
/* if we do have some pending edits, we should also have
@@ -1024,6 +1044,20 @@ manager_patch_vcard (GabbleVCardManager *self,
}
}
+static gboolean
+suspended_request_timeout_cb (gpointer data)
+{
+ GabbleVCardManagerRequest *request = data;
+
+ /* Send the request again */
+ g_assert (request->timer_id == 0);
+ request->timer_id =
+ g_timeout_add_seconds (request->timeout, timeout_request, request);
+ cache_entry_ensure_queued (request, request->timeout);
+
+ return FALSE;
+}
+
/* Called when a GET request in the pipeline has either succeeded or failed. */
static void
pipeline_reply_cb (GabbleConnection *conn,
@@ -1031,7 +1065,8 @@ pipeline_reply_cb (GabbleConnection *conn,
gpointer user_data,
GError *error)
{
- GabbleVCardCacheEntry *entry = user_data;
+ GabbleVCardManagerRequest *request = user_data;
+ GabbleVCardCacheEntry *entry = request->entry;
GabbleVCardManager *self = GABBLE_VCARD_MANAGER (entry->manager);
GabbleVCardManagerPrivate *priv = self->priv;
TpBaseConnection *base = (TpBaseConnection *) conn;
@@ -1044,11 +1079,31 @@ pipeline_reply_cb (GabbleConnection *conn,
g_assert (tp_handle_is_valid (contact_repo, entry->handle, NULL));
g_assert (entry->pipeline_item != NULL);
+ g_assert (entry->suspended_timer_id == 0);
entry->pipeline_item = NULL;
if (error)
{
+ /* First, handle the error "wait": suspend the request and replay it
+ * later */
+ LmMessageNode *error_node = NULL;
+ GabbleXmppErrorType error_type;
+
+ if (reply_msg != NULL)
+ {
+ error_node = lm_message_node_get_child (reply_msg->node, "error");
+ }
+
+ if (error_node != NULL &&
+ gabble_xmpp_error_from_node (error_node, &error_type) ==
+ XMPP_ERROR_RESOURCE_CONSTRAINT && error_type == XMPP_ERROR_TYPE_WAIT)
+ {
+ entry->suspended_timer_id = g_timeout_add_seconds (
+ REQUEST_WAIT_DELAY, suspended_request_timeout_cb, request);
+ return;
+ }
+
/* If request for our own vCard failed, and we do have
* pending edits to make, cancel those and return error
* to the user */
@@ -1120,8 +1175,9 @@ notify_delete_request (gpointer data, GObject *obj)
}
static void
-cache_entry_ensure_queued (GabbleVCardCacheEntry *entry, guint timeout)
+cache_entry_ensure_queued (GabbleVCardManagerRequest *request, guint timeout)
{
+ GabbleVCardCacheEntry *entry = request->entry;
GabbleConnection *conn = entry->manager->priv->connection;
TpBaseConnection *base = (TpBaseConnection *) conn;
TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base,
@@ -1131,6 +1187,10 @@ cache_entry_ensure_queued (GabbleVCardCacheEntry *entry, guint timeout)
{
DEBUG ("adding to cache entry %p with <iq> already pending", entry);
}
+ else if (entry->suspended_timer_id != 0)
+ {
+ DEBUG ("adding to cache entry %p with <iq> suspended", entry);
+ }
else
{
const char *jid;
@@ -1155,7 +1215,7 @@ cache_entry_ensure_queued (GabbleVCardCacheEntry *entry, guint timeout)
NULL);
entry->pipeline_item = gabble_request_pipeline_enqueue (
- conn->req_pipeline, msg, timeout, pipeline_reply_cb, entry);
+ conn->req_pipeline, msg, timeout, pipeline_reply_cb, request);
lm_message_unref (msg);
@@ -1207,7 +1267,7 @@ gabble_vcard_manager_request (GabbleVCardManager *self,
request->timer_id =
g_timeout_add_seconds (timeout, timeout_request, request);
- cache_entry_ensure_queued (request->entry, timeout);
+ cache_entry_ensure_queued (request, timeout);
return request;
}
--
1.5.6.5
More information about the telepathy-commits
mailing list