# HG changeset patch # User Mark Doliner # Date 1139175043 0 # Node ID 442b23efba54db8ae5c40c63119861a11a78ecf5 # Parent a0cdde3b06cff6038493d21cf452f9868ea90827 [gaim-migrate @ 15487] sf patch #1424749, from Evan Schoenberg Fix MSN buddy icon rate-limiting problems committer: Tailor Script diff -r a0cdde3b06cf -r 442b23efba54 src/protocols/msn/session.h --- a/src/protocols/msn/session.h Sun Feb 05 20:06:31 2006 +0000 +++ b/src/protocols/msn/session.h Sun Feb 05 21:30:43 2006 +0000 @@ -28,9 +28,11 @@ #include "sslconn.h" +#include "user.h" +#include "slpcall.h" + #include "notification.h" #include "switchboard.h" -#include "user.h" #include "group.h" #include "cmdproc.h" diff -r a0cdde3b06cf -r 442b23efba54 src/protocols/msn/slp.c --- a/src/protocols/msn/slp.c Sun Feb 05 20:06:31 2006 +0000 +++ b/src/protocols/msn/slp.c Sun Feb 05 21:30:43 2006 +0000 @@ -31,6 +31,9 @@ #include "user.h" #include "switchboard.h" +/* ms to delay between sending buddy icon requests to the server. */ +#define BUDDY_ICON_DELAY 20000 + static void send_ok(MsnSlpCall *slpcall, const char *branch, const char *type, const char *content); @@ -141,7 +144,7 @@ } void -msn_xfer_end_cb(MsnSlpCall *slpcall) +msn_xfer_end_cb(MsnSlpCall *slpcall, MsnSession *session) { if ((gaim_xfer_get_status(slpcall->xfer) != GAIM_XFER_STATUS_DONE) && (gaim_xfer_get_status(slpcall->xfer) != GAIM_XFER_STATUS_CANCEL_REMOTE) && @@ -887,7 +890,7 @@ gaim_debug_info("msn", "Releasing buddy icon request\n"); #endif - while (userlist->buddy_icon_window > 0) + if (userlist->buddy_icon_window > 0) { GQueue *queue; GaimAccount *account; @@ -896,15 +899,15 @@ queue = userlist->buddy_icon_requests; if (g_queue_is_empty(userlist->buddy_icon_requests)) - break; + return; user = g_queue_pop_head(queue); account = userlist->session->account; username = user->passport; + userlist->buddy_icon_window--; msn_request_user_display(user); - userlist->buddy_icon_window--; #ifdef MSN_DEBUG_UD gaim_debug_info("msn", "msn_release_buddy_icon_request(): buddy_icon_window-- yields =%d\n", @@ -913,6 +916,26 @@ } } +/* + * Called on a timeout from end_user_display(). Frees a buddy icon window slow and dequeues the next + * buddy icon request if there is one. + */ +static gboolean +msn_release_buddy_icon_request_timeout(gpointer data) +{ + MsnUserList *userlist = (MsnUserList *)data; + + /* Free one window slot */ + userlist->buddy_icon_window++; + + /* Clear the tag for our former request timer */ + userlist->buddy_icon_request_timer = 0; + + msn_release_buddy_icon_request(userlist); + + return FALSE; +} + void msn_queue_buddy_icon_request(MsnUser *user) { @@ -954,17 +977,12 @@ queue = userlist->buddy_icon_requests; #ifdef MSN_DEBUG_UD - gaim_debug_info("msn", "Queueing buddy icon request: %s\n", - user->passport); + gaim_debug_info("msn", "Queueing buddy icon request for %s (buddy_icon_window = %i)\n", + user->passport, userlist->buddy_icon_window); #endif g_queue_push_tail(queue, user); -#ifdef MSN_DEBUG_UD - gaim_debug_info("msn", "msn_queue_buddy_icon_request(): buddy_icon_window=%d\n", - userlist->buddy_icon_window); -#endif - if (userlist->buddy_icon_window > 0) msn_release_buddy_icon_request(userlist); } @@ -983,7 +1001,7 @@ info = slpcall->data_info; #ifdef MSN_DEBUG_UD - gaim_debug_info("msn", "Got User Display: %s\n", info); + gaim_debug_info("msn", "Got User Display: %s\n", slpcall->slplink->remote_user); #endif userlist = slpcall->slplink->session->userlist; @@ -1014,43 +1032,40 @@ } static void -end_user_display(MsnSlpCall *slpcall) +end_user_display(MsnSlpCall *slpcall, MsnSession *session) { MsnUserList *userlist; - g_return_if_fail(slpcall != NULL); + g_return_if_fail(session != NULL); #ifdef MSN_DEBUG_UD gaim_debug_info("msn", "End User Display\n"); #endif - /* Maybe the slplink was destroyed. */ - if (slpcall->slplink == NULL) { - #ifdef MSN_DEBUG_UD - gaim_debug_info("msn", "end_user_display(): returning because slpcall->slplink is NULL\n"); - #endif - return; - } - - userlist = slpcall->slplink->session->userlist; + userlist = session->userlist; /* If the session is being destroyed we better stop doing anything. */ - if (slpcall->slplink->session->destroying) { - #ifdef MSN_DEBUG_UD - gaim_debug_info("msn", "end_user_display(): returning because slpcall->slplink->session->destroying is TRUE\n"); - #endif + if (session->destroying) return; + + /* Delay before freeing a buddy icon window slot and requesting the next icon, if appropriate. + * If we don't delay, we'll rapidly hit the MSN equivalent of AIM's rate limiting; the server will + * send us an error 800 like so: + * + * C: NS 000: XFR 21 SB + * S: NS 000: 800 21 + */ + if (userlist->buddy_icon_request_timer) { + /* Free the window slot used by this previous request */ + userlist->buddy_icon_window++; + + /* Clear our pending timeout */ + gaim_timeout_remove(userlist->buddy_icon_request_timer); } - /* Free one window slot */ - userlist->buddy_icon_window++; - -#ifdef MSN_DEBUG_UD - gaim_debug_info("msn", "end_user_display(): buddy_icon_window++ yields =%d\n", - userlist->buddy_icon_window); -#endif - - msn_release_buddy_icon_request(userlist); + /* Wait BUDDY_ICON_DELAY ms before freeing our window slot and requesting the next icon. */ + userlist->buddy_icon_request_timer = gaim_timeout_add(BUDDY_ICON_DELAY, + msn_release_buddy_icon_request_timeout, userlist); } void diff -r a0cdde3b06cf -r 442b23efba54 src/protocols/msn/slp.h --- a/src/protocols/msn/slp.h Sun Feb 05 20:06:31 2006 +0000 +++ b/src/protocols/msn/slp.h Sun Feb 05 21:30:43 2006 +0000 @@ -25,7 +25,7 @@ #define _MSN_SLP_H_ #include "slpcall.h" - +#include "session.h" #include "internal.h" #include "ft.h" @@ -41,7 +41,7 @@ const guchar *body, gsize size); void msn_xfer_cancel(GaimXfer *xfer); -void msn_xfer_end_cb(MsnSlpCall *slpcall); +void msn_xfer_end_cb(MsnSlpCall *slpcall, MsnSession *session); void msn_queue_buddy_icon_request(MsnUser *user); diff -r a0cdde3b06cf -r 442b23efba54 src/protocols/msn/slpcall.c --- a/src/protocols/msn/slpcall.c Sun Feb 05 20:06:31 2006 +0000 +++ b/src/protocols/msn/slpcall.c Sun Feb 05 21:30:43 2006 +0000 @@ -77,6 +77,7 @@ msn_slp_call_destroy(MsnSlpCall *slpcall) { GList *e; + MsnSession *session; #ifdef MSN_DEBUG_SLPCALL gaim_debug_info("msn", "slpcall_destroy: slpcall(%p)\n", slpcall); @@ -112,12 +113,13 @@ } } - /* Call the end_cb before removing the slpcall, as the end_cb may need the slplink */ - if (slpcall->end_cb != NULL) - slpcall->end_cb(slpcall); + session = slpcall->slplink->session; msn_slplink_remove_slpcall(slpcall->slplink, slpcall); + if (slpcall->end_cb != NULL) + slpcall->end_cb(slpcall, session); + g_free(slpcall); } diff -r a0cdde3b06cf -r 442b23efba54 src/protocols/msn/slpcall.h --- a/src/protocols/msn/slpcall.h Sun Feb 05 20:06:31 2006 +0000 +++ b/src/protocols/msn/slpcall.h Sun Feb 05 21:30:43 2006 +0000 @@ -28,10 +28,6 @@ typedef struct _MsnSlpCall MsnSlpCall; -typedef void (*MsnSlpCb)(MsnSlpCall *slpcall, - const guchar *data, gsize size); -typedef void (*MsnSlpEndCb)(MsnSlpCall *slpcall); - #include "slplink.h" #include "slpsession.h" @@ -78,7 +74,7 @@ void *xfer; MsnSlpCb cb; - void (*end_cb)(MsnSlpCall *slpcall); + void (*end_cb)(MsnSlpCall *slpcall, MsnSession *session); int timer; }; diff -r a0cdde3b06cf -r 442b23efba54 src/protocols/msn/slplink.h --- a/src/protocols/msn/slplink.h Sun Feb 05 20:06:31 2006 +0000 +++ b/src/protocols/msn/slplink.h Sun Feb 05 21:30:43 2006 +0000 @@ -26,7 +26,6 @@ typedef struct _MsnSlpLink MsnSlpLink; -#include "session.h" #include "directconn.h" #include "slpcall.h" #include "slpmsg.h" @@ -35,6 +34,12 @@ #include "ft.h" +#include "session.h" + +typedef void (*MsnSlpCb)(MsnSlpCall *slpcall, + const guchar *data, gsize size); +typedef void (*MsnSlpEndCb)(MsnSlpCall *slpcall, MsnSession *session); + struct _MsnSlpLink { MsnSession *session; diff -r a0cdde3b06cf -r 442b23efba54 src/protocols/msn/switchboard.c --- a/src/protocols/msn/switchboard.c Sun Feb 05 20:06:31 2006 +0000 +++ b/src/protocols/msn/switchboard.c Sun Feb 05 21:30:43 2006 +0000 @@ -340,7 +340,7 @@ { g_return_if_fail(swboard != NULL); - gaim_debug_info("msg", "Error: Unable to call the user %s\n", passport); + gaim_debug_warning("msg", "Error: Unable to call the user %s for reason %i\n", passport, reason); /* TODO: if current_users > 0, this is probably a chat and an invite failed, * we should report that in the chat or something */ @@ -364,6 +364,8 @@ swboard = trans->data; + gaim_debug_warning("msn", "cal_error_helper: command %s failed for reason %i\n",trans->command,reason); + swboard_error_helper(swboard, reason, passport); g_strfreev(params); @@ -421,6 +423,10 @@ str_reason = _("Message could not be sent " "because a connection error occurred:"); break; + case MSN_SB_ERROR_TOO_FAST: + str_reason = _("Message could not be sent " + "because we are sending too quickly:"); + break; default: str_reason = _("Message could not be sent " "because an error with " @@ -1043,6 +1049,8 @@ static void cal_timeout(MsnCmdProc *cmdproc, MsnTransaction *trans) { + gaim_debug_warning("msn", "cal_timeout: command %s timed out\n", trans->command); + cal_error_helper(trans, MSN_SB_ERROR_UNKNOWN); } @@ -1061,6 +1069,8 @@ reason = MSN_SB_ERROR_USER_OFFLINE; } + gaim_debug_warning("msn", "cal_error: command %s gave error %i\n", trans->command, error); + cal_error_helper(trans, reason); } @@ -1122,9 +1132,14 @@ if (error == 913) reason = MSN_SB_ERROR_OFFLINE; + else if (error == 800) + reason = MSN_SB_ERROR_TOO_FAST; swboard = trans->data; + gaim_debug_info("msn", "xfr_error %i for %s: trans %x, command %s, reason %i\n", + error, swboard->im_user, trans, trans->command, reason); + swboard_error_helper(swboard, reason, swboard->im_user); } diff -r a0cdde3b06cf -r 442b23efba54 src/protocols/msn/switchboard.h --- a/src/protocols/msn/switchboard.h Sun Feb 05 20:06:31 2006 +0000 +++ b/src/protocols/msn/switchboard.h Sun Feb 05 21:30:43 2006 +0000 @@ -45,6 +45,7 @@ MSN_SB_ERROR_OFFLINE, /**< The account is offline. */ MSN_SB_ERROR_USER_OFFLINE, /**< The user to call is offline. */ MSN_SB_ERROR_CONNECTION, /**< There was a connection error. */ + MSN_SB_ERROR_TOO_FAST, /**< We are sending too fast */ MSN_SB_ERROR_UNKNOWN /**< An unknown error occurred. */ } MsnSBErrorType; diff -r a0cdde3b06cf -r 442b23efba54 src/protocols/msn/userlist.c --- a/src/protocols/msn/userlist.c Sun Feb 05 20:06:31 2006 +0000 +++ b/src/protocols/msn/userlist.c Sun Feb 05 21:30:43 2006 +0000 @@ -448,7 +448,11 @@ userlist->session = session; userlist->buddy_icon_requests = g_queue_new(); - userlist->buddy_icon_window = 5; + + /* buddy_icon_window is the number of allowed simultaneous buddy icon requests. + * XXX With smarter rate limiting code, we could allow more at once... 5 was the limit set when + * we weren't retrieiving any more than 5 per MSN session. */ + userlist->buddy_icon_window = 1; return userlist; } @@ -473,6 +477,10 @@ g_list_free(userlist->groups); g_queue_free(userlist->buddy_icon_requests); + + if (userlist->buddy_icon_request_timer) + gaim_timeout_remove(userlist->buddy_icon_request_timer); + g_free(userlist); } diff -r a0cdde3b06cf -r 442b23efba54 src/protocols/msn/userlist.h --- a/src/protocols/msn/userlist.h Sun Feb 05 20:06:31 2006 +0000 +++ b/src/protocols/msn/userlist.h Sun Feb 05 21:30:43 2006 +0000 @@ -58,6 +58,7 @@ GQueue *buddy_icon_requests; int buddy_icon_window; + guint buddy_icon_request_timer; int fl_users_count;