diff libpurple/protocols/msn/user.c @ 31292:47b6eda87723

propagate from branch 'im.pidgin.pidgin' (head 07d0765c444a097af45c2650f54323afb900a07b) to branch 'im.pidgin.soc.2010.msn-tlc' (head f3998422a4724ab424e4e2328f58fc0504856557)
author masca@cpw.pidgin.im
date Mon, 19 Jul 2010 21:11:32 +0000
parents 56ef12440d52
children 4445ae4215b8
line wrap: on
line diff
--- a/libpurple/protocols/msn/user.c	Mon Jul 19 18:25:47 2010 +0000
+++ b/libpurple/protocols/msn/user.c	Mon Jul 19 21:11:32 2010 +0000
@@ -21,10 +21,21 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
-#include "msn.h"
+
+#include "internal.h"
+#include "debug.h"
+#include "util.h"
+
 #include "user.h"
 #include "slp.h"
 
+static void free_user_endpoint(MsnUserEndpoint *data)
+{
+	g_free(data->id);
+	g_free(data->name);
+	g_free(data);
+}
+
 /*new a user object*/
 MsnUser *
 msn_user_new(MsnUserList *userlist, const char *passport,
@@ -39,15 +50,25 @@
 	msn_user_set_passport(user, passport);
 	msn_user_set_friendly_name(user, friendly_name);
 
-	return user;
+	return msn_user_ref(user);
 }
 
 /*destroy a user object*/
-void
+static void
 msn_user_destroy(MsnUser *user)
 {
 	g_return_if_fail(user != NULL);
 
+	if (user->refcount > 1) {
+		msn_user_unref(user);
+		return;
+	}
+
+	while (user->endpoints != NULL) {
+		free_user_endpoint(user->endpoints->data);
+		user->endpoints = g_slist_delete_link(user->endpoints, user->endpoints);
+	}
+
 	if (user->clientcaps != NULL)
 		g_hash_table_destroy(user->clientcaps);
 
@@ -82,6 +103,27 @@
 	g_free(user);
 }
 
+MsnUser *
+msn_user_ref(MsnUser *user)
+{
+	g_return_val_if_fail(user != NULL, NULL);
+
+	user->refcount++;
+
+	return user;
+}
+
+void
+msn_user_unref(MsnUser *user)
+{
+	g_return_if_fail(user != NULL);
+
+	user->refcount--;
+
+	if(user->refcount == 0)
+		msn_user_destroy(user);
+}
+
 void
 msn_user_update(MsnUser *user)
 {
@@ -186,6 +228,9 @@
 {
 	g_return_val_if_fail(user != NULL, FALSE);
 
+	if (user == user->userlist->session->user)
+		return FALSE;
+
 	if (user->friendly_name && name && (!strcmp(user->friendly_name, name) ||
 				!strcmp(user->passport, name)))
 		return FALSE;
@@ -217,6 +262,47 @@
 }
 
 void
+msn_user_set_endpoint_data(MsnUser *user, const char *input, MsnUserEndpoint *newep)
+{
+	MsnUserEndpoint *ep;
+	char *endpoint;
+	GSList *l;
+
+	g_return_if_fail(user != NULL);
+	g_return_if_fail(input != NULL);
+
+	endpoint = g_ascii_strdown(input, -1);
+
+	for (l = user->endpoints; l; l = l->next) {
+		ep = l->data;
+		if (g_str_equal(ep->id, endpoint)) {
+			/* We have info about this endpoint! */
+
+			g_free(endpoint);
+
+			if (newep == NULL) {
+				/* Delete it and exit */
+				user->endpoints = g_slist_delete_link(user->endpoints, l);
+				free_user_endpoint(ep);
+				return;
+			}
+
+			/* Break out of our loop and update it */
+			break;
+		}
+	}
+	if (l == NULL) {
+		/* Need to add a new endpoint */
+		ep = g_new0(MsnUserEndpoint, 1);
+		ep->id = endpoint;
+		user->endpoints = g_slist_prepend(user->endpoints, ep);
+	}
+
+	ep->clientid = newep->clientid;
+	ep->extcaps = newep->extcaps;
+}
+
+void
 msn_user_set_op(MsnUser *user, MsnListOp list_op)
 {
 	g_return_if_fail(user != NULL);
@@ -406,6 +492,14 @@
 }
 
 void
+msn_user_set_extcaps(MsnUser *user, guint extcaps)
+{
+	g_return_if_fail(user != NULL);
+
+	user->extcaps = extcaps;
+}
+
+void
 msn_user_set_network(MsnUser *user, MsnNetwork network)
 {
 	g_return_if_fail(user != NULL);
@@ -413,6 +507,71 @@
 	user->networkid = network;
 }
 
+static gboolean
+buddy_icon_cached(PurpleConnection *gc, MsnObject *obj)
+{
+	PurpleAccount *account;
+	PurpleBuddy *buddy;
+	const char *old;
+	const char *new;
+
+	g_return_val_if_fail(obj != NULL, FALSE);
+
+	account = purple_connection_get_account(gc);
+
+	buddy = purple_find_buddy(account, msn_object_get_creator(obj));
+	if (buddy == NULL)
+		return FALSE;
+
+	old = purple_buddy_icons_get_checksum_for_user(buddy);
+	new = msn_object_get_sha1(obj);
+
+	if (new == NULL)
+		return FALSE;
+
+	/* If the old and new checksums are the same, and the file actually exists,
+	 * then return TRUE */
+	if (old != NULL && !strcmp(old, new))
+		return TRUE;
+
+	return FALSE;
+}
+
+static void
+queue_buddy_icon_request(MsnUser *user)
+{
+	PurpleAccount *account;
+	MsnObject *obj;
+	GQueue *queue;
+
+	g_return_if_fail(user != NULL);
+
+	account = user->userlist->session->account;
+
+	obj = msn_user_get_object(user);
+
+	if (obj == NULL) {
+		purple_buddy_icons_set_for_user(account, user->passport, NULL, 0, NULL);
+		return;
+	}
+
+	if (!buddy_icon_cached(account->gc, obj)) {
+		MsnUserList *userlist;
+
+		userlist = user->userlist;
+		queue = userlist->buddy_icon_requests;
+
+		if (purple_debug_is_verbose())
+			purple_debug_info("msn", "Queueing buddy icon request for %s (buddy_icon_window = %i)\n",
+			                  user->passport, userlist->buddy_icon_window);
+
+		g_queue_push_tail(queue, user);
+
+		if (userlist->buddy_icon_window > 0)
+			msn_release_buddy_icon_request(userlist);
+	}
+}
+
 void
 msn_user_set_object(MsnUser *user, MsnObject *obj)
 {
@@ -423,8 +582,8 @@
 
 	user->msnobj = obj;
 
-	if (user->list_op & MSN_LIST_FL_OP)
-		msn_queue_buddy_icon_request(user);
+	if (user != user->userlist->session->user && user->list_op & MSN_LIST_FL_OP)
+		queue_buddy_icon_request(user);
 }
 
 void
@@ -496,6 +655,39 @@
 	return user->clientid;
 }
 
