changeset 13125:442b23efba54

[gaim-migrate @ 15487] sf patch #1424749, from Evan Schoenberg Fix MSN buddy icon rate-limiting problems committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Sun, 05 Feb 2006 21:30:43 +0000
parents a0cdde3b06cf
children a36053525b79
files src/protocols/msn/session.h src/protocols/msn/slp.c src/protocols/msn/slp.h src/protocols/msn/slpcall.c src/protocols/msn/slpcall.h src/protocols/msn/slplink.h src/protocols/msn/switchboard.c src/protocols/msn/switchboard.h src/protocols/msn/userlist.c src/protocols/msn/userlist.h
diffstat 10 files changed, 95 insertions(+), 50 deletions(-) [+]
line wrap: on
line diff
--- 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"
--- 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
--- 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);
 
--- 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);
 }
 
--- 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;
 };
--- 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;
--- 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);
 }
 
--- 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;
--- 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);
 }
 
--- 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;