From 38ca53fcac323ba5c4b7056b14aa1f0be8c50678 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sun, 12 Nov 2023 16:11:11 +0100 Subject: [PATCH] bump reporting xep and add ability to report messages --- conversations.doap | 2 +- .../conversations/generator/IqGenerator.java | 10 ++++-- .../services/XmppConnectionService.java | 4 +-- .../conversations/ui/BlockContactDialog.java | 32 ++++++++++++++++--- .../conversations/ui/BlocklistActivity.java | 2 +- .../ui/ConversationFragment.java | 19 +++++++++++ .../eu/siacs/conversations/xml/Namespace.java | 2 ++ .../conversations/xmpp/XmppConnection.java | 2 +- src/main/res/menu/message_context.xml | 5 +++ src/main/res/values/strings.xml | 2 ++ 10 files changed, 69 insertions(+), 11 deletions(-) diff --git a/conversations.doap b/conversations.doap index d99e60656..4d492f9b3 100644 --- a/conversations.doap +++ b/conversations.doap @@ -375,7 +375,7 @@ complete - 0.2 + 0.3.1 diff --git a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java index 501c6d0c7..c9fa7f6a6 100644 --- a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java @@ -344,12 +344,18 @@ public class IqGenerator extends AbstractGenerator { return iq; } - public IqPacket generateSetBlockRequest(final Jid jid, boolean reportSpam) { + public IqPacket generateSetBlockRequest(final Jid jid, final boolean reportSpam, final String serverMsgId) { 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); if (reportSpam) { - item.addChild("report", "urn:xmpp:reporting:0").addChild("spam"); + final Element report = item.addChild("report", Namespace.REPORTING); + report.setAttribute("reason", Namespace.REPORTING_REASON_SPAM); + if (serverMsgId != null) { + final Element stanzaId = report.addChild("stanza-id", Namespace.STANZA_IDS); + stanzaId.setAttribute("by", jid); + stanzaId.setAttribute("id", serverMsgId); + } } Log.d(Config.LOGTAG, iq.toString()); return iq; diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 77a257403..d2f26af79 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -4756,10 +4756,10 @@ public class XmppConnectionService extends Service { mDatabaseWriterExecutor.execute(runnable); } - public boolean sendBlockRequest(final Blockable blockable, boolean reportSpam) { + public boolean sendBlockRequest(final Blockable blockable, final boolean reportSpam, final String serverMsgId) { if (blockable != null && blockable.getBlockedJid() != null) { final Jid jid = blockable.getBlockedJid(); - this.sendIqPacket(blockable.getAccount(), getIqGenerator().generateSetBlockRequest(jid, reportSpam), (a, response) -> { + this.sendIqPacket(blockable.getAccount(), getIqGenerator().generateSetBlockRequest(jid, reportSpam, serverMsgId), (a, response) -> { if (response.getType() == IqPacket.TYPE.RESULT) { a.getBlocklist().add(jid); updateBlocklistUi(OnUpdateBlocklist.Status.BLOCKED); diff --git a/src/main/java/eu/siacs/conversations/ui/BlockContactDialog.java b/src/main/java/eu/siacs/conversations/ui/BlockContactDialog.java index 6f4d77c51..986aeb563 100644 --- a/src/main/java/eu/siacs/conversations/ui/BlockContactDialog.java +++ b/src/main/java/eu/siacs/conversations/ui/BlockContactDialog.java @@ -14,13 +14,27 @@ import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.ui.util.JidDialog; public final class BlockContactDialog { + public static void show(final XmppActivity xmppActivity, final Blockable blockable) { + show(xmppActivity, blockable, null); + } + public static void show(final XmppActivity xmppActivity, final Blockable blockable, final String serverMsgId) { final AlertDialog.Builder builder = new AlertDialog.Builder(xmppActivity); final boolean isBlocked = blockable.isBlocked(); builder.setNegativeButton(R.string.cancel, null); DialogBlockContactBinding binding = DataBindingUtil.inflate(xmppActivity.getLayoutInflater(), R.layout.dialog_block_contact, null, false); final boolean reporting = blockable.getAccount().getXmppConnection().getFeatures().spamReporting(); - binding.reportSpam.setVisibility(!isBlocked && reporting ? View.VISIBLE : View.GONE); + if (reporting && !isBlocked) { + binding.reportSpam.setVisibility(View.VISIBLE); + if (serverMsgId != null) { + binding.reportSpam.setChecked(true); + binding.reportSpam.setEnabled(false); + } else { + binding.reportSpam.setEnabled(true); + } + } else { + binding.reportSpam.setVisibility(View.GONE); + } builder.setView(binding.getRoot()); final String value; @@ -34,8 +48,18 @@ public final class BlockContactDialog { value =blockable.getJid().getDomain().toEscapedString(); 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); + if (isBlocked) { + builder.setTitle(R.string.action_unblock_contact); + } else if (serverMsgId != null) { + builder.setTitle(R.string.report_spam_and_block); + } else { + final int resBlockAction = + blockable instanceof Conversation + && ((Conversation) blockable).isWithStranger() + ? R.string.block_stranger + : R.string.action_block_contact; + builder.setTitle(resBlockAction); + } value = blockable.getJid().asBareJid().toEscapedString(); res = isBlocked ? R.string.unblock_contact_text : R.string.block_contact_text; } @@ -45,7 +69,7 @@ public final class BlockContactDialog { xmppActivity.xmppConnectionService.sendUnblockRequest(blockable); } else { boolean toastShown = false; - if (xmppActivity.xmppConnectionService.sendBlockRequest(blockable, binding.reportSpam.isChecked())) { + if (xmppActivity.xmppConnectionService.sendBlockRequest(blockable, binding.reportSpam.isChecked(), serverMsgId)) { Toast.makeText(xmppActivity, R.string.corresponding_conversations_closed, Toast.LENGTH_SHORT).show(); toastShown = true; } diff --git a/src/main/java/eu/siacs/conversations/ui/BlocklistActivity.java b/src/main/java/eu/siacs/conversations/ui/BlocklistActivity.java index 55cf9ba03..17a9853b2 100644 --- a/src/main/java/eu/siacs/conversations/ui/BlocklistActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/BlocklistActivity.java @@ -87,7 +87,7 @@ public class BlocklistActivity extends AbstractSearchableListItemActivity implem dialog.setOnEnterJidDialogPositiveListener((accountJid, contactJid) -> { Blockable blockable = new RawBlockable(account, contactJid); - if (xmppConnectionService.sendBlockRequest(blockable, false)) { + if (xmppConnectionService.sendBlockRequest(blockable, false, null)) { Toast.makeText(BlocklistActivity.this, R.string.corresponding_conversations_closed, Toast.LENGTH_SHORT).show(); } return true; diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 2ff7d9c6f..d19bc4a55 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -1308,6 +1308,7 @@ public class ConversationFragment extends XmppFragment || t instanceof HttpDownloadConnection); activity.getMenuInflater().inflate(R.menu.message_context, menu); menu.setHeaderTitle(R.string.message_options); + final MenuItem reportAndBlock = menu.findItem(R.id.action_report_and_block); MenuItem openWith = menu.findItem(R.id.open_with); MenuItem copyMessage = menu.findItem(R.id.copy_message); MenuItem copyLink = menu.findItem(R.id.copy_link); @@ -1326,6 +1327,17 @@ public class ConversationFragment extends XmppFragment m.getStatus() == Message.STATUS_SEND_FAILED && m.getErrorMessage() != null && !Message.ERROR_MESSAGE_CANCELLED.equals(m.getErrorMessage()); + final Conversational conversational = m.getConversation(); + if (m.getStatus() == Message.STATUS_RECEIVED && conversational instanceof Conversation c) { + final XmppConnection connection = c.getAccount().getXmppConnection(); + if (c.isWithStranger() + && m.getServerMsgId() != null + && !c.isBlocked() + && connection != null + && connection.getFeatures().spamReporting()) { + reportAndBlock.setVisible(true); + } + } if (!m.isFileOrImage() && !encrypted && !m.isGeoUri() @@ -1449,6 +1461,9 @@ public class ConversationFragment extends XmppFragment case R.id.open_with: openWith(selectedMessage); return true; + case R.id.action_report_and_block: + reportMessage(selectedMessage); + return true; default: return super.onContextItemSelected(item); } @@ -2114,6 +2129,10 @@ public class ConversationFragment extends XmppFragment } } + private void reportMessage(final Message message) { + BlockContactDialog.show(activity, conversation.getContact(), message.getServerMsgId()); + } + private void showErrorMessage(final Message message) { AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity()); builder.setTitle(R.string.error_message); diff --git a/src/main/java/eu/siacs/conversations/xml/Namespace.java b/src/main/java/eu/siacs/conversations/xml/Namespace.java index c6730fe6c..667fa6457 100644 --- a/src/main/java/eu/siacs/conversations/xml/Namespace.java +++ b/src/main/java/eu/siacs/conversations/xml/Namespace.java @@ -67,4 +67,6 @@ public final class Namespace { public static final String OMEMO_DTLS_SRTP_VERIFICATION = "http://gultsch.de/xmpp/drafts/omemo/dlts-srtp-verification"; public static final String JINGLE_TRANSPORT_ICE_OPTION = "http://gultsch.de/xmpp/drafts/jingle/transports/ice-udp/option"; public static final String UNIFIED_PUSH = "http://gultsch.de/xmpp/drafts/unified-push"; + public static final String REPORTING = "urn:xmpp:reporting:1"; + public static final String REPORTING_REASON_SPAM = "urn:xmpp:reporting:spam"; } diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index 7de0de272..4151b0187 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -2689,7 +2689,7 @@ public class XmppConnection implements Runnable { } public boolean spamReporting() { - return hasDiscoFeature(account.getDomain(), "urn:xmpp:reporting:reason:spam:0"); + return hasDiscoFeature(account.getDomain(), Namespace.REPORTING); } public boolean flexibleOfflineMessageRetrieval() { diff --git a/src/main/res/menu/message_context.xml b/src/main/res/menu/message_context.xml index f32505203..cb6b31244 100644 --- a/src/main/res/menu/message_context.xml +++ b/src/main/res/menu/message_context.xml @@ -1,6 +1,11 @@ + + Log in Your contact uses unverified devices. Scan their 2D barcode to perform verification and impede active MITM attacks. You are using unverified devices. Scan the 2D barcode on your other devices to perform verification and impede active MITM attacks. + Report spam + Report spam and block spammer