Entity Caps and PEP

I’ve been testing my User Gaming via PEP on a locally installed copy of openfire and things are looking pretty good until I tried on jabber.org. Suddenly none of my packets are getting through. Upon further investigation, I found that you must advertise what information you are publishing and what info you are interested in before jabber.org will forward your PEP packets or route others PEP packets to you. This is in keeping with the PEP specs. Surprise, surprise. And the way this information is published is using a method call Entity Capabilties (XEP-0115).

Here is roughly how it works. When you come online, you Jabber client will send out a presence packet like so

<presence id=”N2ttf-4″/>

However XMPP clients with entity caps sends presences packet looks something like this

<presence id=”N2ttf-6″>
   <c xmlns=”http://jabber.org/protocol/caps&#8221; hash=”sha-1″
         node=”http://www.igniterealtime.org/projects/smack&#8221;
         ver=”FqngNglmgiLwmdc3F7/O7kMua0E=”/>

</presence>

Note the additional <c> fragment (formatted for readability) and inparticular the ver attribute. As you might have guess this is entity caps and the ver is a hash of your entity’s, in this case your JID, capabilities. This is typically what features your client support. I use JID and clients here interchangeably; a client is a XMPP client like Pidgin and JID is what you use to get on say jabber.org.

Now remember the presence packet is going out from the entity who has just come online; as an example and in keeping with most XMPP literature, when romeo@jabber.org comes online it will send out a presences packet to every one in his roster. Juliet (juliet@jabber.org) happens to be in his roster, so Juliet Jabber client receives this packet. Juliet’s client notices that Romeo’s presence packet has a entity cap hash string but does not know what that is. So the client sends a IQ to query Romeo. The following packet goes out to romeo@jabber.org

<iq id=”purple2686f3a5″ to=”romeo@jabber.org/games” from=”juliet@jabber.org/pidgin” type=”get”>
   <query xmlns=”http://jabber.org/protocol/disco#info&#8221;
         node=”http://www.igniterealtime.org/projects/smack#FqngNglmgiLwmdc3F7/O7kMua0E=“/>
</iq>

Romeo’s client then respond to this query with a list of the features that the hash represents them

<iq id=”purple2686f3a5″ to=”juliet@jabber.org/pidgin” type=”result”>
   <query xmlns=”http://jabber.org/protocol/disco#info&#8221;
         node=”http://www.igniterealtime.org/projects/smack#FqngNglmgiLwmdc3F7/O7kMua0E=“>
      <identity category=”client” name=”Smack” type=”pc”/>
      <feature var=”http://jabber.org/protocol/caps”/&gt;
      <feature var=”http://jabber.org/protocol/xhtml-im”/&gt;
      <feature var=”http://jabber.org/protocol/muc”/&gt;
      <feature var=”http://jabber.org/protocol/bytestreams”/&gt;
      <feature var=”http://jabber.org/protocol/commands”/&gt;
      <feature var=”urn:xmpp:gaming:0″/>
      <feature var=”urn:xmpp:gaming:0+notify”/>
   </query>
</iq>

Juliet’s client will now cache the hash string against these features. The next time she sees the same hash string, her client will know exactly what those features are without ever sending an IQ.

So what has this to do with PEP? Simple PEP leverages entity caps to tell other what it is interested in receiving and what it is publishing.

Smack do not support entity cap. However there is a project on github that adds this support. You can find it here. I’ve made a fork of this since mine works with the stock Smack rather than a fork version of Smack as the original did. You can find my implementation here and I’ll be using this for the rest of the article.

The following code snippet shows how you publish your entity cap in your presence

//Create a connection, connection and login
XMPPConnection connection = …
connection.connect();
connection.login(“juliet”, “act2scene2”, “balcony”);

//Get an instance of EntityCapsManager
EntityCapsManager capsManager = EntityCapsManager.getInstanceFor(connection);

//Eg. want to support user gaming (XEP-0196) through PEP (XEP-0163)
capsManager.addFeature(“urn:xmpp:gaming:0”);
capsManager.addFeature(“urn:xmpp:gaming:0+notify”);

//Republish our presence so that it will include our entity caps
connection.sendPacket(new Presence(Presence.Type.available));

//Now publish or receive data

Once you have created a connection, use the connection to retrieve an instance of EntityCapsManager.  Then what you do is now add the namespace XEP-0196 (urn:xmpp:gaming:0) as our feature. Note that there are two lines. The first indicates that we are publishing user gaming data and the second with a +notify appended indicates that we are interested in receiving user gaming data published by others. You can continue adding features here. Once you are done, you now resend your presences. The presence will now include an entity cap fragment with the latest hash code of all your features, including those supported by the client by default.

One important thing to remember is that if you want a feature or extended info to be included in the hash value of your entity caps, use addFeature(), removeFeature(), setExtendedInfo() and removeExtendedInfo() from EntityCapsManager. Do not use those the 4 corresponding methods from ServiceDiscoveryManager. Wherever you add or remove a feature or extended info, don’t forget to republish your presence.

jabber.org is one public servers I’ve tried that supports PEP. To find out what other public servers supports PEP, issue a disco#info to the JID (your login) or and look for the following

<identity category=”pubsub” name=”null” type=”pep“/>

In Smack that would be

XMPPConnection conn = … //Create a connection and login
ServiceDiscoveryManager mgr = ServiceDiscoveryManager.getInstanceFor(conn);
DiscoverInfo discoInfo = mgr.discoverInfo(conn.getUser());
Iterator<DiscoverInfo.Identity> iter = discoInfo.getIdentities();
while (iter.hasNext()) {
   DiscoveryInfo.Identity id = iter.next();
   if (“
pubsub“.equals(id.getCategory() && “pep“.equals(id.getType()))
      //Eureka! our server supports PEP!
}

%d bloggers like this: