mark deleted files in database and not query them when querying for media
This commit is contained in:
parent
bec1b6798c
commit
52afcac230
|
@ -209,7 +209,9 @@ public class PgpDecryptionService {
|
||||||
URL url = message.getFileParams().url;
|
URL url = message.getFileParams().url;
|
||||||
mXmppConnectionService.getFileBackend().updateFileParams(message, url);
|
mXmppConnectionService.getFileBackend().updateFileParams(message, url);
|
||||||
message.setEncryption(Message.ENCRYPTION_DECRYPTED);
|
message.setEncryption(Message.ENCRYPTION_DECRYPTED);
|
||||||
inputFile.delete();
|
if (!inputFile.delete()) {
|
||||||
|
Log.w(Config.LOGTAG,"unable to delete pgp encrypted source file "+inputFile.getAbsolutePath());
|
||||||
|
}
|
||||||
mXmppConnectionService.updateMessage(message);
|
mXmppConnectionService.updateMessage(message);
|
||||||
skipNotificationPush = true;
|
skipNotificationPush = true;
|
||||||
mXmppConnectionService.getFileBackend().updateMediaScanner(outputFile, () -> notifyIfPending(message));
|
mXmppConnectionService.getFileBackend().updateMediaScanner(outputFile, () -> notifyIfPending(message));
|
||||||
|
|
|
@ -206,6 +206,19 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean markAsDeleted(final List<String> uuids) {
|
||||||
|
boolean deleted = false;
|
||||||
|
synchronized (this.messages) {
|
||||||
|
for(Message message : this.messages) {
|
||||||
|
if (uuids.contains(message.getUuid())) {
|
||||||
|
message.setDeleted(true);
|
||||||
|
deleted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return deleted;
|
||||||
|
}
|
||||||
|
|
||||||
public void clearMessages() {
|
public void clearMessages() {
|
||||||
synchronized (this.messages) {
|
synchronized (this.messages) {
|
||||||
this.messages.clear();
|
this.messages.clear();
|
||||||
|
|
|
@ -43,8 +43,8 @@ public class IndividualMessage extends Message {
|
||||||
super(conversation);
|
super(conversation);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IndividualMessage(Conversational conversation, String uuid, String conversationUUid, Jid counterpart, Jid trueCounterpart, String body, long timeSent, int encryption, int status, int type, boolean carbon, String remoteMsgId, String relativeFilePath, String serverMsgId, String fingerprint, boolean read, String edited, boolean oob, String errorMessage, Set<ReadByMarker> readByMarkers, boolean markable) {
|
private IndividualMessage(Conversational conversation, String uuid, String conversationUUid, Jid counterpart, Jid trueCounterpart, String body, long timeSent, int encryption, int status, int type, boolean carbon, String remoteMsgId, String relativeFilePath, String serverMsgId, String fingerprint, boolean read, String edited, boolean oob, String errorMessage, Set<ReadByMarker> readByMarkers, boolean markable, boolean deleted) {
|
||||||
super(conversation, uuid, conversationUUid, counterpart, trueCounterpart, body, timeSent, encryption, status, type, carbon, remoteMsgId, relativeFilePath, serverMsgId, fingerprint, read, edited, oob, errorMessage, readByMarkers, markable);
|
super(conversation, uuid, conversationUUid, counterpart, trueCounterpart, body, timeSent, encryption, status, type, carbon, remoteMsgId, relativeFilePath, serverMsgId, fingerprint, read, edited, oob, errorMessage, readByMarkers, markable, deleted);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -115,6 +115,7 @@ public class IndividualMessage extends Message {
|
||||||
cursor.getInt(cursor.getColumnIndex(OOB)) > 0,
|
cursor.getInt(cursor.getColumnIndex(OOB)) > 0,
|
||||||
cursor.getString(cursor.getColumnIndex(ERROR_MESSAGE)),
|
cursor.getString(cursor.getColumnIndex(ERROR_MESSAGE)),
|
||||||
ReadByMarker.fromJsonString(cursor.getString(cursor.getColumnIndex(READ_BY_MARKERS))),
|
ReadByMarker.fromJsonString(cursor.getString(cursor.getColumnIndex(READ_BY_MARKERS))),
|
||||||
cursor.getInt(cursor.getColumnIndex(MARKABLE)) > 0);
|
cursor.getInt(cursor.getColumnIndex(MARKABLE)) > 0,
|
||||||
|
cursor.getInt(cursor.getColumnIndex(DELETED)) > 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,6 +74,7 @@ public class Message extends AbstractEntity {
|
||||||
public static final String ERROR_MESSAGE = "errorMsg";
|
public static final String ERROR_MESSAGE = "errorMsg";
|
||||||
public static final String READ_BY_MARKERS = "readByMarkers";
|
public static final String READ_BY_MARKERS = "readByMarkers";
|
||||||
public static final String MARKABLE = "markable";
|
public static final String MARKABLE = "markable";
|
||||||
|
public static final String DELETED = "deleted";
|
||||||
public static final String ME_COMMAND = "/me ";
|
public static final String ME_COMMAND = "/me ";
|
||||||
|
|
||||||
public static final String ERROR_MESSAGE_CANCELLED = "eu.siacs.conversations.cancelled";
|
public static final String ERROR_MESSAGE_CANCELLED = "eu.siacs.conversations.cancelled";
|
||||||
|
@ -89,6 +90,7 @@ public class Message extends AbstractEntity {
|
||||||
protected int encryption;
|
protected int encryption;
|
||||||
protected int status;
|
protected int status;
|
||||||
protected int type;
|
protected int type;
|
||||||
|
protected boolean deleted = false;
|
||||||
protected boolean carbon = false;
|
protected boolean carbon = false;
|
||||||
protected boolean oob = false;
|
protected boolean oob = false;
|
||||||
protected List<Edited> edits = new ArrayList<>();
|
protected List<Edited> edits = new ArrayList<>();
|
||||||
|
@ -139,6 +141,7 @@ public class Message extends AbstractEntity {
|
||||||
false,
|
false,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
|
false,
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +151,7 @@ public class Message extends AbstractEntity {
|
||||||
final String remoteMsgId, final String relativeFilePath,
|
final String remoteMsgId, final String relativeFilePath,
|
||||||
final String serverMsgId, final String fingerprint, final boolean read,
|
final String serverMsgId, final String fingerprint, final boolean read,
|
||||||
final String edited, final boolean oob, final String errorMessage, final Set<ReadByMarker> readByMarkers,
|
final String edited, final boolean oob, final String errorMessage, final Set<ReadByMarker> readByMarkers,
|
||||||
final boolean markable) {
|
final boolean markable, final boolean deleted) {
|
||||||
this.conversation = conversation;
|
this.conversation = conversation;
|
||||||
this.uuid = uuid;
|
this.uuid = uuid;
|
||||||
this.conversationUuid = conversationUUid;
|
this.conversationUuid = conversationUUid;
|
||||||
|
@ -170,6 +173,7 @@ public class Message extends AbstractEntity {
|
||||||
this.errorMessage = errorMessage;
|
this.errorMessage = errorMessage;
|
||||||
this.readByMarkers = readByMarkers == null ? new HashSet<>() : readByMarkers;
|
this.readByMarkers = readByMarkers == null ? new HashSet<>() : readByMarkers;
|
||||||
this.markable = markable;
|
this.markable = markable;
|
||||||
|
this.deleted = deleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromCursor(Cursor cursor, Conversation conversation) {
|
public static Message fromCursor(Cursor cursor, Conversation conversation) {
|
||||||
|
@ -217,7 +221,8 @@ public class Message extends AbstractEntity {
|
||||||
cursor.getInt(cursor.getColumnIndex(OOB)) > 0,
|
cursor.getInt(cursor.getColumnIndex(OOB)) > 0,
|
||||||
cursor.getString(cursor.getColumnIndex(ERROR_MESSAGE)),
|
cursor.getString(cursor.getColumnIndex(ERROR_MESSAGE)),
|
||||||
ReadByMarker.fromJsonString(cursor.getString(cursor.getColumnIndex(READ_BY_MARKERS))),
|
ReadByMarker.fromJsonString(cursor.getString(cursor.getColumnIndex(READ_BY_MARKERS))),
|
||||||
cursor.getInt(cursor.getColumnIndex(MARKABLE)) > 0);
|
cursor.getInt(cursor.getColumnIndex(MARKABLE)) > 0,
|
||||||
|
cursor.getInt(cursor.getColumnIndex(DELETED)) > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message createStatusMessage(Conversation conversation, String body) {
|
public static Message createStatusMessage(Conversation conversation, String body) {
|
||||||
|
@ -270,6 +275,7 @@ public class Message extends AbstractEntity {
|
||||||
values.put(ERROR_MESSAGE, errorMessage);
|
values.put(ERROR_MESSAGE, errorMessage);
|
||||||
values.put(READ_BY_MARKERS, ReadByMarker.toJson(readByMarkers).toString());
|
values.put(READ_BY_MARKERS, ReadByMarker.toJson(readByMarkers).toString());
|
||||||
values.put(MARKABLE, markable ? 1 : 0);
|
values.put(MARKABLE, markable ? 1 : 0);
|
||||||
|
values.put(DELETED, deleted ? 1 : 0);
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -386,6 +392,14 @@ public class Message extends AbstractEntity {
|
||||||
return this.read;
|
return this.read;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isDeleted() {
|
||||||
|
return this.deleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeleted(boolean deleted) {
|
||||||
|
this.deleted = deleted;
|
||||||
|
}
|
||||||
|
|
||||||
public void markRead() {
|
public void markRead() {
|
||||||
this.read = true;
|
this.read = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,14 +7,12 @@ public interface Transferable {
|
||||||
|
|
||||||
List<String> VALID_IMAGE_EXTENSIONS = Arrays.asList("webp", "jpeg", "jpg", "png", "jpe");
|
List<String> VALID_IMAGE_EXTENSIONS = Arrays.asList("webp", "jpeg", "jpg", "png", "jpe");
|
||||||
List<String> VALID_CRYPTO_EXTENSIONS = Arrays.asList("pgp", "gpg");
|
List<String> VALID_CRYPTO_EXTENSIONS = Arrays.asList("pgp", "gpg");
|
||||||
List<String> WELL_KNOWN_EXTENSIONS = Arrays.asList("pdf","m4a","mp4","3gp","aac","amr","mp3");
|
|
||||||
|
|
||||||
int STATUS_UNKNOWN = 0x200;
|
int STATUS_UNKNOWN = 0x200;
|
||||||
int STATUS_CHECKING = 0x201;
|
int STATUS_CHECKING = 0x201;
|
||||||
int STATUS_FAILED = 0x202;
|
int STATUS_FAILED = 0x202;
|
||||||
int STATUS_OFFER = 0x203;
|
int STATUS_OFFER = 0x203;
|
||||||
int STATUS_DOWNLOADING = 0x204;
|
int STATUS_DOWNLOADING = 0x204;
|
||||||
int STATUS_DELETED = 0x205;
|
|
||||||
int STATUS_OFFER_CHECK_FILESIZE = 0x206;
|
int STATUS_OFFER_CHECK_FILESIZE = 0x206;
|
||||||
int STATUS_UPLOADING = 0x207;
|
int STATUS_UPLOADING = 0x207;
|
||||||
|
|
||||||
|
|
|
@ -131,10 +131,9 @@ public class HttpDownloadConnection implements Transferable {
|
||||||
public void cancel() {
|
public void cancel() {
|
||||||
this.canceled = true;
|
this.canceled = true;
|
||||||
mHttpConnectionManager.finishConnection(this);
|
mHttpConnectionManager.finishConnection(this);
|
||||||
|
message.setTransferable(null);
|
||||||
if (message.isFileOrImage()) {
|
if (message.isFileOrImage()) {
|
||||||
message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_DELETED));
|
message.setDeleted(true);
|
||||||
} else {
|
|
||||||
message.setTransferable(null);
|
|
||||||
}
|
}
|
||||||
mHttpConnectionManager.updateConversationUi(true);
|
mHttpConnectionManager.updateConversationUi(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ import java.security.cert.CertificateException;
|
||||||
import java.security.cert.CertificateFactory;
|
import java.security.cert.CertificateFactory;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
@ -63,7 +64,7 @@ import rocks.xmpp.addr.Jid;
|
||||||
public class DatabaseBackend extends SQLiteOpenHelper {
|
public class DatabaseBackend extends SQLiteOpenHelper {
|
||||||
|
|
||||||
private static final String DATABASE_NAME = "history";
|
private static final String DATABASE_NAME = "history";
|
||||||
private static final int DATABASE_VERSION = 43;
|
private static final int DATABASE_VERSION = 44;
|
||||||
private static DatabaseBackend instance = null;
|
private static DatabaseBackend instance = null;
|
||||||
private static String CREATE_CONTATCS_STATEMENT = "create table "
|
private static String CREATE_CONTATCS_STATEMENT = "create table "
|
||||||
+ Contact.TABLENAME + "(" + Contact.ACCOUNT + " TEXT, "
|
+ Contact.TABLENAME + "(" + Contact.ACCOUNT + " TEXT, "
|
||||||
|
@ -165,6 +166,9 @@ public class DatabaseBackend extends SQLiteOpenHelper {
|
||||||
|
|
||||||
private static String CREATE_MESSAGE_TIME_INDEX = "create INDEX message_time_index ON " + Message.TABLENAME + "(" + Message.TIME_SENT + ")";
|
private static String CREATE_MESSAGE_TIME_INDEX = "create INDEX message_time_index ON " + Message.TABLENAME + "(" + Message.TIME_SENT + ")";
|
||||||
private static String CREATE_MESSAGE_CONVERSATION_INDEX = "create INDEX message_conversation_index ON " + Message.TABLENAME + "(" + Message.CONVERSATION + ")";
|
private static String CREATE_MESSAGE_CONVERSATION_INDEX = "create INDEX message_conversation_index ON " + Message.TABLENAME + "(" + Message.CONVERSATION + ")";
|
||||||
|
private static String CREATE_MESSAGE_DELETED_INDEX = "create index message_deleted_index ON "+ Message.TABLENAME + "(" + Message.DELETED + ")";
|
||||||
|
private static String CREATE_MESSAGE_RELATIVE_FILE_PATH_INDEX = "create INDEX message_file_path_index ON " + Message.TABLENAME + "(" + Message.RELATIVE_FILE_PATH + ")";
|
||||||
|
private static String CREATE_MESSAGE_TYPE_INDEX = "create INDEX message_type_index ON " + Message.TABLENAME + "(" + Message.TYPE + ")";
|
||||||
|
|
||||||
private static String CREATE_MESSAGE_INDEX_TABLE = "CREATE VIRTUAL TABLE messages_index USING FTS4(uuid TEXT PRIMARY KEY, body TEXT)";
|
private static String CREATE_MESSAGE_INDEX_TABLE = "CREATE VIRTUAL TABLE messages_index USING FTS4(uuid TEXT PRIMARY KEY, body TEXT)";
|
||||||
private static String CREATE_MESSAGE_INSERT_TRIGGER = "CREATE TRIGGER after_message_insert AFTER INSERT ON " + Message.TABLENAME + " BEGIN INSERT INTO messages_index (uuid,body) VALUES (new.uuid,new.body); END;";
|
private static String CREATE_MESSAGE_INSERT_TRIGGER = "CREATE TRIGGER after_message_insert AFTER INSERT ON " + Message.TABLENAME + " BEGIN INSERT INTO messages_index (uuid,body) VALUES (new.uuid,new.body); END;";
|
||||||
|
@ -236,12 +240,16 @@ public class DatabaseBackend extends SQLiteOpenHelper {
|
||||||
+ Message.ERROR_MESSAGE + " TEXT,"
|
+ Message.ERROR_MESSAGE + " TEXT,"
|
||||||
+ Message.READ_BY_MARKERS + " TEXT,"
|
+ Message.READ_BY_MARKERS + " TEXT,"
|
||||||
+ Message.MARKABLE + " NUMBER DEFAULT 0,"
|
+ Message.MARKABLE + " NUMBER DEFAULT 0,"
|
||||||
|
+ Message.DELETED + " NUMBER DEFAULT 0,"
|
||||||
+ Message.REMOTE_MSG_ID + " TEXT, FOREIGN KEY("
|
+ Message.REMOTE_MSG_ID + " TEXT, FOREIGN KEY("
|
||||||
+ Message.CONVERSATION + ") REFERENCES "
|
+ Message.CONVERSATION + ") REFERENCES "
|
||||||
+ Conversation.TABLENAME + "(" + Conversation.UUID
|
+ Conversation.TABLENAME + "(" + Conversation.UUID
|
||||||
+ ") ON DELETE CASCADE);");
|
+ ") ON DELETE CASCADE);");
|
||||||
db.execSQL(CREATE_MESSAGE_TIME_INDEX);
|
db.execSQL(CREATE_MESSAGE_TIME_INDEX);
|
||||||
db.execSQL(CREATE_MESSAGE_CONVERSATION_INDEX);
|
db.execSQL(CREATE_MESSAGE_CONVERSATION_INDEX);
|
||||||
|
db.execSQL(CREATE_MESSAGE_DELETED_INDEX);
|
||||||
|
db.execSQL(CREATE_MESSAGE_RELATIVE_FILE_PATH_INDEX);
|
||||||
|
db.execSQL(CREATE_MESSAGE_TYPE_INDEX);
|
||||||
db.execSQL(CREATE_CONTATCS_STATEMENT);
|
db.execSQL(CREATE_CONTATCS_STATEMENT);
|
||||||
db.execSQL(CREATE_DISCOVERY_RESULTS_STATEMENT);
|
db.execSQL(CREATE_DISCOVERY_RESULTS_STATEMENT);
|
||||||
db.execSQL(CREATE_SESSIONS_STATEMENT);
|
db.execSQL(CREATE_SESSIONS_STATEMENT);
|
||||||
|
@ -527,6 +535,13 @@ public class DatabaseBackend extends SQLiteOpenHelper {
|
||||||
+ "=?", new String[]{account.getUuid()});
|
+ "=?", new String[]{account.getUuid()});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (oldVersion < 44 && newVersion >= 44) {
|
||||||
|
db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + Message.DELETED + " NUMBER DEFAULT 0");
|
||||||
|
db.execSQL(CREATE_MESSAGE_DELETED_INDEX);
|
||||||
|
db.execSQL(CREATE_MESSAGE_RELATIVE_FILE_PATH_INDEX);
|
||||||
|
db.execSQL(CREATE_MESSAGE_TYPE_INDEX);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void canonicalizeJids(SQLiteDatabase db) {
|
private void canonicalizeJids(SQLiteDatabase db) {
|
||||||
|
@ -790,9 +805,58 @@ public class DatabaseBackend extends SQLiteOpenHelper {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> markFileAsDeleted(final File file, final boolean internal) {
|
||||||
|
SQLiteDatabase db = this.getReadableDatabase();
|
||||||
|
String selection;
|
||||||
|
String[] selectionArgs;
|
||||||
|
if (internal) {
|
||||||
|
selection = Message.RELATIVE_FILE_PATH+" IN(?,?) and type in (1,2)";
|
||||||
|
selectionArgs = new String[]{file.getAbsolutePath(),file.getName()};
|
||||||
|
} else {
|
||||||
|
selection = Message.RELATIVE_FILE_PATH+"=? and type in (1,2)";
|
||||||
|
selectionArgs = new String[]{file.getAbsolutePath()};
|
||||||
|
}
|
||||||
|
final List<String> uuids = new ArrayList<>();
|
||||||
|
Cursor cursor = db.query(Message.TABLENAME,new String[]{Message.UUID},selection,selectionArgs,null,null,null);
|
||||||
|
while(cursor != null && cursor.moveToNext()) {
|
||||||
|
uuids.add(cursor.getString(0));
|
||||||
|
}
|
||||||
|
if (cursor != null) {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
markFileAsDeleted(uuids);
|
||||||
|
return uuids;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void markFileAsDeleted(List<String> uuids) {
|
||||||
|
SQLiteDatabase db = this.getReadableDatabase();
|
||||||
|
final ContentValues contentValues = new ContentValues();
|
||||||
|
final String where = Message.UUID+"=?";
|
||||||
|
contentValues.put(Message.DELETED,1);
|
||||||
|
db.beginTransaction();
|
||||||
|
for(String uuid : uuids) {
|
||||||
|
db.update(Message.TABLENAME, contentValues, where, new String[]{uuid});
|
||||||
|
}
|
||||||
|
db.setTransactionSuccessful();
|
||||||
|
db.endTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<FilePath> getAllNonDeletedFilePath() {
|
||||||
|
final SQLiteDatabase db = this.getReadableDatabase();
|
||||||
|
final Cursor cursor = db.query(Message.TABLENAME,new String[]{Message.UUID,Message.RELATIVE_FILE_PATH},"type in (1,2) and deleted=0",null,null,null,null);
|
||||||
|
final List<FilePath> list = new ArrayList<>();
|
||||||
|
while (cursor != null && cursor.moveToNext()) {
|
||||||
|
list.add(new FilePath(cursor.getString(0),cursor.getString(1)));
|
||||||
|
}
|
||||||
|
if (cursor != null) {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
public List<FilePath> getRelativeFilePaths(String account, Jid jid, int limit) {
|
public List<FilePath> getRelativeFilePaths(String account, Jid jid, int limit) {
|
||||||
SQLiteDatabase db = this.getReadableDatabase();
|
SQLiteDatabase db = this.getReadableDatabase();
|
||||||
final String SQL = "select uuid,relativeFilePath from messages where type in (1,2) and conversationUuid=(select uuid from conversations where accountUuid=? and (contactJid=? or contactJid like ?)) order by timeSent desc";
|
final String SQL = "select uuid,relativeFilePath from messages where type in (1,2) and deleted=0 and conversationUuid=(select uuid from conversations where accountUuid=? and (contactJid=? or contactJid like ?)) order by timeSent desc";
|
||||||
final String[] args = {account, jid.toEscapedString(), jid.toEscapedString()+"/%"};
|
final String[] args = {account, jid.toEscapedString(), jid.toEscapedString()+"/%"};
|
||||||
Cursor cursor = db.rawQuery(SQL+(limit > 0 ? " limit "+String.valueOf(limit) : ""), args);
|
Cursor cursor = db.rawQuery(SQL+(limit > 0 ? " limit "+String.valueOf(limit) : ""), args);
|
||||||
List<FilePath> filesPaths = new ArrayList<>();
|
List<FilePath> filesPaths = new ArrayList<>();
|
||||||
|
|
|
@ -473,6 +473,10 @@ public class FileBackend {
|
||||||
return getFile(message, true);
|
return getFile(message, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DownloadableFile getFileForPath(String path) {
|
||||||
|
return getFileForPath(path,MimeUtils.guessMimeTypeFromExtension(MimeUtils.extractRelevantExtension(path)));
|
||||||
|
}
|
||||||
|
|
||||||
public DownloadableFile getFileForPath(String path, String mime) {
|
public DownloadableFile getFileForPath(String path, String mime) {
|
||||||
final DownloadableFile file;
|
final DownloadableFile file;
|
||||||
if (path.startsWith("/")) {
|
if (path.startsWith("/")) {
|
||||||
|
@ -489,6 +493,11 @@ public class FileBackend {
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isInternalFile(final File file) {
|
||||||
|
final File internalFile = getFileForPath(file.getName());
|
||||||
|
return file.getAbsolutePath().equals(internalFile.getAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
public DownloadableFile getFile(Message message, boolean decrypted) {
|
public DownloadableFile getFile(Message message, boolean decrypted) {
|
||||||
final boolean encrypted = !decrypted
|
final boolean encrypted = !decrypted
|
||||||
&& (message.getEncryption() == Message.ENCRYPTION_PGP
|
&& (message.getEncryption() == Message.ENCRYPTION_PGP
|
||||||
|
@ -1187,6 +1196,7 @@ public class FileBackend {
|
||||||
body.append("|0|0|").append(getMediaRuntime(file));
|
body.append("|0|0|").append(getMediaRuntime(file));
|
||||||
}
|
}
|
||||||
message.setBody(body.toString());
|
message.setBody(body.toString());
|
||||||
|
message.setDeleted(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMediaRuntime(Uri uri) {
|
public int getMediaRuntime(Uri uri) {
|
||||||
|
|
|
@ -726,6 +726,7 @@ public class NotificationService {
|
||||||
private static boolean isImageMessage(Message message) {
|
private static boolean isImageMessage(Message message) {
|
||||||
return message.getType() != Message.TYPE_TEXT
|
return message.getType() != Message.TYPE_TEXT
|
||||||
&& message.getTransferable() == null
|
&& message.getTransferable() == null
|
||||||
|
&& !message.isDeleted()
|
||||||
&& message.getEncryption() != Message.ENCRYPTION_PGP
|
&& message.getEncryption() != Message.ENCRYPTION_PGP
|
||||||
&& message.getFileParams().height > 0;
|
&& message.getFileParams().height > 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@ import org.openintents.openpgp.IOpenPgpService2;
|
||||||
import org.openintents.openpgp.util.OpenPgpApi;
|
import org.openintents.openpgp.util.OpenPgpApi;
|
||||||
import org.openintents.openpgp.util.OpenPgpServiceConnection;
|
import org.openintents.openpgp.util.OpenPgpServiceConnection;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.security.Security;
|
import java.security.Security;
|
||||||
|
@ -84,7 +85,6 @@ import eu.siacs.conversations.entities.Bookmark;
|
||||||
import eu.siacs.conversations.entities.Contact;
|
import eu.siacs.conversations.entities.Contact;
|
||||||
import eu.siacs.conversations.entities.Conversation;
|
import eu.siacs.conversations.entities.Conversation;
|
||||||
import eu.siacs.conversations.entities.Conversational;
|
import eu.siacs.conversations.entities.Conversational;
|
||||||
import eu.siacs.conversations.entities.DownloadableFile;
|
|
||||||
import eu.siacs.conversations.entities.Message;
|
import eu.siacs.conversations.entities.Message;
|
||||||
import eu.siacs.conversations.entities.MucOptions;
|
import eu.siacs.conversations.entities.MucOptions;
|
||||||
import eu.siacs.conversations.entities.MucOptions.OnRenameListener;
|
import eu.siacs.conversations.entities.MucOptions.OnRenameListener;
|
||||||
|
@ -92,8 +92,6 @@ import eu.siacs.conversations.entities.Presence;
|
||||||
import eu.siacs.conversations.entities.PresenceTemplate;
|
import eu.siacs.conversations.entities.PresenceTemplate;
|
||||||
import eu.siacs.conversations.entities.Roster;
|
import eu.siacs.conversations.entities.Roster;
|
||||||
import eu.siacs.conversations.entities.ServiceDiscoveryResult;
|
import eu.siacs.conversations.entities.ServiceDiscoveryResult;
|
||||||
import eu.siacs.conversations.entities.Transferable;
|
|
||||||
import eu.siacs.conversations.entities.TransferablePlaceholder;
|
|
||||||
import eu.siacs.conversations.generator.AbstractGenerator;
|
import eu.siacs.conversations.generator.AbstractGenerator;
|
||||||
import eu.siacs.conversations.generator.IqGenerator;
|
import eu.siacs.conversations.generator.IqGenerator;
|
||||||
import eu.siacs.conversations.generator.MessageGenerator;
|
import eu.siacs.conversations.generator.MessageGenerator;
|
||||||
|
@ -235,7 +233,6 @@ public class XmppConnectionService extends Service {
|
||||||
) {
|
) {
|
||||||
@Override
|
@Override
|
||||||
public void onEvent(int event, String path) {
|
public void onEvent(int event, String path) {
|
||||||
Log.d(Config.LOGTAG,"event "+event+" path="+path);
|
|
||||||
markFileDeleted(path);
|
markFileDeleted(path);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1010,6 +1007,7 @@ public class XmppConnectionService extends Service {
|
||||||
if (Compatibility.hasStoragePermission(this)) {
|
if (Compatibility.hasStoragePermission(this)) {
|
||||||
Log.d(Config.LOGTAG, "starting file observer");
|
Log.d(Config.LOGTAG, "starting file observer");
|
||||||
new Thread(fileObserver::startWatching).start();
|
new Thread(fileObserver::startWatching).start();
|
||||||
|
mFileAddingExecutor.execute(this::checkForDeletedFiles);
|
||||||
}
|
}
|
||||||
if (Config.supportOpenPgp()) {
|
if (Config.supportOpenPgp()) {
|
||||||
this.pgpServiceConnection = new OpenPgpServiceConnection(this, "org.sufficientlysecure.keychain", new OpenPgpServiceConnection.OnBound() {
|
this.pgpServiceConnection = new OpenPgpServiceConnection(this, "org.sufficientlysecure.keychain", new OpenPgpServiceConnection.OnBound() {
|
||||||
|
@ -1047,6 +1045,22 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkForDeletedFiles() {
|
||||||
|
final List<String> deletedUuids = new ArrayList<>();
|
||||||
|
final List<DatabaseBackend.FilePath> relativeFilePaths = databaseBackend.getAllNonDeletedFilePath();
|
||||||
|
for(final DatabaseBackend.FilePath filePath : relativeFilePaths) {
|
||||||
|
final File file = fileBackend.getFileForPath(filePath.path);
|
||||||
|
if (!file.exists()) {
|
||||||
|
deletedUuids.add(filePath.uuid.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.d(Config.LOGTAG,"found "+deletedUuids.size()+" deleted files on start up. total="+relativeFilePaths.size());
|
||||||
|
if (deletedUuids.size() > 0) {
|
||||||
|
databaseBackend.markFileAsDeleted(deletedUuids);
|
||||||
|
markUuidsAsDeletedFiles(deletedUuids);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void startContactObserver() {
|
public void startContactObserver() {
|
||||||
getContentResolver().registerContentObserver(ContactsContract.Contacts.CONTENT_URI, true, new ContentObserver(null) {
|
getContentResolver().registerContentObserver(ContactsContract.Contacts.CONTENT_URI, true, new ContentObserver(null) {
|
||||||
@Override
|
@Override
|
||||||
|
@ -1081,6 +1095,7 @@ public class XmppConnectionService extends Service {
|
||||||
|
|
||||||
public void restartFileObserver() {
|
public void restartFileObserver() {
|
||||||
Log.d(Config.LOGTAG, "restarting file observer");
|
Log.d(Config.LOGTAG, "restarting file observer");
|
||||||
|
mFileAddingExecutor.execute(this::checkForDeletedFiles);
|
||||||
new Thread(fileObserver::restartWatching).start();
|
new Thread(fileObserver::restartWatching).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1575,7 +1590,6 @@ public class XmppConnectionService extends Service {
|
||||||
|
|
||||||
private void restoreMessages(Conversation conversation) {
|
private void restoreMessages(Conversation conversation) {
|
||||||
conversation.addAll(0, databaseBackend.getMessages(conversation, Config.PAGE_SIZE));
|
conversation.addAll(0, databaseBackend.getMessages(conversation, Config.PAGE_SIZE));
|
||||||
checkDeletedFiles(conversation);
|
|
||||||
conversation.findUnsentTextMessages(message -> markMessage(message, Message.STATUS_WAITING));
|
conversation.findUnsentTextMessages(message -> markMessage(message, Message.STATUS_WAITING));
|
||||||
conversation.findUnreadMessages(message -> mNotificationService.pushFromBacklog(message));
|
conversation.findUnreadMessages(message -> mNotificationService.pushFromBacklog(message));
|
||||||
}
|
}
|
||||||
|
@ -1617,39 +1631,23 @@ public class XmppConnectionService extends Service {
|
||||||
return this.conversations;
|
return this.conversations;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkDeletedFiles(Conversation conversation) {
|
private void markFileDeleted(final String path) {
|
||||||
conversation.findMessagesWithFiles(message -> {
|
final File file = new File(path);
|
||||||
if (!getFileBackend().isFileAvailable(message)) {
|
final boolean isInternalFile = fileBackend.isInternalFile(file);
|
||||||
message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_DELETED));
|
final List<String> uuids = databaseBackend.markFileAsDeleted(file, isInternalFile);
|
||||||
final int s = message.getStatus();
|
Log.d(Config.LOGTAG, "deleted file " + path+" internal="+isInternalFile+", database hits="+uuids.size());
|
||||||
if (s == Message.STATUS_WAITING || s == Message.STATUS_OFFERED || s == Message.STATUS_UNSEND) {
|
markUuidsAsDeletedFiles(uuids);
|
||||||
markMessage(message, Message.STATUS_SEND_FAILED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void markFileDeleted(final String path) {
|
private void markUuidsAsDeletedFiles(List<String> uuids) {
|
||||||
Log.d(Config.LOGTAG, "deleted file " + path);
|
boolean deleted = false;
|
||||||
for (Conversation conversation : getConversations()) {
|
for (Conversation conversation : getConversations()) {
|
||||||
conversation.findMessagesWithFiles(message -> {
|
deleted |= conversation.markAsDeleted(uuids);
|
||||||
DownloadableFile file = fileBackend.getFile(message);
|
}
|
||||||
if (file.getAbsolutePath().equals(path)) {
|
if (deleted) {
|
||||||
if (!file.exists()) {
|
updateConversationUi();
|
||||||
message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_DELETED));
|
}
|
||||||
final int s = message.getStatus();
|
}
|
||||||
if (s == Message.STATUS_WAITING || s == Message.STATUS_OFFERED || s == Message.STATUS_UNSEND) {
|
|
||||||
markMessage(message, Message.STATUS_SEND_FAILED);
|
|
||||||
} else {
|
|
||||||
updateConversationUi();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.d(Config.LOGTAG, "found matching message for file " + path + " but file still exists");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void populateWithOrderedConversations(final List<Conversation> list) {
|
public void populateWithOrderedConversations(final List<Conversation> list) {
|
||||||
populateWithOrderedConversations(list, true);
|
populateWithOrderedConversations(list, true);
|
||||||
|
@ -1686,7 +1684,6 @@ public class XmppConnectionService extends Service {
|
||||||
List<Message> messages = databaseBackend.getMessages(conversation, 50, timestamp);
|
List<Message> messages = databaseBackend.getMessages(conversation, 50, timestamp);
|
||||||
if (messages.size() > 0) {
|
if (messages.size() > 0) {
|
||||||
conversation.addAll(0, messages);
|
conversation.addAll(0, messages);
|
||||||
checkDeletedFiles(conversation);
|
|
||||||
callback.onMoreMessagesLoaded(messages.size(), conversation);
|
callback.onMoreMessagesLoaded(messages.size(), conversation);
|
||||||
} else if (conversation.hasMessagesLeftOnServer()
|
} else if (conversation.hasMessagesLeftOnServer()
|
||||||
&& account.isOnlineAndConnected()
|
&& account.isOnlineAndConnected()
|
||||||
|
@ -1835,7 +1832,6 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checkDeletedFiles(c);
|
|
||||||
if (joinAfterCreate) {
|
if (joinAfterCreate) {
|
||||||
joinMuc(c);
|
joinMuc(c);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1059,7 +1059,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final boolean deleted = t != null && t instanceof TransferablePlaceholder;
|
final boolean deleted = m.isDeleted();
|
||||||
final boolean encrypted = m.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED
|
final boolean encrypted = m.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED
|
||||||
|| m.getEncryption() == Message.ENCRYPTION_PGP;
|
|| m.getEncryption() == Message.ENCRYPTION_PGP;
|
||||||
final boolean receiving = m.getStatus() == Message.STATUS_RECEIVED && (t instanceof JingleConnection || t instanceof HttpDownloadConnection);
|
final boolean receiving = m.getStatus() == Message.STATUS_RECEIVED && (t instanceof JingleConnection || t instanceof HttpDownloadConnection);
|
||||||
|
@ -1638,7 +1638,8 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
|
||||||
builder.setMessage(R.string.delete_file_dialog_msg);
|
builder.setMessage(R.string.delete_file_dialog_msg);
|
||||||
builder.setPositiveButton(R.string.confirm, (dialog, which) -> {
|
builder.setPositiveButton(R.string.confirm, (dialog, which) -> {
|
||||||
if (activity.xmppConnectionService.getFileBackend().deleteFile(message)) {
|
if (activity.xmppConnectionService.getFileBackend().deleteFile(message)) {
|
||||||
message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_DELETED));
|
message.setDeleted(true);
|
||||||
|
activity.xmppConnectionService.updateMessage(message, false);
|
||||||
activity.onConversationsListItemUpdated();
|
activity.onConversationsListItemUpdated();
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
@ -1672,7 +1673,9 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(activity, R.string.file_deleted, Toast.LENGTH_SHORT).show();
|
Toast.makeText(activity, R.string.file_deleted, Toast.LENGTH_SHORT).show();
|
||||||
message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_DELETED));
|
//TODO check if we have storage permission
|
||||||
|
message.setDeleted(true);
|
||||||
|
activity.xmppConnectionService.updateMessage(message, false);
|
||||||
activity.onConversationsListItemUpdated();
|
activity.onConversationsListItemUpdated();
|
||||||
refresh();
|
refresh();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -122,7 +122,7 @@ public class ConversationAdapter extends RecyclerView.Adapter<ConversationAdapte
|
||||||
viewHolder.lastMessage.setTypeface(null, Typeface.NORMAL);
|
viewHolder.lastMessage.setTypeface(null, Typeface.NORMAL);
|
||||||
viewHolder.sender.setTypeface(null, Typeface.ITALIC);
|
viewHolder.sender.setTypeface(null, Typeface.ITALIC);
|
||||||
} else {
|
} else {
|
||||||
final boolean fileAvailable = message.getTransferable() == null || message.getTransferable().getStatus() != Transferable.STATUS_DELETED;
|
final boolean fileAvailable = !message.isDeleted();
|
||||||
final boolean showPreviewText;
|
final boolean showPreviewText;
|
||||||
if (fileAvailable && (message.isFileOrImage() || message.treatAsDownloadable() || message.isGeoUri())) {
|
if (fileAvailable && (message.isFileOrImage() || message.treatAsDownloadable() || message.isGeoUri())) {
|
||||||
final int imageResource;
|
final int imageResource;
|
||||||
|
|
|
@ -743,10 +743,10 @@ public class MessageAdapter extends ArrayAdapter<Message> implements CopyTextVie
|
||||||
});
|
});
|
||||||
|
|
||||||
final Transferable transferable = message.getTransferable();
|
final Transferable transferable = message.getTransferable();
|
||||||
if (transferable != null && transferable.getStatus() != Transferable.STATUS_UPLOADING) {
|
if (message.isDeleted() || (transferable != null && transferable.getStatus() != Transferable.STATUS_UPLOADING)) {
|
||||||
if (transferable.getStatus() == Transferable.STATUS_OFFER) {
|
if (transferable != null && transferable.getStatus() == Transferable.STATUS_OFFER) {
|
||||||
displayDownloadableMessage(viewHolder, message, activity.getString(R.string.download_x_file, UIHelper.getFileDescriptionString(activity, message)));
|
displayDownloadableMessage(viewHolder, message, activity.getString(R.string.download_x_file, UIHelper.getFileDescriptionString(activity, message)));
|
||||||
} else if (transferable.getStatus() == Transferable.STATUS_OFFER_CHECK_FILESIZE) {
|
} else if (transferable != null && transferable.getStatus() == Transferable.STATUS_OFFER_CHECK_FILESIZE) {
|
||||||
displayDownloadableMessage(viewHolder, message, activity.getString(R.string.check_x_filesize, UIHelper.getFileDescriptionString(activity, message)));
|
displayDownloadableMessage(viewHolder, message, activity.getString(R.string.check_x_filesize, UIHelper.getFileDescriptionString(activity, message)));
|
||||||
} else {
|
} else {
|
||||||
displayInfoMessage(viewHolder, UIHelper.getMessagePreview(activity, message).first, darkBackground);
|
displayInfoMessage(viewHolder, UIHelper.getMessagePreview(activity, message).first, darkBackground);
|
||||||
|
|
|
@ -271,8 +271,6 @@ public class UIHelper {
|
||||||
case Transferable.STATUS_OFFER_CHECK_FILESIZE:
|
case Transferable.STATUS_OFFER_CHECK_FILESIZE:
|
||||||
return new Pair<>(context.getString(R.string.x_file_offered_for_download,
|
return new Pair<>(context.getString(R.string.x_file_offered_for_download,
|
||||||
getFileDescriptionString(context, message)), true);
|
getFileDescriptionString(context, message)), true);
|
||||||
case Transferable.STATUS_DELETED:
|
|
||||||
return new Pair<>(context.getString(R.string.file_deleted), true);
|
|
||||||
case Transferable.STATUS_FAILED:
|
case Transferable.STATUS_FAILED:
|
||||||
return new Pair<>(context.getString(R.string.file_transmission_failed), true);
|
return new Pair<>(context.getString(R.string.file_transmission_failed), true);
|
||||||
case Transferable.STATUS_UPLOADING:
|
case Transferable.STATUS_UPLOADING:
|
||||||
|
@ -286,6 +284,8 @@ public class UIHelper {
|
||||||
default:
|
default:
|
||||||
return new Pair<>("", false);
|
return new Pair<>("", false);
|
||||||
}
|
}
|
||||||
|
} else if (message.isFileOrImage() && message.isDeleted()) {
|
||||||
|
return new Pair<>(context.getString(R.string.file_deleted), true);
|
||||||
} else if (message.getEncryption() == Message.ENCRYPTION_PGP) {
|
} else if (message.getEncryption() == Message.ENCRYPTION_PGP) {
|
||||||
return new Pair<>(context.getString(R.string.pgp_message), true);
|
return new Pair<>(context.getString(R.string.pgp_message), true);
|
||||||
} else if (message.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) {
|
} else if (message.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) {
|
||||||
|
@ -294,7 +294,7 @@ public class UIHelper {
|
||||||
return new Pair<>(context.getString(R.string.not_encrypted_for_this_device), true);
|
return new Pair<>(context.getString(R.string.not_encrypted_for_this_device), true);
|
||||||
} else if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL_FAILED) {
|
} else if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL_FAILED) {
|
||||||
return new Pair<>(context.getString(R.string.omemo_decryption_failed), true);
|
return new Pair<>(context.getString(R.string.omemo_decryption_failed), true);
|
||||||
} else if (message.getType() == Message.TYPE_FILE || message.getType() == Message.TYPE_IMAGE) {
|
} else if (message.isFileOrImage()) {
|
||||||
return new Pair<>(getFileDescriptionString(context, message), true);
|
return new Pair<>(getFileDescriptionString(context, message), true);
|
||||||
} else {
|
} else {
|
||||||
final String body = MessageUtils.filterLtrRtl(message.getBody());
|
final String body = MessageUtils.filterLtrRtl(message.getBody());
|
||||||
|
|
Loading…
Reference in a new issue