diff --git a/src/cheogram/java/com/cheogram/android/BobTransfer.java b/src/cheogram/java/com/cheogram/android/BobTransfer.java index a748ada109050679dbe788b8fe9aabfdaba79566..d6765d8601248a35f1f970b1dd21c61e1b17ec59 100644 --- a/src/cheogram/java/com/cheogram/android/BobTransfer.java +++ b/src/cheogram/java/com/cheogram/android/BobTransfer.java @@ -111,7 +111,7 @@ public class BobTransfer implements Transferable { outputStream.close(); finish(file); - } catch (IOException e) { + } catch (final IOException | XmppConnectionService.BlockedMediaException e) { finish(null); xmppConnectionService.showErrorToastInUi(R.string.download_failed_could_not_write_file); } diff --git a/src/cheogram/res/values/strings.xml b/src/cheogram/res/values/strings.xml index 067db242baa37b2c7f48a9f1522aef43910c409d..1e2ddba47109cc3fa9f78b0d5346d61c5944c4d2 100644 --- a/src/cheogram/res/values/strings.xml +++ b/src/cheogram/res/values/strings.xml @@ -34,4 +34,5 @@ Moderate Moderation Reason Unable to Moderate + Block Media diff --git a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java index 67e29178d04f71df8fa0e9737045badc44e99bc9..28685bfe9b799f5d50594a0b0f9a13e07954912f 100644 --- a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java +++ b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java @@ -201,6 +201,10 @@ public class HttpDownloadConnection implements Transferable { Log.w(Config.LOGTAG, "Failed to rename downloaded file: " + e); file = tmp; message.setRelativeFilePath(file.getAbsolutePath()); + } catch (final XmppConnectionService.BlockedMediaException e) { + file = tmp; + tmp.delete(); + message.setDeleted(true); } message.setTransferable(null); mXmppConnectionService.updateMessage(message); diff --git a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java index 08d777e8f3218fdc662f483023c43ab2f339a2b3..f3148143f29a894e5dd04892ff1211c8311ca0ca 100644 --- a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java @@ -756,8 +756,13 @@ public class FileBackend { extension = "oga"; } - setupRelativeFilePath(message, uri, extension); - copyFileToPrivateStorage(mXmppConnectionService.getFileBackend().getFile(message), uri); + try { + setupRelativeFilePath(message, uri, extension); + copyFileToPrivateStorage(mXmppConnectionService.getFileBackend().getFile(message), uri); + } catch (final XmppConnectionService.BlockedMediaException e) { + message.setRelativeFilePath(null); + message.setDeleted(true); + } } private String getExtensionFromUri(final Uri uri) { @@ -903,12 +908,17 @@ public class FileBackend { throw new FileCopyException(R.string.error_file_not_found); } catch (final IOException e) { throw new FileCopyException(R.string.error_io_exception); + } catch (final XmppConnectionService.BlockedMediaException e) { + tmp.delete(); + message.setRelativeFilePath(null); + message.setDeleted(true); + return; } tmp.renameTo(getFile(message)); updateFileParams(message, null, false); } - public void setupRelativeFilePath(final Message message, final Uri uri, final String extension) throws FileCopyException { + public void setupRelativeFilePath(final Message message, final Uri uri, final String extension) throws FileCopyException, XmppConnectionService.BlockedMediaException { try { setupRelativeFilePath(message, mXmppConnectionService.getContentResolver().openInputStream(uri), extension); } catch (final FileNotFoundException e) { @@ -926,7 +936,7 @@ public class FileBackend { } } - public void setupRelativeFilePath(final Message message, final InputStream is, final String extension) throws IOException { + public void setupRelativeFilePath(final Message message, final InputStream is, final String extension) throws IOException, XmppConnectionService.BlockedMediaException { message.setRelativeFilePath(getStorageLocation(is, extension).getAbsolutePath()); } @@ -936,7 +946,7 @@ public class FileBackend { setupRelativeFilePath(message, filename, mime); } - public File getStorageLocation(final InputStream is, final String extension) throws IOException { + public File getStorageLocation(final InputStream is, final String extension) throws IOException, XmppConnectionService.BlockedMediaException { final String mime = MimeUtils.guessMimeTypeFromExtension(extension); Cid[] cids = calculateCids(is); @@ -1796,7 +1806,7 @@ public class FileBackend { for (int i = 0; i < cids.length; i++) { mXmppConnectionService.saveCid(cids[i], file); } - } catch (final IOException e) { } + } catch (final IOException | XmppConnectionService.BlockedMediaException e) { } } } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index ae3397565c6de04665b376bf512126fd8e4e9272..13d8846fef4ce022f8f0bb2ebc9cdbd3c3789dba 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -64,6 +64,8 @@ import org.openintents.openpgp.util.OpenPgpApi; import org.openintents.openpgp.util.OpenPgpServiceConnection; import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; import java.security.Security; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; @@ -559,10 +561,22 @@ public class XmppConnectionService extends Service { return this.databaseBackend.getFileForCid(cid); } - public void saveCid(Cid cid, File file) { + public void saveCid(Cid cid, File file) throws BlockedMediaException { + if (this.databaseBackend.isBlockedMedia(cid)) { + throw new BlockedMediaException(); + } this.databaseBackend.saveCid(cid, file); } + public void blockMedia(File f) { + try { + Cid[] cids = getFileBackend().calculateCids(new FileInputStream(f)); + for (Cid cid : cids) { + blockMedia(cid); + } + } catch (final IOException e) { } + } + public void blockMedia(Cid cid) { this.databaseBackend.blockMedia(cid); } @@ -5027,10 +5041,22 @@ public class XmppConnectionService extends Service { sendIqPacket(account, set, null); } + public void evictPreview(File f) { + if (mBitmapCache.remove(f.getAbsolutePath()) != null) { + Log.d(Config.LOGTAG, "deleted cached preview"); + } + if (mDrawableCache.remove(f.getAbsolutePath()) != null) { + Log.d(Config.LOGTAG, "deleted cached preview"); + } + } + public void evictPreview(String uuid) { if (mBitmapCache.remove(uuid) != null) { Log.d(Config.LOGTAG, "deleted cached preview"); } + if (mDrawableCache.remove(uuid) != null) { + Log.d(Config.LOGTAG, "deleted cached preview"); + } } public interface OnMamPreferencesFetched { @@ -5154,4 +5180,6 @@ public class XmppConnectionService extends Service { return Objects.hashCode(id, media, reconnecting); } } + + public static class BlockedMediaException extends Exception { } } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 155de9a48e080b07882672843f295654f4609f5b..9b7eef5cec0c9eae949047483256403e72001fb5 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -1439,6 +1439,7 @@ public class ConversationFragment extends XmppFragment MenuItem saveAsSticker = menu.findItem(R.id.save_as_sticker); MenuItem downloadFile = menu.findItem(R.id.download_file); MenuItem cancelTransmission = menu.findItem(R.id.cancel_transmission); + MenuItem blockMedia = menu.findItem(R.id.block_media); MenuItem deleteFile = menu.findItem(R.id.delete_file); MenuItem showErrorMessage = menu.findItem(R.id.show_error_message); onlyThisThread.setVisible(!conversation.getLockThread() && m.getThread() != null); @@ -1503,6 +1504,7 @@ public class ConversationFragment extends XmppFragment || !path.startsWith("/") || FileBackend.inConversationsDirectory(requireActivity(), path)) { saveAsSticker.setVisible(true); + blockMedia.setVisible(true); deleteFile.setVisible(true); deleteFile.setTitle( activity.getString( @@ -1577,6 +1579,23 @@ public class ConversationFragment extends XmppFragment case R.id.retry_decryption: retryDecryption(selectedMessage); return true; + case R.id.block_media: + new AlertDialog.Builder(activity) + .setTitle(R.string.block_media) + .setMessage("Do you really want to block this media in all messages?") + .setPositiveButton(R.string.yes, (dialog, whichButton) -> { + File f = activity.xmppConnectionService.getFileBackend().getFile(selectedMessage); + activity.xmppConnectionService.blockMedia(f); + if (activity.xmppConnectionService.getFileBackend().deleteFile(selectedMessage)) { + selectedMessage.setDeleted(true); + activity.xmppConnectionService.evictPreview(f); + activity.xmppConnectionService.updateMessage(selectedMessage, false); + activity.onConversationsListItemUpdated(); + refresh(); + } + }) + .setNegativeButton(R.string.no, null).show(); + return true; case R.id.delete_file: deleteFile(selectedMessage); return true; @@ -2038,6 +2057,7 @@ public class ConversationFragment extends XmppFragment if (writeGranted(grantResults, permissions)) { if (activity != null && activity.xmppConnectionService != null) { activity.xmppConnectionService.getBitmapCache().evictAll(); + activity.xmppConnectionService.getDrawableCache().evictAll(); activity.xmppConnectionService.restartFileObserver(); } refresh(); @@ -2385,7 +2405,7 @@ public class ConversationFragment extends XmppFragment (dialog, which) -> { if (activity.xmppConnectionService.getFileBackend().deleteFile(message)) { message.setDeleted(true); - activity.xmppConnectionService.evictPreview(message.getUuid()); + activity.xmppConnectionService.evictPreview(activity.xmppConnectionService.getFileBackend().getFile(message)); activity.xmppConnectionService.updateMessage(message, false); activity.onConversationsListItemUpdated(); refresh(); diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleFileTransferConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleFileTransferConnection.java index 38ef60ccd0a231616d7e77583e1ab5965b8cbc06..1b21966916e0e38aef825f768c32e7a2c6be08a7 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleFileTransferConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleFileTransferConnection.java @@ -38,6 +38,7 @@ import eu.siacs.conversations.entities.TransferablePlaceholder; import eu.siacs.conversations.parser.IqParser; import eu.siacs.conversations.persistance.FileBackend; import eu.siacs.conversations.services.AbstractConnectionManager; +import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.utils.MimeUtils; import eu.siacs.conversations.xml.Element; @@ -138,6 +139,11 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple } catch (final IOException e) { finalFile = file; message.setRelativeFilePath(finalFile.getAbsolutePath()); + } catch (final XmppConnectionService.BlockedMediaException e) { + finalFile = file; + file.delete(); + message.setRelativeFilePath(null); + message.setDeleted(true); } xmppConnectionService.getFileBackend().updateFileParams(message, null, false); diff --git a/src/main/res/menu/message_context.xml b/src/main/res/menu/message_context.xml index b845c444f7c929cd0adaf1d3c10a76288083fe4f..92d1c31fc11e4ea466613f537ca0421114cd439b 100644 --- a/src/main/res/menu/message_context.xml +++ b/src/main/res/menu/message_context.xml @@ -66,6 +66,10 @@ android:id="@+id/cancel_transmission" android:title="@string/cancel_transmission" android:visible="false" /> +