+guint
+msn_user_get_extcaps(const MsnUser *user)
+{
+	g_return_val_if_fail(user != NULL, 0);
+
+	return user->extcaps;
+}
+
+MsnUserEndpoint *
+msn_user_get_endpoint_data(MsnUser *user, const char *input)
+{
+	char *endpoint;
+	GSList *l;
+	MsnUserEndpoint *ep;
+
+	g_return_val_if_fail(user != NULL, NULL);
+	g_return_val_if_fail(input != NULL, NULL);
+
+	endpoint = g_ascii_strdown(input, -1);
+
+	for (l = user->endpoints; l; l = l->next) {
+		ep = l->data;
+		if (g_str_equal(ep->id, endpoint)) {
+			g_free(endpoint);
+			return ep;
+		}
+	}
+
+	g_free(endpoint);
+
+	return NULL;
+}
+
 MsnObject *
 msn_user_get_object(const MsnUser *user)
 {
@@ -520,3 +712,54 @@
 	return user->invite_message;
 }
 
+gboolean
+msn_user_is_capable(MsnUser *user, char *endpoint, guint capability, guint extcap)
+{
+	g_return_val_if_fail(user != NULL, FALSE);
+
+	if (endpoint != NULL) {
+		MsnUserEndpoint *ep = msn_user_get_endpoint_data(user, endpoint);
+		if (ep != NULL)
+			return (ep->clientid & capability) && (ep->extcaps & extcap);
+		else
+			return FALSE;
+	}
+
+	return (user->clientid & capability) && (user->extcaps & extcap);
+}
+
+/**************************************************************************
+ * Utility functions
+ **************************************************************************/
+
+int
+msn_user_passport_cmp(MsnUser *user, const char *passport)
+{
+	const char *pass;
+
+	pass = msn_user_get_passport(user);
+
+	return strcmp(pass, purple_normalize_nocase(NULL, passport));
+}
+
+gboolean
+msn_user_is_in_group(MsnUser *user, const char * group_id)
+{
+	if (user == NULL)
+		return FALSE;
+
+	if (group_id == NULL)
+		return FALSE;
+
+	return (g_list_find_custom(user->group_ids, group_id, (GCompareFunc)strcmp)) != NULL;
+}
+
+gboolean
+msn_user_is_in_list(MsnUser *user, MsnListId list_id)
+{
+	if (user == NULL)
+		return FALSE;
+
+	return (user->list_op & (1 << list_id));
+}
+