# HG changeset patch # User Evan Schoenberg # Date 1216592350 0 # Node ID a73d527731ffb7b3cd5451e5805b01ec91fb8f5a # Parent e53a21941d438a6e93db934b5f8ee13f9b0c1de3 To decrease the odds of hitting the rate limit ceiling rapidly on a buddy list with a large number of ICQ buddies, space out our requests for the ICQ Status Note. This has 2 beneficial effects: 1. Request notes over a longer period of time, avoiding hitting the rate limit immediately. 2. Coalesce multiple requests for the same note into a single request. Previously, we were making n*2 to n*4 requests, where n is the number of ICQ contacts with status notes, at signon, as purple_parse_oncoming is called multiple times for each one. diff -r e53a21941d43 -r a73d527731ff libpurple/protocols/oscar/oscar.c --- a/libpurple/protocols/oscar/oscar.c Sun Jul 20 05:53:00 2008 +0000 +++ b/libpurple/protocols/oscar/oscar.c Sun Jul 20 22:19:10 2008 +0000 @@ -1893,6 +1893,39 @@ return 1; } +static gboolean purple_requesticqstatusnote(gpointer data) +{ + PurpleConnection *gc = data; + OscarData *od = gc->proto_data; + char *sn; + struct aim_ssi_item *ssi_item; + aim_tlv_t *note_hash; + + if (!od->statusnotes_queue) { + purple_debug_misc("oscar", "No more ICQ status notes to request"); + od->statusnotes_queue_timer = 0; + return FALSE; + } + + sn = od->statusnotes_queue->data; + + ssi_item = aim_ssi_itemlist_finditem(od->ssi.local, + NULL, sn, AIM_SSI_TYPE_BUDDY); + if (ssi_item != NULL) + { + note_hash = aim_tlv_gettlv(ssi_item->data, 0x015c, 1); + if (note_hash != NULL) { + aim_icq_getstatusnote(od, sn, note_hash->value, note_hash->length); + } + } + + od->statusnotes_queue = g_slist_remove(od->statusnotes_queue, sn); + free(sn); + + return TRUE; +} + + static int purple_parse_oncoming(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) { PurpleConnection *gc; @@ -2074,8 +2107,20 @@ if (ssi_item != NULL) { note_hash = aim_tlv_gettlv(ssi_item->data, 0x015c, 1); - if (note_hash != NULL) - aim_icq_getstatusnote(od, info->sn, note_hash->value, note_hash->length); + if (note_hash != NULL) { + /* We do automatic rate limiting, so a flood of requests would not disconnect us. + * However, they would mean that we had to wait a potentially long time to be able to message + * in real time again. Also, since we're requesting with every purple_parse_oncoming() call, + * which often come in groups, we should coalesce to do a single lookup. + */ + if (!od->statusnotes_queue || (g_slist_find_custom(od->statusnotes_queue, info->sn, (GCompareFunc)strcmp) == NULL)) { + od->statusnotes_queue = g_slist_append(od->statusnotes_queue, g_strdup(info->sn)); + + if (od->statusnotes_queue_timer) + purple_timeout_remove(od->statusnotes_queue_timer); + od->statusnotes_queue_timer = purple_timeout_add_seconds(2, purple_requesticqstatusnote, gc); + } + } } } diff -r e53a21941d43 -r a73d527731ff libpurple/protocols/oscar/oscar.h --- a/libpurple/protocols/oscar/oscar.h Sun Jul 20 05:53:00 2008 +0000 +++ b/libpurple/protocols/oscar/oscar.h Sun Jul 20 22:19:10 2008 +0000 @@ -544,6 +544,10 @@ /** A linked list containing PeerConnections. */ GSList *peer_connections; + + /** Queue of ICQ Status Notes to request. */ + GSList *statusnotes_queue; + gint statusnotes_queue_timer; }; /* Valid for calling aim_icq_setstatus() and for aim_userinfo_t->icqinfo.status */ diff -r e53a21941d43 -r a73d527731ff libpurple/protocols/oscar/oscar_data.c --- a/libpurple/protocols/oscar/oscar_data.c Sun Jul 20 05:53:00 2008 +0000 +++ b/libpurple/protocols/oscar/oscar_data.c Sun Jul 20 22:19:10 2008 +0000 @@ -92,6 +92,14 @@ od->requesticon = g_slist_remove(od->requesticon, sn); g_free(sn); } + while (od->statusnotes_queue) + { + gchar *sn = od->statusnotes_queue->data; + od->statusnotes_queue = g_slist_remove(od->statusnotes_queue, sn); + g_free(sn); + } + if (od->statusnotes_queue_timer) + purple_timeout_remove(od->statusnotes_queue_timer); g_free(od->email); g_free(od->newp); g_free(od->oldp);