Detailed changes
@@ -12,6 +12,8 @@ import java.util.List;
import java.util.Locale;
import java.util.Set;
+import io.ipfs.cid.Cid;
+
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.services.AvatarService;
@@ -817,6 +819,14 @@ public class MucOptions {
return avatar == null ? null : avatar.getFilename();
}
+ public Cid getAvatarCid() {
+ if (avatar != null) {
+ return avatar.cid();
+ }
+ Avatar avatar = realJid != null ? getAccount().getRoster().getContact(realJid).getAvatar() : null;
+ return avatar == null ? null : avatar.cid();
+ }
+
public Account getAccount() {
return options.getAccount();
}
@@ -274,6 +274,15 @@ public class DatabaseBackend extends SQLiteOpenHelper {
db.execSQL("PRAGMA cheogram.user_version = 5");
}
+ if(cheogramVersion < 6) {
+ db.execSQL(
+ "CREATE TABLE cheogram.blocked_media (" +
+ "cid TEXT NOT NULL PRIMARY KEY" +
+ ")"
+ );
+ db.execSQL("PRAGMA cheogram.user_version = 6");
+ }
+
db.setTransactionSuccessful();
} finally {
db.endTransaction();
@@ -774,6 +783,24 @@ public class DatabaseBackend extends SQLiteOpenHelper {
db.insertWithOnConflict("cheogram.cids", null, cv, SQLiteDatabase.CONFLICT_REPLACE);
}
+ public void blockMedia(Cid cid) {
+ SQLiteDatabase db = this.getWritableDatabase();
+ ContentValues cv = new ContentValues();
+ cv.put("cid", cid.toString());
+ db.insertWithOnConflict("cheogram.blocked_media", null, cv, SQLiteDatabase.CONFLICT_REPLACE);
+ }
+
+ public boolean isBlockedMedia(Cid cid) {
+ SQLiteDatabase db = this.getReadableDatabase();
+ Cursor cursor = db.query("cheogram.blocked_media", new String[]{"count(*)"}, "cid=?", new String[]{cid.toString()}, null, null, null);
+ boolean is = false;
+ if (cursor.moveToNext()) {
+ is = cursor.getInt(0) > 0;
+ }
+ cursor.close();
+ return is;
+ }
+
public void createConversation(Conversation conversation) {
SQLiteDatabase db = this.getWritableDatabase();
db.insert(Conversation.TABLENAME, null, conversation.getContentValues());
@@ -1600,7 +1600,7 @@ public class FileBackend {
return new File(mXmppConnectionService.getFilesDir(), "/avatars/");
}
- private File getAvatarFile(String avatar) {
+ public File getAvatarFile(String avatar) {
return new File(mXmppConnectionService.getCacheDir(), "/avatars/" + avatar);
}
@@ -563,6 +563,10 @@ public class XmppConnectionService extends Service {
this.databaseBackend.saveCid(cid, file);
}
+ public void blockMedia(Cid cid) {
+ this.databaseBackend.blockMedia(cid);
+ }
+
public AvatarService getAvatarService() {
return this.mAvatarService;
}
@@ -3889,6 +3893,11 @@ public class XmppConnectionService extends Service {
}
public void fetchAvatar(Account account, final Avatar avatar, final UiCallback<Avatar> callback) {
+ if (databaseBackend.isBlockedMedia(avatar.cid())) {
+ if (callback != null) callback.error(0, null);
+ return;
+ }
+
final String KEY = generateFetchKey(account, avatar);
synchronized (this.mInProgressAvatarFetches) {
if (mInProgressAvatarFetches.add(KEY)) {
@@ -57,6 +57,7 @@ public final class MucDetailsContextMenuHelper {
MenuItem sendPrivateMessage = menu.findItem(R.id.send_private_message);
if (user != null && user.getRealJid() != null) {
MenuItem showContactDetails = menu.findItem(R.id.action_contact_details);
+ MenuItem blockAvatar = menu.findItem(R.id.action_block_avatar);
MenuItem startConversation = menu.findItem(R.id.start_conversation);
MenuItem giveMembership = menu.findItem(R.id.give_membership);
MenuItem removeMembership = menu.findItem(R.id.remove_membership);
@@ -76,6 +77,9 @@ public final class MucDetailsContextMenuHelper {
if ((contact != null && contact.showInRoster()) || mucOptions.isPrivateAndNonAnonymous()) {
showContactDetails.setVisible(contact == null || !contact.isSelf());
}
+ if (user.getAvatar() != null) {
+ blockAvatar.setVisible(true);
+ }
if ((activity instanceof ConferenceDetailsActivity || activity instanceof MucUsersActivity) && user.getRole() == MucOptions.Role.NONE) {
invite.setVisible(true);
}
@@ -144,6 +148,14 @@ public final class MucDetailsContextMenuHelper {
activity.switchToContactDetails(contact, fingerprint);
}
return true;
+ case R.id.action_block_avatar:
+ activity.xmppConnectionService.getFileBackend().getAvatarFile(user.getAvatar()).delete();
+ activity.xmppConnectionService.blockMedia(user.getAvatarCid());
+ activity.avatarService().clear(user);
+ if (user.getContact() != null) activity.avatarService().clear(user.getContact());
+ user.setAvatar(null);
+ activity.xmppConnectionService.updateConversationUi();
+ return true;
case R.id.start_conversation:
startConversation(user, activity);
return true;
@@ -226,4 +238,4 @@ public final class MucDetailsContextMenuHelper {
activity.switchToConversation(newConversation);
}
}
-}
+}
@@ -2,6 +2,11 @@ package eu.siacs.conversations.xmpp.pep;
import android.util.Base64;
+import java.security.NoSuchAlgorithmException;
+
+import io.ipfs.cid.Cid;
+
+import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.Jid;
@@ -82,6 +87,16 @@ public class Avatar {
}
}
+ public Cid cid() {
+ if (sha1sum == null) return null;
+
+ try {
+ return CryptoHelper.cid(CryptoHelper.hexToBytes(sha1sum), "sha-1");
+ } catch (final NoSuchAlgorithmException e) {
+ return null;
+ }
+ }
+
public static Avatar parsePresence(Element x) {
String hash = x == null ? null : x.findChildContent("photo");
if (hash == null) {
@@ -8,6 +8,10 @@
android:id="@+id/action_contact_details"
android:title="@string/action_contact_details"
android:visible="false" />
+ <item
+ android:id="@+id/action_block_avatar"
+ android:title="Block Avatar"
+ android:visible="false" />
<item
android:id="@+id/invite"
android:title="@string/invite_again"