Generate capHash from any discovery result

Stephen Paul Weber created

Change summary

src/main/java/eu/siacs/conversations/entities/ServiceDiscoveryResult.java | 84 
1 file changed, 80 insertions(+), 4 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/entities/ServiceDiscoveryResult.java 🔗

@@ -1,26 +1,41 @@
 package eu.siacs.conversations.entities;
 
-import java.util.List;
+import android.content.ContentValues;
+import android.util.Base64;
+import java.io.UnsupportedEncodingException;
+import java.lang.Comparable;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 
 import eu.siacs.conversations.xml.Element;
 import eu.siacs.conversations.xmpp.stanzas.IqPacket;
 
 public class ServiceDiscoveryResult {
-	public static class Identity {
+
+	protected static String blankNull(String s) {
+		return s == null ? "" : s;
+	}
+
+	public static class Identity implements Comparable {
 		protected final String category;
 		protected final String type;
+		protected final String lang;
 		protected final String name;
 
-		public Identity(final String category, final String type, final String name) {
+		public Identity(final String category, final String type, final String lang, final String name) {
 			this.category = category;
 			this.type = type;
+			this.lang = lang;
 			this.name = name;
 		}
 
 		public Identity(final Element el) {
 			this.category = el.getAttribute("category");
 			this.type = el.getAttribute("type");
+			this.lang = el.getAttribute("xml:lang");
 			this.name = el.getAttribute("name");
 		}
 
@@ -32,9 +47,29 @@ public class ServiceDiscoveryResult {
 			return this.type;
 		}
 
+		public String getLang() {
+			return this.lang;
+		}
+
 		public String getName() {
 			return this.name;
 		}
+
+		public int compareTo(Object other) {
+			Identity o = (Identity)other;
+			int r = blankNull(this.getCategory()).compareTo(blankNull(o.getCategory()));
+			if(r == 0) {
+				r = blankNull(this.getType()).compareTo(blankNull(o.getType()));
+			}
+			if(r == 0) {
+				r = blankNull(this.getLang()).compareTo(blankNull(o.getLang()));
+			}
+			if(r == 0) {
+				r = blankNull(this.getName()).compareTo(blankNull(o.getName()));
+			}
+
+			return r;
+		}
 	}
 
 	protected final List<Identity> identities;
@@ -58,7 +93,9 @@ public class ServiceDiscoveryResult {
 					identities.add(id);
 				}
 			} else if (element.getName().equals("feature")) {
-				features.add(element.getAttribute("var"));
+				if (element.getAttribute("var") != null) {
+					features.add(element.getAttribute("var"));
+				}
 			}
 		}
 	}
@@ -81,4 +118,43 @@ public class ServiceDiscoveryResult {
 
 		return false;
 	}
+
+	public byte[] getCapHash() {
+		StringBuilder s = new StringBuilder();
+
+		List<Identity> identities = this.getIdentities();
+		Collections.sort(identities);
+
+		for(Identity id : identities) {
+			s.append(
+				blankNull(id.getCategory()) + "/" +
+				blankNull(id.getType()) + "/" +
+				blankNull(id.getLang()) + "/" +
+				blankNull(id.getName()) + "<"
+			);
+		}
+
+		List<String> features = this.getFeatures();
+		Collections.sort(features);
+
+		for (String feature : features) {
+			s.append(feature + "<");
+		}
+
+		// TODO: data forms?
+
+		MessageDigest md;
+		try {
+			md = MessageDigest.getInstance("SHA-1");
+		} catch (NoSuchAlgorithmException e) {
+			return null;
+		}
+
+		try {
+			return md.digest(s.toString().getBytes("UTF-8"));
+		} catch(UnsupportedEncodingException e) {
+			return null;
+		}
+	}
+
 }