handle blocking and unblocking of full jids

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/entities/RawBlockable.java          | 87 
src/main/java/eu/siacs/conversations/generator/IqGenerator.java          |  4 
src/main/java/eu/siacs/conversations/parser/MessageParser.java           |  4 
src/main/java/eu/siacs/conversations/services/AvatarService.java         |  5 
src/main/java/eu/siacs/conversations/services/XmppConnectionService.java | 20 
src/main/java/eu/siacs/conversations/ui/BlockContactDialog.java          |  8 
src/main/java/eu/siacs/conversations/ui/BlocklistActivity.java           | 21 
src/main/res/values/strings.xml                                          |  2 
8 files changed, 128 insertions(+), 23 deletions(-)

Detailed changes

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

@@ -0,0 +1,87 @@
+package eu.siacs.conversations.entities;
+
+import android.content.Context;
+import android.text.TextUtils;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+
+import eu.siacs.conversations.utils.UIHelper;
+import rocks.xmpp.addr.Jid;
+
+public class RawBlockable implements ListItem, Blockable {
+
+    private final Account account;
+    private final Jid jid;
+
+    public RawBlockable(Account account, Jid jid) {
+        this.account = account;
+        this.jid = jid;
+    }
+
+    @Override
+    public boolean isBlocked() {
+        return true;
+    }
+
+    @Override
+    public boolean isDomainBlocked() {
+        throw new AssertionError("not implemented");
+    }
+
+    @Override
+    public Jid getBlockedJid() {
+        return this.jid;
+    }
+
+    @Override
+    public String getDisplayName() {
+        if (jid.isFullJid()) {
+            return jid.getResource();
+        } else {
+            return jid.toEscapedString();
+        }
+    }
+
+    @Override
+    public Jid getJid() {
+        return this.jid;
+    }
+
+    @Override
+    public List<Tag> getTags(Context context) {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public boolean match(Context context, String needle) {
+        if (TextUtils.isEmpty(needle)) {
+            return true;
+        }
+        needle = needle.toLowerCase(Locale.US).trim();
+        String[] parts = needle.split("\\s+");
+        for (String part : parts) {
+            if (!jid.toEscapedString().contains(part)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public Account getAccount() {
+        return account;
+    }
+
+    @Override
+    public int getAvatarBackgroundColor() {
+        return  UIHelper.getColorForName(jid.toEscapedString());
+    }
+
+    @Override
+    public int compareTo(ListItem o) {
+        return this.getDisplayName().compareToIgnoreCase(
+				o.getDisplayName());
+    }
+}

src/main/java/eu/siacs/conversations/generator/IqGenerator.java 🔗

@@ -305,7 +305,7 @@ public class IqGenerator extends AbstractGenerator {
 	public IqPacket generateSetBlockRequest(final Jid jid, boolean reportSpam) {
 		final IqPacket iq = new IqPacket(IqPacket.TYPE.SET);
 		final Element block = iq.addChild("block", Namespace.BLOCKING);
-		final Element item = block.addChild("item").setAttribute("jid", jid.asBareJid().toString());
+		final Element item = block.addChild("item").setAttribute("jid", jid.toEscapedString());
 		if (reportSpam) {
 			item.addChild("report", "urn:xmpp:reporting:0").addChild("spam");
 		}
@@ -316,7 +316,7 @@ public class IqGenerator extends AbstractGenerator {
 	public IqPacket generateSetUnblockRequest(final Jid jid) {
 		final IqPacket iq = new IqPacket(IqPacket.TYPE.SET);
 		final Element block = iq.addChild("unblock", Namespace.BLOCKING);
-		block.addChild("item").setAttribute("jid", jid.asBareJid().toString());
+		block.addChild("item").setAttribute("jid", jid.toEscapedString());
 		return iq;
 	}
 

src/main/java/eu/siacs/conversations/parser/MessageParser.java 🔗

@@ -127,7 +127,8 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
                     service.reportBrokenSessionException(e, postpone);
                     return new Message(conversation, "", Message.ENCRYPTION_AXOLOTL_FAILED, status);
                 } else {
-                    Log.d(Config.LOGTAG,"ignoring broken session exception because checkForDuplicase failed");
+                    Log.d(Config.LOGTAG,"ignoring broken session exception because checkForDuplicates failed");
+                    //TODO should be still emit a failed message?
                     return null;
                 }
             } catch (NotEncryptedForThisDeviceException e) {
@@ -449,6 +450,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
                     origin = from;
                 }
 
+                //TODO either or is probably fine?
                 final boolean checkedForDuplicates = serverMsgId != null && remoteMsgId != null && !conversation.possibleDuplicate(serverMsgId, remoteMsgId);
 
                 if (origin != null) {

src/main/java/eu/siacs/conversations/services/AvatarService.java 🔗

@@ -37,6 +37,7 @@ import eu.siacs.conversations.entities.Conversational;
 import eu.siacs.conversations.entities.ListItem;
 import eu.siacs.conversations.entities.Message;
 import eu.siacs.conversations.entities.MucOptions;
+import eu.siacs.conversations.entities.RawBlockable;
 import eu.siacs.conversations.http.services.MuclumbusService;
 import eu.siacs.conversations.utils.UIHelper;
 import eu.siacs.conversations.xmpp.OnAdvancedStreamFeaturesLoaded;
@@ -272,7 +273,9 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded {
 	}
 
 	public Bitmap get(ListItem item, int size, boolean cachedOnly) {
-		if (item instanceof Contact) {
+		if (item instanceof RawBlockable) {
+			return get(item.getDisplayName(), item.getJid().toEscapedString(), size, cachedOnly);
+		} else if (item instanceof Contact) {
 			return get((Contact) item, size, cachedOnly);
 		} else if (item instanceof Bookmark) {
 			Bookmark bookmark = (Bookmark) item;

src/main/java/eu/siacs/conversations/services/XmppConnectionService.java 🔗

@@ -4251,17 +4251,15 @@ public class XmppConnectionService extends Service {
 	public boolean sendBlockRequest(final Blockable blockable, boolean reportSpam) {
 		if (blockable != null && blockable.getBlockedJid() != null) {
 			final Jid jid = blockable.getBlockedJid();
-			this.sendIqPacket(blockable.getAccount(), getIqGenerator().generateSetBlockRequest(jid, reportSpam), new OnIqPacketReceived() {
-
-				@Override
-				public void onIqPacketReceived(final Account account, final IqPacket packet) {
-					if (packet.getType() == IqPacket.TYPE.RESULT) {
-						account.getBlocklist().add(jid);
-						updateBlocklistUi(OnUpdateBlocklist.Status.BLOCKED);
-					}
-				}
-			});
-			if (removeBlockedConversations(blockable.getAccount(), jid)) {
+			this.sendIqPacket(blockable.getAccount(), getIqGenerator().generateSetBlockRequest(jid, reportSpam), (a, response) -> {
+                if (response.getType() == IqPacket.TYPE.RESULT) {
+                    a.getBlocklist().add(jid);
+                    updateBlocklistUi(OnUpdateBlocklist.Status.BLOCKED);
+                }
+            });
+			if (blockable.getBlockedJid().isFullJid()) {
+			    return false;
+            } else if (removeBlockedConversations(blockable.getAccount(), jid)) {
 				updateConversationUi();
 				return true;
 			} else {

src/main/java/eu/siacs/conversations/ui/BlockContactDialog.java 🔗

@@ -28,14 +28,18 @@ public final class BlockContactDialog {
 
 		final String value;
 		@StringRes int res;
-		if (blockable.getJid().getLocal() == null || blockable.getAccount().isBlocked(Jid.ofDomain(blockable.getJid().getDomain()))) {
+		if (blockable.getJid().isFullJid()) {
+			builder.setTitle(isBlocked ? R.string.action_unblock_participant : R.string.action_block_participant);
+			value = blockable.getJid().toEscapedString();
+			res = isBlocked ? R.string.unblock_contact_text : R.string.block_contact_text;
+		} else if (blockable.getJid().getLocal() == null || blockable.getAccount().isBlocked(Jid.ofDomain(blockable.getJid().getDomain()))) {
 			builder.setTitle(isBlocked ? R.string.action_unblock_domain : R.string.action_block_domain);
 			value = Jid.ofDomain(blockable.getJid().getDomain()).toString();
 			res = isBlocked ? R.string.unblock_domain_text : R.string.block_domain_text;
 		} else {
 			int resBlockAction = blockable instanceof Conversation && ((Conversation) blockable).isWithStranger() ? R.string.block_stranger : R.string.action_block_contact;
 			builder.setTitle(isBlocked ? R.string.action_unblock_contact : resBlockAction);
-			value = blockable.getJid().asBareJid().toString();
+			value = blockable.getJid().asBareJid().toEscapedString();
 			res = isBlocked ? R.string.unblock_contact_text : R.string.block_contact_text;
 		}
 		binding.text.setText(JidDialog.style(xmppActivity, res, value));

src/main/java/eu/siacs/conversations/ui/BlocklistActivity.java 🔗

@@ -10,7 +10,10 @@ import java.util.Collections;
 
 import eu.siacs.conversations.R;
 import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.entities.Blockable;
 import eu.siacs.conversations.entities.Contact;
+import eu.siacs.conversations.entities.ListItem;
+import eu.siacs.conversations.entities.RawBlockable;
 import eu.siacs.conversations.ui.interfaces.OnBackendConnected;
 import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
 import rocks.xmpp.addr.Jid;
@@ -23,7 +26,7 @@ public class BlocklistActivity extends AbstractSearchableListItemActivity implem
 	public void onCreate(final Bundle savedInstanceState) {
 		super.onCreate(savedInstanceState);
 		getListView().setOnItemLongClickListener((parent, view, position, id) -> {
-			BlockContactDialog.show(BlocklistActivity.this, (Contact) getListItems().get(position));
+			BlockContactDialog.show(BlocklistActivity.this, (Blockable) getListItems().get(position));
 			return true;
 		});
 		this.binding.fab.show();
@@ -50,9 +53,14 @@ public class BlocklistActivity extends AbstractSearchableListItemActivity implem
 		getListItems().clear();
 		if (account != null) {
 			for (final Jid jid : account.getBlocklist()) {
-				final Contact contact = account.getRoster().getContact(jid);
-				if (contact.match(this, needle) && contact.isBlocked()) {
-					getListItems().add(contact);
+				ListItem item;
+				if (jid.isFullJid()) {
+					item = new RawBlockable(account, jid);
+				} else {
+					item = account.getRoster().getContact(jid);
+				}
+				if (item.match(this, needle)) {
+					getListItems().add(item);
 				}
 			}
 			Collections.sort(getListItems());
@@ -78,8 +86,8 @@ public class BlocklistActivity extends AbstractSearchableListItemActivity implem
 		);
 
 		dialog.setOnEnterJidDialogPositiveListener((accountJid, contactJid) -> {
-			Contact contact = account.getRoster().getContact(contactJid);
-			if (xmppConnectionService.sendBlockRequest(contact, false)) {
+			Blockable blockable = new RawBlockable(account, contactJid);
+			if (xmppConnectionService.sendBlockRequest(blockable, false)) {
 				Toast.makeText(BlocklistActivity.this, R.string.corresponding_conversations_closed, Toast.LENGTH_SHORT).show();
 			}
 			return true;
@@ -101,4 +109,5 @@ public class BlocklistActivity extends AbstractSearchableListItemActivity implem
 	public void OnUpdateBlocklist(final OnUpdateBlocklist.Status status) {
 		refreshUi();
 	}
+
 }

src/main/res/values/strings.xml 🔗

@@ -17,6 +17,8 @@
     <string name="action_unblock_contact">Unblock contact</string>
     <string name="action_block_domain">Block domain</string>
     <string name="action_unblock_domain">Unblock domain</string>
+    <string name="action_block_participant">Block participant</string>
+    <string name="action_unblock_participant">Unblock participant</string>
     <string name="title_activity_manage_accounts">Manage Accounts</string>
     <string name="title_activity_settings">Settings</string>
     <string name="title_activity_sharewith">Share with Conversation</string>