/* * Copyright 2006-2010 Daniel Henninger. All rights reserved. * * This software is published under the terms of the GNU Public License (GPL), * a copy of which is included in this distribution. */ package net.sf.kraken.protocols.xmpp; import net.sf.kraken.avatars.Avatar; import net.sf.kraken.type.NameSpace; import org.apache.log4j.Logger; import org.jivesoftware.smack.PacketListener; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.packet.DefaultPacketExtension; import org.jivesoftware.smack.packet.Packet; import org.jivesoftware.smack.packet.PacketExtension; import org.jivesoftware.smackx.packet.VCard; import org.jivesoftware.util.JiveGlobals; import org.jivesoftware.util.NotFoundException; import org.xmpp.packet.Presence; /** * Presence packets are used for two purposes. First, to notify the server of * our the clients current presence status. Second, they are used to subscribe * and unsubscribe users from the roster. * * Instances of XMPPSubscriptionHandler * are responsible for handling events generated by receiving * both types of presence stanzas from the legacy domain. * * @author Guus der Kinderen, guus.der.kinderen@gmail.com */ public class XMPPPresenceHandler implements PacketListener{ final static Logger Log = Logger.getLogger(XMPPPresenceHandler.class); private final XMPPSession session; /** * Instantiates a new Presence handler for the given session. * * @param session * The session for which to handle presence stanzas. */ public XMPPPresenceHandler(XMPPSession session) { if (session == null) { throw new IllegalArgumentException( "Argument 'session' cannot be null."); } this.session = session; } /* (non-Javadoc) * @see org.jivesoftware.smack.PacketListener#processPacket(org.jivesoftware.smack.packet.Packet) */ public void processPacket(Packet packet) { if (!(packet instanceof org.jivesoftware.smack.packet.Presence)) { throw new IllegalArgumentException(getClass().getName() + " can only be used to handle presence packets. " + "Please modify the caller code accordingly " + "(use a appropriate PacketFilter)."); } final org.jivesoftware.smack.packet.Presence presence = (org.jivesoftware.smack.packet.Presence) packet; final org.jivesoftware.smack.packet.Presence.Type type = presence.getType(); if (type.equals(org.jivesoftware.smack.packet.Presence.Type.available) || type.equals(org.jivesoftware.smack.packet.Presence.Type.unavailable)) { handlePresenceMode(presence); } else { handlePresenceSubscription(presence); } } /** * Handles incoming presence stanzas that relate to presence status / mode * changes. Ignores others. * * @param presence * the stanza */ private void handlePresenceMode( final org.jivesoftware.smack.packet.Presence presence) { if (!session.getBuddyManager().isActivated()) { session.getBuddyManager().storePendingStatus(session.getTransport().convertIDToJID(presence.getFrom()), ((XMPPTransport)session.getTransport()).convertXMPPStatusToGateway(presence.getType(), presence.getMode()), presence.getStatus()); } else { // TODO: Need to handle resources and priorities! try { final XMPPBuddy xmppBuddy = session.getBuddyManager().getBuddy(session.getTransport().convertIDToJID(presence.getFrom())); Log.debug("XMPP: Presence changed detected type "+presence.getType()+" and mode "+presence.getMode()+" for "+presence.getFrom()); xmppBuddy.setPresenceAndStatus( ((XMPPTransport)session.getTransport()).convertXMPPStatusToGateway(presence.getType(), presence.getMode()), presence.getStatus() ); if (JiveGlobals.getBooleanProperty("plugin.gateway."+session.getTransport().getType()+".avatars", true)) { PacketExtension pe = presence.getExtension("x", NameSpace.VCARD_TEMP_X_UPDATE); if (pe != null) { DefaultPacketExtension dpe = (DefaultPacketExtension)pe; String hash = dpe.getValue("photo"); final String from = presence.getFrom(); if (hash != null) { Avatar curAvatar = xmppBuddy.getAvatar(); if (curAvatar == null || !curAvatar.getLegacyIdentifier().equals(hash)) { new Thread() { @Override public void run() { VCard vcard = new VCard(); try { vcard.load(session.conn, from); xmppBuddy.setAvatar(new Avatar(xmppBuddy.getJID(), from, vcard.getAvatar())); } catch (XMPPException e) { Log.debug("XMPP: Failed to load XMPP avatar: ", e); } catch (IllegalArgumentException e) { Log.debug("XMPP: Got null avatar, ignoring."); } } }.start(); } } } } } catch (NotFoundException e) { Log.debug("XMPP: Received presence notification for contact that's not in the buddy manager of user " + session.getJID() + ". GTalk is known to do this occasionally: "+presence.getFrom()); // We cannot add this buddy to the buddy manager, as that would result into an auto-accept of the contact sending the data. } } } /** * Handles incoming presence stanzas that relate to subscription status. * Ignores others. * * @param presence * the stanza */ private void handlePresenceSubscription( final org.jivesoftware.smack.packet.Presence presence) { final Presence p = new Presence(); p.setTo(session.getJID()); p.setFrom(session.getTransport().convertIDToJID(presence.getFrom())); switch (presence.getType()) { case subscribe: p.setType(Presence.Type.subscribe); break; case subscribed: final XMPPBuddy buddy = new XMPPBuddy(session.getBuddyManager(), presence.getFrom()); session.getBuddyManager().storeBuddy(buddy); p.setType(Presence.Type.subscribed); break; case unsubscribe: p.setType(Presence.Type.unsubscribe); break; case unsubscribed: p.setType(Presence.Type.unsubscribed); break; case error: p.setType(Presence.Type.error); break; default: // don't send anything. return; } session.getTransport().sendPacket(p); } }