From 5ea1c547d5d956473d3bce83d1f4354c0936ac6f Mon Sep 17 00:00:00 2001
From: Daniel Gultsch <daniel@gultsch.de>
Date: Sat, 25 Apr 2015 18:24:10 +0200
Subject: [PATCH] fixed service discovery by properly storing and checking
 identities

---
 .../conversations/ui/EditAccountActivity.java |  2 +-
 .../ui/PublishProfilePictureActivity.java     |  3 +-
 .../conversations/xmpp/XmppConnection.java    | 75 ++++++++++++-------
 3 files changed, 50 insertions(+), 30 deletions(-)

diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
index dbad9e00e..7aa7b1c2e 100644
--- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
@@ -468,7 +468,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
 			} else {
 				this.mServerInfoSm.setText(R.string.server_info_unavailable);
 			}
-			if (features.pubsub()) {
+			if (features.pep()) {
 				this.mServerInfoPep.setText(R.string.server_info_available);
 			} else {
 				this.mServerInfoPep.setText(R.string.server_info_unavailable);
diff --git a/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java b/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java
index 3f72b7233..e8ab8dae7 100644
--- a/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java
@@ -163,8 +163,7 @@ public class PublishProfilePictureActivity extends XmppActivity {
             if (jid != null) {
 				this.account = xmppConnectionService.findAccountByJid(jid);
 				if (this.account.getXmppConnection() != null) {
-					this.support = this.account.getXmppConnection()
-							.getFeatures().pubsub();
+					this.support = this.account.getXmppConnection().getFeatures().pep();
 				}
 				if (this.avatarUri == null) {
 					if (this.account.getAvatar() != null
diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
index 1351226ba..cf580df1b 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
@@ -90,7 +90,7 @@ public class XmppConnection implements Runnable {
 	private boolean shouldBind = true;
 	private boolean shouldAuthenticate = true;
 	private Element streamFeatures;
-	private final HashMap<String, List<String>> disco = new HashMap<>();
+	private final HashMap<Jid, Info> disco = new HashMap<>();
 
 	private String streamId = null;
 	private int smVersion = 3;
@@ -334,6 +334,7 @@ public class XmppConnection implements Runnable {
 								} catch (final NumberFormatException ignored) {
 								}
 								sendServiceDiscoveryInfo(account.getServer());
+								sendServiceDiscoveryInfo(account.getJid().toBareJid());
 								sendServiceDiscoveryItems(account.getServer());
 								sendInitialPing();
 							} else if (nextTag.isStart("r")) {
@@ -734,6 +735,7 @@ public class XmppConnection implements Runnable {
 		features.blockListRequested = false;
 		disco.clear();
 		sendServiceDiscoveryInfo(account.getServer());
+		sendServiceDiscoveryInfo(account.getJid().toBareJid());
 		sendServiceDiscoveryItems(account.getServer());
 		if (bindListener != null) {
 			bindListener.onBind(account);
@@ -741,34 +743,35 @@ public class XmppConnection implements Runnable {
 		sendInitialPing();
 	}
 
-	private void sendServiceDiscoveryInfo(final Jid server) {
-		if (disco.containsKey(server.toDomainJid().toString())) {
-			if (account.getServer().equals(server.toDomainJid())) {
+	private void sendServiceDiscoveryInfo(final Jid jid) {
+		if (disco.containsKey(jid)) {
+			if (account.getServer().equals(jid)) {
 				enableAdvancedStreamFeatures();
 			}
 		} else {
 			final IqPacket iq = new IqPacket(IqPacket.TYPE.GET);
-			iq.setTo(server.toDomainJid());
+			iq.setTo(jid);
 			iq.query("http://jabber.org/protocol/disco#info");
 			this.sendIqPacket(iq, new OnIqPacketReceived() {
 
 				@Override
 				public void onIqPacketReceived(final Account account, final IqPacket packet) {
 					final List<Element> elements = packet.query().getChildren();
-					final List<String> features = new ArrayList<>();
+					final Info info = new Info();
 					for (final Element element : elements) {
 						if (element.getName().equals("identity")) {
-							if ("irc".equals(element.getAttribute("type"))) {
-								//add fake feature to not confuse irc and real muc
-								features.add("siacs:no:muc");
+							String type = element.getAttribute("type");
+							String category = element.getAttribute("category");
+							if (type != null && category != null) {
+								info.identities.add(new Pair<>(category,type));
 							}
 						} else if (element.getName().equals("feature")) {
-							features.add(element.getAttribute("var"));
+							info.features.add(element.getAttribute("var"));
 						}
 					}
-					disco.put(server.toDomainJid().toString(), features);
+					disco.put(jid, info);
 
-					if (account.getServer().equals(server.toDomainJid())) {
+					if (account.getServer().equals(jid)) {
 						enableAdvancedStreamFeatures();
 						for (final OnAdvancedStreamFeaturesLoaded listener : advancedStreamFeaturesLoadedListeners) {
 							listener.onAdvancedStreamFeaturesAvailable(account);
@@ -987,9 +990,9 @@ public class XmppConnection implements Runnable {
 
 	public List<String> findDiscoItemsByFeature(final String feature) {
 		final List<String> items = new ArrayList<>();
-		for (final Entry<String, List<String>> cursor : disco.entrySet()) {
-			if (cursor.getValue().contains(feature)) {
-				items.add(cursor.getKey());
+		for (final Entry<Jid, Info> cursor : disco.entrySet()) {
+			if (cursor.getValue().features.contains(feature)) {
+				items.add(cursor.getKey().toString());
 			}
 		}
 		return items;
@@ -1008,10 +1011,12 @@ public class XmppConnection implements Runnable {
 	}
 
 	public String getMucServer() {
-		for (final Entry<String, List<String>> cursor : disco.entrySet()) {
-			final List<String> value = cursor.getValue();
-			if (value.contains("http://jabber.org/protocol/muc") && !value.contains("jabber:iq:gateway") && !value.contains("siacs:no:muc")) {
-				return cursor.getKey();
+		for (final Entry<Jid, Info> cursor : disco.entrySet()) {
+			final Info value = cursor.getValue();
+			if (value.features.contains("http://jabber.org/protocol/muc")
+					&& !value.features.contains("jabber:iq:gateway")
+					&& !value.identities.contains(new Pair<>("conference","irc"))) {
+				return cursor.getKey().toString();
 			}
 		}
 		return null;
@@ -1066,6 +1071,11 @@ public class XmppConnection implements Runnable {
 		this.lastConnect = 0;
 	}
 
+	private class Info {
+		public final ArrayList<String> features = new ArrayList<>();
+		public final ArrayList<Pair<String,String>> identities = new ArrayList<>();
+	}
+
 	public class Features {
 		XmppConnection connection;
 		private boolean carbonsEnabled = false;
@@ -1077,8 +1087,8 @@ public class XmppConnection implements Runnable {
 		}
 
 		private boolean hasDiscoFeature(final Jid server, final String feature) {
-			return connection.disco.containsKey(server.toDomainJid().toString()) &&
-				connection.disco.get(server.toDomainJid().toString()).contains(feature);
+			return connection.disco.containsKey(server) &&
+				connection.disco.get(server).features.contains(feature);
 		}
 
 		public boolean carbons() {
@@ -1094,24 +1104,35 @@ public class XmppConnection implements Runnable {
 		}
 
 		public boolean sm() {
-			return streamId != null;
+			return streamId != null
+					|| (connection.streamFeatures != null && connection.streamFeatures.hasChild("sm"));
 		}
 
 		public boolean csi() {
 			return connection.streamFeatures != null && connection.streamFeatures.hasChild("csi", "urn:xmpp:csi:0");
 		}
 
-		public boolean pubsub() {
-			return hasDiscoFeature(account.getServer(),
-					"http://jabber.org/protocol/pubsub#publish");
+		public boolean pep() {
+			final Pair<String,String> needle = new Pair<>("pubsub","pep");
+			Info info = disco.get(account.getServer());
+			if (info != null && info.identities.contains(needle)) {
+				return true;
+			} else {
+				info = disco.get(account.getJid().toBareJid());
+				return info != null && info.identities.contains(needle);
+			}
 		}
 
 		public boolean mam() {
-			return hasDiscoFeature(account.getServer(), "urn:xmpp:mam:0");
+			if (hasDiscoFeature(account.getJid().toBareJid(), "urn:xmpp:mam:0")) {
+				return true;
+			} else {
+				return hasDiscoFeature(account.getServer(), "urn:xmpp:mam:0");
+			}
 		}
 
 		public boolean advancedStreamFeaturesLoaded() {
-			return disco.containsKey(account.getServer().toString());
+			return disco.containsKey(account.getServer());
 		}
 
 		public boolean rosterVersioning() {