changeset 25798:8060be20fa6e

propagate from branch 'im.pidgin.pidgin' (head e1fd1e27a14e8cc717dc7fb6cb69ff1f10672704) to branch 'im.pidgin.cpw.malu.xmpp.idle' (head 2b7644a0be37509450d6d1faf831af6fdcb8c0c2)
author Marcus Lundblad <ml@update.uu.se>
date Tue, 18 Nov 2008 22:35:40 +0000
parents cac2f6203505 (diff) 3d6fe79753c3 (current diff)
children 6986ae0cbb51
files libpurple/protocols/jabber/jabber.c
diffstat 5 files changed, 73 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/jabber/buddy.c	Tue Nov 18 07:32:23 2008 +0000
+++ b/libpurple/protocols/jabber/buddy.c	Tue Nov 18 22:35:40 2008 +0000
@@ -99,32 +99,36 @@
 
 	for(l = jb->resources; l; l = l->next)
 	{
+		JabberBuddyResource *tmp = l->data;
 		if(!jbr && !resource) {
-			jbr = l->data;
+			jbr = tmp;
 		} else if(!resource) {
-			if(((JabberBuddyResource *)l->data)->priority > jbr->priority)
-				jbr = l->data;
-			else if(((JabberBuddyResource *)l->data)->priority == jbr->priority) {
+			if(tmp->priority > jbr->priority)
+				jbr = tmp;
+			else if(tmp->priority == jbr->priority) {
 				/* Determine if this resource is more available than the one we've currently chosen */
-				switch(((JabberBuddyResource *)l->data)->state) {
+				switch(tmp->state) {
 					case JABBER_BUDDY_STATE_ONLINE:
 					case JABBER_BUDDY_STATE_CHAT:
 						/* This resource is online/chatty. Prefer to one which isn't either. */
-						if ((jbr->state != JABBER_BUDDY_STATE_ONLINE) && (jbr->state != JABBER_BUDDY_STATE_CHAT))
-							jbr = l->data;
+						if (((jbr->state != JABBER_BUDDY_STATE_ONLINE) && (jbr->state != JABBER_BUDDY_STATE_CHAT)) ||
+							(jbr->idle && !tmp->idle) || (jbr->idle && tmp->idle && tmp->idle > jbr->idle))
+							jbr = tmp;
 						break;
 					case JABBER_BUDDY_STATE_AWAY:
 					case JABBER_BUDDY_STATE_DND:
 					case JABBER_BUDDY_STATE_UNAVAILABLE:
 						/* This resource is away/dnd/unavailable. Prefer to one which is extended away or unknown. */
-						if ((jbr->state == JABBER_BUDDY_STATE_XA) || 
-							(jbr->state == JABBER_BUDDY_STATE_UNKNOWN) || (jbr->state == JABBER_BUDDY_STATE_ERROR))
-							jbr = l->data;
+						if (((jbr->state == JABBER_BUDDY_STATE_XA) || 
+							(jbr->state == JABBER_BUDDY_STATE_UNKNOWN) || (jbr->state == JABBER_BUDDY_STATE_ERROR)) ||
+							(jbr->idle && !tmp->idle) || (jbr->idle && tmp->idle && tmp->idle > jbr->idle))
+							jbr = tmp;
 						break;
 					case JABBER_BUDDY_STATE_XA:
 						/* This resource is extended away. That's better than unknown. */
-						if ((jbr->state == JABBER_BUDDY_STATE_UNKNOWN) || (jbr->state == JABBER_BUDDY_STATE_ERROR))
-							jbr = l->data;
+						if (((jbr->state == JABBER_BUDDY_STATE_UNKNOWN) || (jbr->state == JABBER_BUDDY_STATE_ERROR)) ||
+							(jbr->idle && !tmp->idle) || (jbr->idle && tmp->idle && tmp->idle > jbr->idle))
+							jbr = tmp;
 						break;
 					case JABBER_BUDDY_STATE_UNKNOWN:
 					case JABBER_BUDDY_STATE_ERROR:
@@ -132,9 +136,9 @@
 						break;
 				}
 			}
-		} else if(((JabberBuddyResource *)l->data)->name) {
-			if(!strcmp(((JabberBuddyResource *)l->data)->name, resource)) {
-				jbr = l->data;
+		} else if(tmp->name) {
+			if(!strcmp(tmp->name, resource)) {
+				jbr = tmp;
 				break;
 			}
 		}
--- a/libpurple/protocols/jabber/buddy.h	Tue Nov 18 07:32:23 2008 +0000
+++ b/libpurple/protocols/jabber/buddy.h	Tue Nov 18 22:35:40 2008 +0000
@@ -69,6 +69,7 @@
 	int priority;
 	JabberBuddyState state;
 	char *status;
+	time_t idle;
 	JabberCapabilities capabilities;
 	char *thread_id;
 	enum {
--- a/libpurple/protocols/jabber/jabber.c	Tue Nov 18 07:32:23 2008 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Tue Nov 18 22:35:40 2008 +0000
@@ -1434,8 +1434,14 @@
 void jabber_idle_set(PurpleConnection *gc, int idle)
 {
 	JabberStream *js = gc->proto_data;
-
+	PurpleAccount *account = purple_connection_get_account(gc);
+	PurpleStatus *status = purple_account_get_active_status(account);
+	
 	js->idle = idle ? time(NULL) - idle : idle;
+	
+	/* send out an updated prescence */
+	purple_debug_info("jabber", "sending updated presence for idle\n");
+	jabber_presence_send(account, status);
 }
 
 void jabber_add_feature(const char *shortname, const char *namespace, JabberFeatureEnabled cb) {
--- a/libpurple/protocols/jabber/jabber.h	Tue Nov 18 07:32:23 2008 +0000
+++ b/libpurple/protocols/jabber/jabber.h	Tue Nov 18 22:35:40 2008 +0000
@@ -153,6 +153,7 @@
 	GList *file_transfers;
 
 	time_t idle;
+	time_t old_idle;
 
 	JabberID *user;
 	PurpleConnection *gc;
--- a/libpurple/protocols/jabber/presence.c	Tue Nov 18 07:32:23 2008 +0000
+++ b/libpurple/protocols/jabber/presence.c	Tue Nov 18 22:35:40 2008 +0000
@@ -151,7 +151,8 @@
 					  (a && !b) || (a && a[0] != '\0' && b && b[0] == '\0') || (a && b && strcmp(a,b)))
 	/* check if there are any differences to the <presence> and send them in that case */
 	if (allowBuzz != js->allowBuzz || js->old_state != state || CHANGED(js->old_msg, stripped) ||
-		js->old_priority != priority || CHANGED(js->old_avatarhash, js->avatar_hash)) {
+		js->old_priority != priority || CHANGED(js->old_avatarhash, js->avatar_hash) ||
+		js->old_idle != js->idle) {
 		js->allowBuzz = allowBuzz;
 
 		presence = jabber_presence_create_js(js, state, stripped, priority);
@@ -178,6 +179,7 @@
 		js->old_avatarhash = g_strdup(js->avatar_hash);
 		js->old_state = state;
 		js->old_priority = priority;
+		js->old_idle = js->idle;
 	}
 	g_free(stripped);
 
@@ -260,6 +262,16 @@
 		g_free(pstr);
 	}
 
+	/* if we are idle and not offline, include idle */
+	if (js->idle && state != JABBER_BUDDY_STATE_UNAVAILABLE) {
+		xmlnode *query = xmlnode_new_child(presence, "query");
+		gchar seconds[10];
+		g_snprintf(seconds, 10, "%d", (int) (time(NULL) - js->idle));
+		
+		xmlnode_set_namespace(query, "jabber:iq:last");
+		xmlnode_set_attrib(query, "seconds", seconds);
+	}
+	
 	/* JEP-0115 */
 	c = xmlnode_new_child(presence, "c");
 	xmlnode_set_namespace(c, "http://jabber.org/protocol/caps");
@@ -427,6 +439,7 @@
 	JabberBuddyResource *jbr = NULL, *found_jbr = NULL;
 	PurpleConvChatBuddyFlags flags = PURPLE_CBFLAGS_NONE;
 	gboolean delayed = FALSE;
+	const gchar *stamp = NULL; /* from <delayed/> element */
 	PurpleBuddy *b = NULL;
 	char *buddy_name;
 	JabberBuddyState state = JABBER_BUDDY_STATE_UNKNOWN;
@@ -434,7 +447,8 @@
 	gboolean muc = FALSE;
 	char *avatar_hash = NULL;
 	xmlnode *caps = NULL;
-
+	int idle = 0;
+	
 	if(!(jb = jabber_buddy_find(js, from, TRUE)))
 		return;
 
@@ -513,6 +527,7 @@
 		} else if(!strcmp(y->name, "delay") && !strcmp(xmlns, "urn:xmpp:delay")) {
 			/* XXX: compare the time.  jabber:x:delay can happen on presence packets that aren't really and truly delayed */
 			delayed = TRUE;
+			stamp = xmlnode_get_attrib(y, "stamp");
 		} else if(!strcmp(y->name, "c") && !strcmp(xmlns, "http://jabber.org/protocol/caps")) {
 			caps = y; /* store for later, when creating buddy resource */
 		} else if(!strcmp(y->name, "x")) {
@@ -520,6 +535,7 @@
 			if(xmlns && !strcmp(xmlns, "jabber:x:delay")) {
 				/* XXX: compare the time.  jabber:x:delay can happen on presence packets that aren't really and truly delayed */
 				delayed = TRUE;
+				stamp = xmlnode_get_attrib(y, "stamp");
 			} else if(xmlns && !strcmp(xmlns, "http://jabber.org/protocol/muc#user")) {
 				xmlnode *z;
 
@@ -570,9 +586,29 @@
 					avatar_hash = xmlnode_get_data(photo);
 				}
 			}
+		} else if (!strcmp(y->name, "query") && 
+			!strcmp(xmlnode_get_namespace(y), "jabber:iq:last")) {
+			/* resource has specified idle */
+			const gchar *seconds = xmlnode_get_attrib(y, "seconds");
+			if (seconds) {
+				/* we may need to take "delayed" into account here */
+				idle = atoi(seconds);
+			}
 		}
 	}
 
+	purple_debug_info("jabber", "got %d seconds idle from presence\n", idle);
+	
+	if (idle && delayed && stamp) {
+		/* if we have a delayed presence, we need to add the delay to the idle
+		 value */
+		time_t offset = time(NULL) - purple_str_to_time(stamp, TRUE, NULL, NULL,
+			NULL);
+		purple_debug_info("jabber", "got delay %s yielding %ld s offset\n",
+			stamp, offset);
+		idle += offset; 
+	}
+	
 
 	if(jid->node && (chat = jabber_chat_find(js, jid->node, jid->domain))) {
 		static int i = 1;
@@ -747,6 +783,12 @@
 		} else {
 			jbr = jabber_buddy_track_resource(jb, jid->resource, priority,
 					state, status);
+			if (idle) {
+				jbr->idle = time(NULL) - idle;
+			} else {
+				jbr->idle = 0;
+			}
+			
 			if(caps) {
 				const char *node = xmlnode_get_attrib(caps,"node");
 				const char *ver = xmlnode_get_attrib(caps,"ver");
@@ -765,6 +807,7 @@
 		if((found_jbr = jabber_buddy_find_resource(jb, NULL))) {
 			jabber_google_presence_incoming(js, buddy_name, found_jbr);
 			purple_prpl_got_user_status(js->gc->account, buddy_name, jabber_buddy_state_get_status_id(found_jbr->state), "priority", found_jbr->priority, "message", found_jbr->status, NULL);
+			purple_prpl_got_user_idle(js->gc->account, buddy_name, found_jbr->idle, found_jbr->idle);
 		} else {
 			purple_prpl_got_user_status(js->gc->account, buddy_name, "offline", status ? "message" : NULL, status, NULL);
 		}