--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/asmack-beem/beem_patches/50-public-info-features.patch Thu Jul 22 23:34:36 2010 +0200
@@ -0,0 +1,18 @@
+--- org/jivesoftware/smackx/packet/DiscoverInfo.java 2010-07-22 22:16:27.000000000 +0200
++++ org/jivesoftware/smackx/packet/DiscoverInfo.java 2010-07-22 22:58:43.000000000 +0200
+@@ -62,7 +62,7 @@
+ *
+ * @return an Iterator on the discovered features of an XMPP entity
+ */
+- Iterator<Feature> getFeatures() {
++ public Iterator<Feature> getFeatures() {
+ synchronized (features) {
+ return Collections.unmodifiableList(features).iterator();
+ }
+@@ -266,4 +266,4 @@
+ return buf.toString();
+ }
+ }
+-}
+\ Pas de fin de ligne à la fin du fichier.
++}
Binary file libs/asmack-android-7-beem.jar has changed
--- a/src/com/beem/project/beem/BeemService.java Wed Jul 21 23:29:41 2010 +0200
+++ b/src/com/beem/project/beem/BeemService.java Thu Jul 22 23:34:36 2010 +0200
@@ -51,6 +51,8 @@
import org.jivesoftware.smack.provider.PrivacyProvider;
import org.jivesoftware.smack.provider.ProviderManager;
import org.jivesoftware.smackx.provider.DelayInfoProvider;
+import org.jivesoftware.smackx.provider.DiscoverInfoProvider;
+import org.jivesoftware.smackx.provider.DiscoverItemsProvider;
import org.jivesoftware.smackx.packet.ChatStateExtension;
import org.jivesoftware.smack.proxy.ProxyInfo;
import org.jivesoftware.smack.proxy.ProxyInfo.ProxyType;
@@ -78,6 +80,7 @@
import com.beem.project.beem.utils.BeemBroadcastReceiver;
import com.beem.project.beem.utils.BeemConnectivity;
import com.beem.project.beem.utils.Status;
+import com.beem.project.beem.smack.caps.CapsProvider;
/**
* This class is for the Beem service.
@@ -319,6 +322,11 @@
// Delayed Delivery only the new version
pm.addExtensionProvider("delay", "urn:xmpp:delay", new DelayInfoProvider());
+ // Service Discovery # Items
+ pm.addIQProvider("query", "http://jabber.org/protocol/disco#items", new DiscoverItemsProvider());
+ // Service Discovery # Info
+ pm.addIQProvider("query", "http://jabber.org/protocol/disco#info", new DiscoverInfoProvider());
+
// Chat State
ChatStateExtension.Provider chatState = new ChatStateExtension.Provider();
pm.addExtensionProvider("active", "http://jabber.org/protocol/chatstates", chatState);
@@ -327,6 +335,7 @@
pm.addExtensionProvider("paused", "http://jabber.org/protocol/chatstates", chatState);
pm.addExtensionProvider("inactive", "http://jabber.org/protocol/chatstates", chatState);
pm.addExtensionProvider("gone", "http://jabber.org/protocol/chatstates", chatState);
+ pm.addExtensionProvider("c", "http://jabber.org/protocol/caps", new CapsProvider());
/*
// Private Data Storage
pm.addIQProvider("query", "jabber:iq:private", new PrivateDataManager.PrivateDataIQProvider());
@@ -344,10 +353,6 @@
pm.addExtensionProvider("html", "http://jabber.org/protocol/xhtml-im", new XHTMLExtensionProvider());
// Group Chat Invitations
pm.addExtensionProvider("x", "jabber:x:conference", new GroupChatInvitation.Provider());
- // Service Discovery # Items
- pm.addIQProvider("query", "http://jabber.org/protocol/disco#items", new DiscoverItemsProvider());
- // Service Discovery # Info
- pm.addIQProvider("query", "http://jabber.org/protocol/disco#info", new DiscoverInfoProvider());
// Data Forms
pm.addExtensionProvider("x", "jabber:x:data", new DataFormProvider());
// MUC User
--- a/src/com/beem/project/beem/service/XmppConnectionAdapter.java Wed Jul 21 23:29:41 2010 +0200
+++ b/src/com/beem/project/beem/service/XmppConnectionAdapter.java Thu Jul 22 23:34:36 2010 +0200
@@ -76,6 +76,7 @@
import com.beem.project.beem.ui.Subscription;
import com.beem.project.beem.utils.BeemBroadcastReceiver;
import com.beem.project.beem.utils.Status;
+import com.beem.project.beem.smack.caps.CapsManager;
/**
* This class implements an adapter for XMPPConnection.
@@ -205,9 +206,6 @@
if (!mAdaptee.isConnected())
return false;
try {
- mAdaptee.login(mLogin, mPassword, mResource);
- mChatManager = new BeemChatManager(mAdaptee.getChatManager(), mService);
- mPrivacyListManager = new PrivacyListManagerAdapter(PrivacyListManager.getInstanceFor(mAdaptee));
this.initFeatures(); // pour declarer les features xmpp qu'on
// supporte
@@ -227,6 +225,9 @@
mAdaptee.addPacketListener(mSubscribePacketListener, filter);
+ mAdaptee.login(mLogin, mPassword, mResource);
+ mChatManager = new BeemChatManager(mAdaptee.getChatManager(), mService);
+ mPrivacyListManager = new PrivacyListManagerAdapter(PrivacyListManager.getInstanceFor(mAdaptee));
mService.resetStatus();
mService.initJingle(mAdaptee);
@@ -392,7 +393,9 @@
sdm = new ServiceDiscoveryManager(mAdaptee);
sdm.addFeature("http://jabber.org/protocol/disco#info");
sdm.addFeature("jabber:iq:privacy");
+ sdm.addFeature("http://jabber.org/protocol/caps");
mChatStateManager = ChatStateManager.getInstance(mAdaptee);
+ CapsManager caps = new CapsManager(sdm, mAdaptee);
}
/**
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/beem/project/beem/smack/caps/CapsExtension.java Thu Jul 22 23:34:36 2010 +0200
@@ -0,0 +1,78 @@
+package com.beem.project.beem.smack.caps;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+
+public class CapsExtension implements PacketExtension {
+
+ private String mVer;
+ private String mHash;
+ private String mNode;
+ private String mExt;
+
+
+ public CapsExtension(String hash, String node, String ver) {
+ mHash = hash;
+ mNode = node;
+ mVer = ver;
+ }
+
+ public String getVer(){
+ return mVer;
+ }
+
+ public String getHash(){
+ return mHash;
+ }
+
+ public String getNode(){
+ return mNode;
+ }
+
+ public String getExt(){
+ return mExt;
+ }
+
+ public void setHash(String hash) {
+ mHash = hash;
+ }
+
+ public void setVer(String ver) {
+ mVer = ver;
+ }
+
+ public void setNode(String node) {
+ mNode = node;
+ }
+
+ public void setExt(String ext) {
+ mExt = ext;
+ }
+
+ @Override
+ public String getElementName() {
+ return "c";
+ }
+
+ @Override
+ public String getNamespace() {
+ return "http://jabber.org/protocol/caps";
+ }
+
+ @Override
+ public String toXML(){
+ StringBuilder b = new StringBuilder("<");
+ b.append(getElementName());
+ b.append(" xmlns=\"").append(getNamespace()).append("\" ");
+ if (mHash != null){
+ b.append("hash=\"").append(mHash).append("\" ");
+ }
+ if (mNode != null)
+ b.append("node=\"").append(mNode).append("\" ");
+ if (mVer != null)
+ b.append("ver=\"").append(mVer).append("\" ");
+ if (mExt!= null)
+ b.append("ext=\"").append(mExt).append("\" ");
+ b.append("/>");
+ return b.toString();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/beem/project/beem/smack/caps/CapsManager.java Thu Jul 22 23:34:36 2010 +0200
@@ -0,0 +1,183 @@
+
+package com.beem.project.beem.smack.caps;
+
+import org.jivesoftware.smack.Connection;
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smackx.packet.DiscoverInfo;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smackx.ServiceDiscoveryManager;
+import org.jivesoftware.smack.util.collections.ReferenceMap;
+import org.jivesoftware.smack.PacketListener;
+import org.jivesoftware.smack.filter.PacketFilter;
+import org.jivesoftware.smack.filter.PacketExtensionFilter;
+
+import java.util.Map;
+import java.util.Iterator;
+import java.util.Comparator;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.security.NoSuchAlgorithmException;
+import java.security.MessageDigest;
+
+import org.jivesoftware.smack.util.StringUtils;
+
+public class CapsManager {
+ // the verCache should be stored on disk
+ Map<String, DiscoverInfo> mVerCache = new ReferenceMap<String, DiscoverInfo>();
+ Map<String, DiscoverInfo> mJidCache = new ReferenceMap<String, DiscoverInfo>();
+
+ private ServiceDiscoveryManager mSdm;
+ private Connection mConnection;
+ private List<String> mSupportedAlgorithm = new ArrayList<String>();
+
+ public CapsManager(ServiceDiscoveryManager sdm, Connection conn) {
+ mSdm = sdm;
+ mConnection = conn;
+ init();
+ }
+
+ private void init() {
+ initSupportedAlgorithm();
+ PacketFilter filter = new PacketExtensionFilter("c", "http://jabber.org/protocol/caps");
+ mConnection.addPacketListener( new PacketListener() {
+ public void processPacket(Packet packet) {
+ PacketExtension p = packet.getExtension("c", "http://jabber.org/protocol/caps");
+ CapsExtension caps = (CapsExtension) p;
+ if (!mVerCache.containsKey(caps.getVer()))
+ validate(packet.getFrom(), caps.getVer(), caps.getHash());
+ }
+ }, filter);
+ }
+
+ public DiscoverInfo getDiscoverInfo(String ver) {
+ return mVerCache.get(ver);
+ }
+
+ public DiscoverInfo getDiscoverInfo(String jid, String ver) {
+ DiscoverInfo info = mVerCache.get(ver);
+ if (info == null)
+ info = mJidCache.get(jid);
+ return info;
+ }
+
+ /**
+ *
+ *
+ * @param jid
+ * @param ver
+ * @param hashMethod
+ * @return
+ */
+ private boolean validate(String jid, String ver, String hashMethod) {
+ try {
+ DiscoverInfo info = mSdm.discoverInfo(jid);
+ if (!mSupportedAlgorithm.contains(hashMethod)) {
+ mJidCache.put(jid, info);
+ return false;
+ }
+ String v = calculateVer(info, hashMethod);
+ boolean res = v.equals(ver);
+ if (res)
+ mVerCache.put(ver, info);
+ return res;
+ } catch (XMPPException e) {
+ e.printStackTrace();
+ return false;
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ private String calculateVer(DiscoverInfo info, String hashMethod) throws NoSuchAlgorithmException {
+ StringBuilder S = new StringBuilder();
+ for(DiscoverInfo.Identity identity : getSortedIdentity(info)) {
+ String c = identity.getCategory();
+ if (c != null)
+ S.append(c);
+ S.append('/');
+ c = identity.getType();
+ if (c != null)
+ S.append(c);
+ S.append('/');
+ // Should add lang but it is not available
+// c = identity.getType();
+// if (c != null)
+// S.append(c);
+ S.append('/');
+ c = identity.getName();
+ if (c != null)
+ S.append(c);
+ S.append('<');
+ }
+ for (String f : getSortedFeature(info)) {
+ S.append(f);
+ S.append('<');
+ }
+ // Should add data form (XEP 0128) but it is not available
+ byte[] hash = getHash(hashMethod, S.toString().getBytes());
+ return StringUtils.encodeBase64(hash);
+ }
+
+ private List<DiscoverInfo.Identity> getSortedIdentity(DiscoverInfo info) {
+ List<DiscoverInfo.Identity> result = new ArrayList<DiscoverInfo.Identity>();
+ Iterator<DiscoverInfo.Identity> it = info.getIdentities();
+ while (it.hasNext()) {
+ DiscoverInfo.Identity id = it.next();
+ result.add(id);
+ }
+ Collections.sort(result, new Comparator<DiscoverInfo.Identity>() {
+ public int compare(DiscoverInfo.Identity o1, DiscoverInfo.Identity o2) {
+
+ String cat1 = o1.getCategory();
+ if (cat1 == null) cat1 = "";
+ String cat2 = o2.getCategory();
+ if (cat2 == null) cat2 = "";
+ int res = cat1.compareTo(cat2);
+ if (res != 0)
+ return res;
+ String type1 = o1.getType();
+ if (type1 == null) type1 = "";
+ String type2 = o2.getCategory();
+ if (type2 == null) type2 = "";
+ res = type1.compareTo(type2);
+ if (res != 0)
+ return res;
+ // should compare lang but not avalaible
+ return 0;
+ }
+ });
+ return result;
+ }
+
+ private List<String> getSortedFeature(DiscoverInfo info) {
+ List<String> result = new ArrayList<String>();
+ Iterator<DiscoverInfo.Feature> it = info.getFeatures();
+ while (it.hasNext()) {
+ DiscoverInfo.Feature feat = it.next();
+ result.add(feat.getVar());
+ }
+ Collections.sort(result);
+ return result;
+ }
+
+ private byte[] getHash(String algo, byte[] data) throws NoSuchAlgorithmException {
+ MessageDigest md = MessageDigest.getInstance(algo);
+ return md.digest(data);
+ }
+
+ private void initSupportedAlgorithm() {
+ String algo[] = new String[] {"md2", "md5", "sha-1", "sha-224", "sha-256", "sha-384", "sha-512" };
+ for (String a : algo) {
+ try {
+ MessageDigest md = MessageDigest.getInstance(a);
+ mSupportedAlgorithm.add(a);
+ } catch(NoSuchAlgorithmException e) {
+ System.err.println("Hash algorithm " + a + " not supported");
+ }
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/beem/project/beem/smack/caps/CapsProvider.java Thu Jul 22 23:34:36 2010 +0200
@@ -0,0 +1,21 @@
+
+package com.beem.project.beem.smack.caps;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.jivesoftware.smack.provider.PacketExtensionProvider;
+import org.jivesoftware.smack.packet.PacketExtension;
+
+public class CapsProvider implements PacketExtensionProvider {
+
+ @Override
+ public PacketExtension parseExtension(XmlPullParser parser) {
+ String ver = parser.getAttributeValue("", "ver");
+ String hash = parser.getAttributeValue("", "hash");
+ String node = parser.getAttributeValue("", "node");
+ String ext = parser.getAttributeValue("", "ext");
+ CapsExtension e = new CapsExtension(hash, node, ver);
+ e.setExt(ext);
+ return e;
+ }
+
+}