# HG changeset patch # User Marcus Lundblad # Date 1228614167 0 # Node ID f03a067fcfbaa457656932f6df910c7671b8cf36 # Parent 4895879ebafb6da0a840cbeca4e8da6582f59a97# Parent e3bb0bbfa388f5f8283835ce464fe8d288b16ed1 propagate from branch 'im.pidgin.pidgin' (head 196060989ecbfa760153e43530294b78f8999df6) to branch 'im.pidgin.cpw.malu.xmpp.idle' (head bb697289b68b0046f498cf9cb8fa8363622d4f2f) diff -r 4895879ebafb -r f03a067fcfba libpurple/protocols/jabber/buddy.c --- a/libpurple/protocols/jabber/buddy.c Sat Dec 06 20:02:49 2008 +0000 +++ b/libpurple/protocols/jabber/buddy.c Sun Dec 07 01:42:47 2008 +0000 @@ -99,36 +99,41 @@ for(l = jb->resources; l; l = l->next) { - if(!jbr && !resource) { - jbr = l->data; - } else if(!resource) { - if(((JabberBuddyResource *)l->data)->priority > jbr->priority) - jbr = l->data; - else if(((JabberBuddyResource *)l->data)->priority == jbr->priority) { + JabberBuddyResource *tmp = (JabberBuddyResource *) l->data; + if (!jbr && !resource) { + jbr = tmp; + } else if (!resource) { + 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: /* This resource is away/dnd. Prefer to one which is extended away, unavailable, or unknown. */ - if ((jbr->state == JABBER_BUDDY_STATE_XA) || (jbr->state == JABBER_BUDDY_STATE_UNAVAILABLE) || + if (((jbr->state == JABBER_BUDDY_STATE_XA) || (jbr->state == JABBER_BUDDY_STATE_UNAVAILABLE) || (jbr->state == JABBER_BUDDY_STATE_UNKNOWN) || (jbr->state == JABBER_BUDDY_STATE_ERROR)) - jbr = l->data; + || (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 unavailable or unknown. */ if ((jbr->state == JABBER_BUDDY_STATE_UNAVAILABLE) || (jbr->state == JABBER_BUDDY_STATE_UNKNOWN) || (jbr->state == JABBER_BUDDY_STATE_ERROR)) - jbr = l->data; + jbr = tmp; break; case JABBER_BUDDY_STATE_UNAVAILABLE: /* This resource is unavailable. That's better than unknown. */ if ((jbr->state == JABBER_BUDDY_STATE_UNKNOWN) || (jbr->state == JABBER_BUDDY_STATE_ERROR)) - jbr = l->data; + jbr = tmp; break; case JABBER_BUDDY_STATE_UNKNOWN: case JABBER_BUDDY_STATE_ERROR: @@ -136,9 +141,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; } } diff -r 4895879ebafb -r f03a067fcfba libpurple/protocols/jabber/buddy.h --- a/libpurple/protocols/jabber/buddy.h Sat Dec 06 20:02:49 2008 +0000 +++ b/libpurple/protocols/jabber/buddy.h Sun Dec 07 01:42:47 2008 +0000 @@ -69,6 +69,7 @@ int priority; JabberBuddyState state; char *status; + time_t idle; JabberCapabilities capabilities; char *thread_id; enum { diff -r 4895879ebafb -r f03a067fcfba libpurple/protocols/jabber/jabber.c --- a/libpurple/protocols/jabber/jabber.c Sat Dec 06 20:02:49 2008 +0000 +++ b/libpurple/protocols/jabber/jabber.c Sun Dec 07 01:42:47 2008 +0000 @@ -1441,8 +1441,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) { diff -r 4895879ebafb -r f03a067fcfba libpurple/protocols/jabber/jabber.h --- a/libpurple/protocols/jabber/jabber.h Sat Dec 06 20:02:49 2008 +0000 +++ b/libpurple/protocols/jabber/jabber.h Sun Dec 07 01:42:47 2008 +0000 @@ -153,6 +153,7 @@ GList *file_transfers; time_t idle; + time_t old_idle; JabberID *user; PurpleConnection *gc; diff -r 4895879ebafb -r f03a067fcfba libpurple/protocols/jabber/presence.c --- a/libpurple/protocols/jabber/presence.c Sat Dec 06 20:02:49 2008 +0000 +++ b/libpurple/protocols/jabber/presence.c Sun Dec 07 01:42:47 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 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 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(xmlns && !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); }