mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-19 16:19:33 +01:00
Clean up AttachmentTable schema.
This commit is contained in:
committed by
Alex Hart
parent
62b142cdeb
commit
fe39b5e4e2
@@ -31,13 +31,11 @@ abstract class Attachment(
|
||||
@JvmField
|
||||
val cdnNumber: Int,
|
||||
@JvmField
|
||||
val location: String?,
|
||||
val remoteLocation: String?,
|
||||
@JvmField
|
||||
val key: String?,
|
||||
val remoteKey: String?,
|
||||
@JvmField
|
||||
val relay: String?,
|
||||
@JvmField
|
||||
val digest: ByteArray?,
|
||||
val remoteDigest: ByteArray?,
|
||||
@JvmField
|
||||
val incrementalDigest: ByteArray?,
|
||||
@JvmField
|
||||
@@ -79,10 +77,9 @@ abstract class Attachment(
|
||||
size = parcel.readLong(),
|
||||
fileName = parcel.readString(),
|
||||
cdnNumber = parcel.readInt(),
|
||||
location = parcel.readString(),
|
||||
key = parcel.readString(),
|
||||
relay = parcel.readString(),
|
||||
digest = ParcelUtil.readByteArray(parcel),
|
||||
remoteLocation = parcel.readString(),
|
||||
remoteKey = parcel.readString(),
|
||||
remoteDigest = ParcelUtil.readByteArray(parcel),
|
||||
incrementalDigest = ParcelUtil.readByteArray(parcel),
|
||||
fastPreflightId = parcel.readString(),
|
||||
voiceNote = ParcelUtil.readBoolean(parcel),
|
||||
@@ -107,10 +104,9 @@ abstract class Attachment(
|
||||
dest.writeLong(size)
|
||||
dest.writeString(fileName)
|
||||
dest.writeInt(cdnNumber)
|
||||
dest.writeString(location)
|
||||
dest.writeString(key)
|
||||
dest.writeString(relay)
|
||||
ParcelUtil.writeByteArray(dest, digest)
|
||||
dest.writeString(remoteLocation)
|
||||
dest.writeString(remoteKey)
|
||||
ParcelUtil.writeByteArray(dest, remoteDigest)
|
||||
ParcelUtil.writeByteArray(dest, incrementalDigest)
|
||||
dest.writeString(fastPreflightId)
|
||||
ParcelUtil.writeBoolean(dest, voiceNote)
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
package org.thoughtcrime.securesms.attachments;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
public class AttachmentId implements Parcelable {
|
||||
|
||||
@JsonProperty
|
||||
private final long rowId;
|
||||
|
||||
@JsonProperty
|
||||
private final long uniqueId;
|
||||
|
||||
public AttachmentId(@JsonProperty("rowId") long rowId, @JsonProperty("uniqueId") long uniqueId) {
|
||||
this.rowId = rowId;
|
||||
this.uniqueId = uniqueId;
|
||||
}
|
||||
|
||||
private AttachmentId(Parcel in) {
|
||||
this.rowId = in.readLong();
|
||||
this.uniqueId = in.readLong();
|
||||
}
|
||||
|
||||
public long getRowId() {
|
||||
return rowId;
|
||||
}
|
||||
|
||||
public long getUniqueId() {
|
||||
return uniqueId;
|
||||
}
|
||||
|
||||
public String[] toStrings() {
|
||||
return new String[] {String.valueOf(rowId), String.valueOf(uniqueId)};
|
||||
}
|
||||
|
||||
public @NonNull String toString() {
|
||||
return "AttachmentId::(" + rowId + ", " + uniqueId + ")";
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return rowId >= 0 && uniqueId >= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
AttachmentId attachmentId = (AttachmentId)o;
|
||||
|
||||
if (rowId != attachmentId.rowId) return false;
|
||||
return uniqueId == attachmentId.uniqueId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Util.hashCode(rowId, uniqueId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeLong(rowId);
|
||||
dest.writeLong(uniqueId);
|
||||
}
|
||||
|
||||
public static final Creator<AttachmentId> CREATOR = new Creator<AttachmentId>() {
|
||||
@Override
|
||||
public AttachmentId createFromParcel(Parcel in) {
|
||||
return new AttachmentId(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttachmentId[] newArray(int size) {
|
||||
return new AttachmentId[size];
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package org.thoughtcrime.securesms.attachments
|
||||
|
||||
import android.os.Parcelable
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
data class AttachmentId(
|
||||
@JsonProperty("rowId")
|
||||
@JvmField
|
||||
val id: Long
|
||||
) : Parcelable {
|
||||
|
||||
val isValid: Boolean
|
||||
get() = id >= 0
|
||||
|
||||
override fun toString(): String {
|
||||
return "AttachmentId::$id"
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,6 @@ class DatabaseAttachment : Attachment {
|
||||
cdnNumber: Int,
|
||||
location: String?,
|
||||
key: String?,
|
||||
relay: String?,
|
||||
digest: ByteArray?,
|
||||
incrementalDigest: ByteArray?,
|
||||
incrementalMacChunkSize: Int,
|
||||
@@ -61,10 +60,9 @@ class DatabaseAttachment : Attachment {
|
||||
size = size,
|
||||
fileName = fileName,
|
||||
cdnNumber = cdnNumber,
|
||||
location = location,
|
||||
key = key,
|
||||
relay = relay,
|
||||
digest = digest,
|
||||
remoteLocation = location,
|
||||
remoteKey = key,
|
||||
remoteDigest = digest,
|
||||
incrementalDigest = incrementalDigest,
|
||||
fastPreflightId = fastPreflightId,
|
||||
voiceNote = voiceNote,
|
||||
|
||||
@@ -22,7 +22,6 @@ class PointerAttachment : Attachment {
|
||||
cdnNumber: Int,
|
||||
location: String,
|
||||
key: String?,
|
||||
relay: String?,
|
||||
digest: ByteArray?,
|
||||
incrementalDigest: ByteArray?,
|
||||
incrementalMacChunkSize: Int,
|
||||
@@ -42,10 +41,9 @@ class PointerAttachment : Attachment {
|
||||
size = size,
|
||||
fileName = fileName,
|
||||
cdnNumber = cdnNumber,
|
||||
location = location,
|
||||
key = key,
|
||||
relay = relay,
|
||||
digest = digest,
|
||||
remoteLocation = location,
|
||||
remoteKey = key,
|
||||
remoteDigest = digest,
|
||||
incrementalDigest = incrementalDigest,
|
||||
fastPreflightId = fastPreflightId,
|
||||
voiceNote = voiceNote,
|
||||
@@ -103,7 +101,6 @@ class PointerAttachment : Attachment {
|
||||
cdnNumber = pointer.get().asPointer().cdnNumber,
|
||||
location = pointer.get().asPointer().remoteId.toString(),
|
||||
key = encodedKey,
|
||||
relay = null,
|
||||
digest = pointer.get().asPointer().digest.orElse(null),
|
||||
incrementalDigest = pointer.get().asPointer().incrementalDigest.orElse(null),
|
||||
incrementalMacChunkSize = pointer.get().asPointer().incrementalMacChunkSize,
|
||||
@@ -133,7 +130,6 @@ class PointerAttachment : Attachment {
|
||||
cdnNumber = thumbnail?.asPointer()?.cdnNumber ?: 0,
|
||||
location = thumbnail?.asPointer()?.remoteId?.toString() ?: "0",
|
||||
key = if (thumbnail != null && thumbnail.asPointer().key != null) encodeWithPadding(thumbnail.asPointer().key) else null,
|
||||
relay = null,
|
||||
digest = thumbnail?.asPointer()?.digest?.orElse(null),
|
||||
incrementalDigest = thumbnail?.asPointer()?.incrementalDigest?.orElse(null),
|
||||
incrementalMacChunkSize = thumbnail?.asPointer()?.incrementalMacChunkSize ?: 0,
|
||||
@@ -171,7 +167,6 @@ class PointerAttachment : Attachment {
|
||||
cdnNumber = thumbnail?.asPointer()?.cdnNumber ?: 0,
|
||||
location = thumbnail?.asPointer()?.remoteId?.toString() ?: "0",
|
||||
key = if (thumbnail != null && thumbnail.asPointer().key != null) encodeWithPadding(thumbnail.asPointer().key) else null,
|
||||
relay = null,
|
||||
digest = thumbnail?.asPointer()?.digest?.orElse(null),
|
||||
incrementalDigest = thumbnail?.asPointer()?.incrementalDigest?.orElse(null),
|
||||
incrementalMacChunkSize = thumbnail?.asPointer()?.incrementalMacChunkSize ?: 0,
|
||||
|
||||
@@ -18,10 +18,9 @@ class TombstoneAttachment : Attachment {
|
||||
size = 0,
|
||||
fileName = null,
|
||||
cdnNumber = 0,
|
||||
location = null,
|
||||
key = null,
|
||||
relay = null,
|
||||
digest = null,
|
||||
remoteLocation = null,
|
||||
remoteKey = null,
|
||||
remoteDigest = null,
|
||||
incrementalDigest = null,
|
||||
fastPreflightId = null,
|
||||
voiceNote = false,
|
||||
|
||||
@@ -70,10 +70,9 @@ class UriAttachment : Attachment {
|
||||
size = size,
|
||||
fileName = fileName,
|
||||
cdnNumber = 0,
|
||||
location = null,
|
||||
key = null,
|
||||
relay = null,
|
||||
digest = null,
|
||||
remoteLocation = null,
|
||||
remoteKey = null,
|
||||
remoteDigest = null,
|
||||
incrementalDigest = null,
|
||||
fastPreflightId = fastPreflightId,
|
||||
voiceNote = voiceNote,
|
||||
|
||||
@@ -21,7 +21,7 @@ object BackupCountQueries {
|
||||
@get:JvmStatic
|
||||
val attachmentCount: String = """
|
||||
SELECT COUNT(*) FROM ${AttachmentTable.TABLE_NAME}
|
||||
INNER JOIN ${MessageTable.TABLE_NAME} ON ${AttachmentTable.TABLE_NAME}.${AttachmentTable.MMS_ID} = ${MessageTable.TABLE_NAME}.${MessageTable.ID}
|
||||
INNER JOIN ${MessageTable.TABLE_NAME} ON ${AttachmentTable.TABLE_NAME}.${AttachmentTable.MESSAGE_ID} = ${MessageTable.TABLE_NAME}.${MessageTable.ID}
|
||||
WHERE ${MessageTable.TABLE_NAME}.${MessageTable.EXPIRES_IN} <= 0 AND ${MessageTable.TABLE_NAME}.${MessageTable.VIEW_ONCE} <= 0
|
||||
"""
|
||||
}
|
||||
|
||||
@@ -119,8 +119,7 @@ class BackupFrameOutputStream extends FullBackupBase.BackupStream {
|
||||
try {
|
||||
write(outputStream, new BackupFrame.Builder()
|
||||
.attachment(new Attachment.Builder()
|
||||
.rowId(attachmentId.getRowId())
|
||||
.attachmentId(attachmentId.getUniqueId())
|
||||
.rowId(attachmentId.id)
|
||||
.length(Util.toIntExact(size))
|
||||
.build())
|
||||
.build());
|
||||
|
||||
@@ -167,7 +167,7 @@ public class FullBackupExporter extends FullBackupBase {
|
||||
} else if (table.equals(GroupReceiptTable.TABLE_NAME)) {
|
||||
count = exportTable(table, input, outputStream, cursor -> isForNonExpiringMmsMessage(input, cursor.getLong(cursor.getColumnIndexOrThrow(GroupReceiptTable.MMS_ID))), null, count, estimatedCount, cancellationSignal);
|
||||
} else if (table.equals(AttachmentTable.TABLE_NAME)) {
|
||||
count = exportTable(table, input, outputStream, cursor -> isForNonExpiringMmsMessage(input, cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentTable.MMS_ID))), (cursor, innerCount) -> exportAttachment(attachmentSecret, cursor, outputStream, innerCount, estimatedCount), count, estimatedCount, cancellationSignal);
|
||||
count = exportTable(table, input, outputStream, cursor -> isForNonExpiringMmsMessage(input, cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentTable.MESSAGE_ID))), (cursor, innerCount) -> exportAttachment(attachmentSecret, cursor, outputStream, innerCount, estimatedCount), count, estimatedCount, cancellationSignal);
|
||||
} else if (table.equals(StickerTable.TABLE_NAME)) {
|
||||
count = exportTable(table, input, outputStream, cursor -> true, (cursor, innerCount) -> exportSticker(attachmentSecret, cursor, outputStream, innerCount, estimatedCount), count, estimatedCount, cancellationSignal);
|
||||
} else if (!TABLE_CONTENT_BLOCKLIST.contains(table)) {
|
||||
@@ -444,11 +444,10 @@ public class FullBackupExporter extends FullBackupBase {
|
||||
long estimatedCount)
|
||||
throws IOException
|
||||
{
|
||||
long rowId = cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentTable.ROW_ID));
|
||||
long uniqueId = cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentTable.UNIQUE_ID));
|
||||
long size = cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentTable.SIZE));
|
||||
long rowId = cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentTable.ID));
|
||||
long size = cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentTable.DATA_SIZE));
|
||||
|
||||
String data = cursor.getString(cursor.getColumnIndexOrThrow(AttachmentTable.DATA));
|
||||
String data = cursor.getString(cursor.getColumnIndexOrThrow(AttachmentTable.DATA_FILE));
|
||||
byte[] random = cursor.getBlob(cursor.getColumnIndexOrThrow(AttachmentTable.DATA_RANDOM));
|
||||
|
||||
if (!TextUtils.isEmpty(data)) {
|
||||
@@ -457,14 +456,14 @@ public class FullBackupExporter extends FullBackupBase {
|
||||
|
||||
if (size <= 0 || fileLength != dbLength) {
|
||||
size = calculateVeryOldStreamLength(attachmentSecret, random, data);
|
||||
Log.w(TAG, "Needed size calculation! Manual: " + size + " File: " + fileLength + " DB: " + dbLength + " ID: " + new AttachmentId(rowId, uniqueId));
|
||||
Log.w(TAG, "Needed size calculation! Manual: " + size + " File: " + fileLength + " DB: " + dbLength + " ID: " + new AttachmentId(rowId));
|
||||
}
|
||||
}
|
||||
|
||||
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count, estimatedCount));
|
||||
if (!TextUtils.isEmpty(data) && size > 0) {
|
||||
try (InputStream inputStream = openAttachmentStream(attachmentSecret, random, data)) {
|
||||
outputStream.write(new AttachmentId(rowId, uniqueId), inputStream, size);
|
||||
outputStream.write(new AttachmentId(rowId), inputStream, size);
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.w(TAG, "Missing attachment", e);
|
||||
}
|
||||
|
||||
@@ -202,18 +202,18 @@ public class FullBackupImporter extends FullBackupBase {
|
||||
try {
|
||||
inputStream.readAttachmentTo(output.second, attachment.length);
|
||||
|
||||
contentValues.put(AttachmentTable.DATA, dataFile.getAbsolutePath());
|
||||
contentValues.put(AttachmentTable.DATA_FILE, dataFile.getAbsolutePath());
|
||||
contentValues.put(AttachmentTable.DATA_RANDOM, output.first);
|
||||
} catch (BackupRecordInputStream.BadMacException e) {
|
||||
Log.w(TAG, "Bad MAC for attachment " + attachment.attachmentId + "! Can't restore it.", e);
|
||||
dataFile.delete();
|
||||
contentValues.put(AttachmentTable.DATA, (String) null);
|
||||
contentValues.put(AttachmentTable.DATA_FILE, (String) null);
|
||||
contentValues.put(AttachmentTable.DATA_RANDOM, (String) null);
|
||||
}
|
||||
|
||||
db.update(AttachmentTable.TABLE_NAME, contentValues,
|
||||
AttachmentTable.ROW_ID + " = ? AND " + AttachmentTable.UNIQUE_ID + " = ?",
|
||||
new String[] {String.valueOf(attachment.rowId), String.valueOf(attachment.attachmentId)});
|
||||
AttachmentTable.ID + " = ?",
|
||||
new String[] {String.valueOf(attachment.rowId)});
|
||||
}
|
||||
|
||||
private static void processSticker(@NonNull Context context, @NonNull AttachmentSecret attachmentSecret, @NonNull SQLiteDatabase db, @NonNull Sticker sticker, BackupRecordInputStream inputStream)
|
||||
|
||||
@@ -532,8 +532,8 @@ public class ThumbnailView extends FrameLayout {
|
||||
if (Util.equals(slide, other)) {
|
||||
|
||||
if (slide != null && other != null) {
|
||||
byte[] digestLeft = slide.asAttachment().digest;
|
||||
byte[] digestRight = other.asAttachment().digest;
|
||||
byte[] digestLeft = slide.asAttachment().remoteDigest;
|
||||
byte[] digestRight = other.asAttachment().remoteDigest;
|
||||
|
||||
return Arrays.equals(digestLeft, digestRight);
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ sealed class ConversationSettingsViewModel(
|
||||
if (!cleared) {
|
||||
state.copy(
|
||||
sharedMedia = mediaRecords,
|
||||
sharedMediaIds = mediaRecords.mapNotNull { it.attachment?.attachmentId?.rowId },
|
||||
sharedMediaIds = mediaRecords.mapNotNull { it.attachment?.attachmentId?.id },
|
||||
sharedMediaLoaded = true,
|
||||
displayInternalRecipientDetails = repository.isInternalRecipientDetailsEnabled()
|
||||
)
|
||||
|
||||
@@ -102,42 +102,41 @@ class AttachmentTable(
|
||||
companion object {
|
||||
val TAG = Log.tag(AttachmentTable::class.java)
|
||||
|
||||
const val TABLE_NAME = "part"
|
||||
const val ROW_ID = "_id"
|
||||
const val ATTACHMENT_JSON_ALIAS = "attachment_json"
|
||||
const val MMS_ID = "mid"
|
||||
const val CONTENT_TYPE = "ct"
|
||||
const val NAME = "name"
|
||||
const val CONTENT_DISPOSITION = "cd"
|
||||
const val CONTENT_LOCATION = "cl"
|
||||
const val DATA = "_data"
|
||||
const val TRANSFER_STATE = "pending_push"
|
||||
const val TABLE_NAME = "attachment"
|
||||
const val ID = "_id"
|
||||
const val MESSAGE_ID = "message_id"
|
||||
const val CONTENT_TYPE = "content_type"
|
||||
const val REMOTE_KEY = "remote_key"
|
||||
const val REMOTE_LOCATION = "remote_location"
|
||||
const val REMOTE_DIGEST = "remote_digest"
|
||||
const val REMOTE_INCREMENTAL_DIGEST = "remote_incremental_digest"
|
||||
const val REMOTE_INCREMENTAL_DIGEST_CHUNK_SIZE = "remote_incremental_digest_chunk_size"
|
||||
const val CDN_NUMBER = "cdn_number"
|
||||
const val TRANSFER_STATE = "transfer_state"
|
||||
const val TRANSFER_FILE = "transfer_file"
|
||||
const val SIZE = "data_size"
|
||||
const val DATA_FILE = "data_file"
|
||||
const val DATA_SIZE = "data_size"
|
||||
const val DATA_RANDOM = "data_random"
|
||||
const val DATA_HASH = "data_hash"
|
||||
const val FILE_NAME = "file_name"
|
||||
const val UNIQUE_ID = "unique_id"
|
||||
const val DIGEST = "digest"
|
||||
const val FAST_PREFLIGHT_ID = "fast_preflight_id"
|
||||
const val VOICE_NOTE = "voice_note"
|
||||
const val BORDERLESS = "borderless"
|
||||
const val VIDEO_GIF = "video_gif"
|
||||
const val QUOTE = "quote"
|
||||
const val WIDTH = "width"
|
||||
const val HEIGHT = "height"
|
||||
const val CAPTION = "caption"
|
||||
const val STICKER_PACK_ID = "sticker_pack_id"
|
||||
const val STICKER_PACK_KEY = "sticker_pack_key"
|
||||
const val STICKER_ID = "sticker_id"
|
||||
const val STICKER_EMOJI = "sticker_emoji"
|
||||
const val FAST_PREFLIGHT_ID = "fast_preflight_id"
|
||||
const val DATA_RANDOM = "data_random"
|
||||
const val WIDTH = "width"
|
||||
const val HEIGHT = "height"
|
||||
const val CAPTION = "caption"
|
||||
const val DATA_HASH = "data_hash"
|
||||
const val VISUAL_HASH = "blur_hash"
|
||||
const val BLUR_HASH = "blur_hash"
|
||||
const val TRANSFORM_PROPERTIES = "transform_properties"
|
||||
const val DISPLAY_ORDER = "display_order"
|
||||
const val UPLOAD_TIMESTAMP = "upload_timestamp"
|
||||
const val CDN_NUMBER = "cdn_number"
|
||||
const val MAC_DIGEST = "incremental_mac_digest"
|
||||
const val INCREMENTAL_MAC_CHUNK_SIZE = "incremental_mac_chunk_size"
|
||||
|
||||
const val ATTACHMENT_JSON_ALIAS = "attachment_json"
|
||||
|
||||
private const val DIRECTORY = "parts"
|
||||
|
||||
@@ -148,31 +147,28 @@ class AttachmentTable(
|
||||
const val TRANSFER_PROGRESS_PERMANENT_FAILURE = 4
|
||||
const val PREUPLOAD_MESSAGE_ID: Long = -8675309
|
||||
|
||||
private const val PART_ID_WHERE = "$ROW_ID = ? AND $UNIQUE_ID = ?"
|
||||
private const val PART_ID_WHERE_NOT = "$ROW_ID != ? AND $UNIQUE_ID != ?"
|
||||
|
||||
private val PROJECTION = arrayOf(
|
||||
ROW_ID,
|
||||
MMS_ID,
|
||||
ID,
|
||||
MESSAGE_ID,
|
||||
CONTENT_TYPE,
|
||||
NAME,
|
||||
CONTENT_DISPOSITION,
|
||||
REMOTE_KEY,
|
||||
REMOTE_LOCATION,
|
||||
REMOTE_DIGEST,
|
||||
REMOTE_INCREMENTAL_DIGEST,
|
||||
REMOTE_INCREMENTAL_DIGEST_CHUNK_SIZE,
|
||||
CDN_NUMBER,
|
||||
CONTENT_LOCATION,
|
||||
DATA,
|
||||
TRANSFER_STATE,
|
||||
SIZE,
|
||||
TRANSFER_FILE,
|
||||
DATA_FILE,
|
||||
DATA_SIZE,
|
||||
DATA_RANDOM,
|
||||
DATA_HASH,
|
||||
FILE_NAME,
|
||||
UNIQUE_ID,
|
||||
DIGEST,
|
||||
MAC_DIGEST,
|
||||
INCREMENTAL_MAC_CHUNK_SIZE,
|
||||
FAST_PREFLIGHT_ID,
|
||||
VOICE_NOTE,
|
||||
BORDERLESS,
|
||||
VIDEO_GIF,
|
||||
QUOTE,
|
||||
DATA_RANDOM,
|
||||
WIDTH,
|
||||
HEIGHT,
|
||||
CAPTION,
|
||||
@@ -180,40 +176,34 @@ class AttachmentTable(
|
||||
STICKER_PACK_KEY,
|
||||
STICKER_ID,
|
||||
STICKER_EMOJI,
|
||||
DATA_HASH,
|
||||
VISUAL_HASH,
|
||||
BLUR_HASH,
|
||||
TRANSFORM_PROPERTIES,
|
||||
TRANSFER_FILE,
|
||||
DISPLAY_ORDER,
|
||||
UPLOAD_TIMESTAMP
|
||||
)
|
||||
|
||||
const val CREATE_TABLE = """
|
||||
CREATE TABLE $TABLE_NAME (
|
||||
$ROW_ID INTEGER PRIMARY KEY,
|
||||
$MMS_ID INTEGER,
|
||||
seq INTEGER DEFAULT 0,
|
||||
$ID INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
$MESSAGE_ID INTEGER,
|
||||
$CONTENT_TYPE TEXT,
|
||||
$NAME TEXT,
|
||||
chset INTEGER,
|
||||
$CONTENT_DISPOSITION TEXT,
|
||||
fn TEXT,
|
||||
cid TEXT,
|
||||
$CONTENT_LOCATION TEXT,
|
||||
ctt_s INTEGER,
|
||||
ctt_t TEXT,
|
||||
encrypted INTEGER,
|
||||
$REMOTE_KEY TEXT,
|
||||
$REMOTE_LOCATION TEXT,
|
||||
$REMOTE_DIGEST BLOB,
|
||||
$REMOTE_INCREMENTAL_DIGEST BLOB,
|
||||
$REMOTE_INCREMENTAL_DIGEST_CHUNK_SIZE INTEGER DEFAULT 0,
|
||||
$CDN_NUMBER INTEGER DEFAULT 0,
|
||||
$TRANSFER_STATE INTEGER,
|
||||
$DATA TEXT,
|
||||
$SIZE INTEGER,
|
||||
$TRANSFER_FILE TEXT DEFAULT NULL,
|
||||
$DATA_FILE TEXT,
|
||||
$DATA_SIZE INTEGER,
|
||||
$DATA_RANDOM BLOB,
|
||||
$DATA_HASH TEXT DEFAULT NULL,
|
||||
$FILE_NAME TEXT,
|
||||
$UNIQUE_ID INTEGER NOT NULL,
|
||||
$DIGEST BLOB,
|
||||
$FAST_PREFLIGHT_ID TEXT,
|
||||
$VOICE_NOTE INTEGER DEFAULT 0,
|
||||
$BORDERLESS INTEGER DEFAULT 0,
|
||||
$VIDEO_GIF INTEGER DEFAULT 0,
|
||||
$DATA_RANDOM BLOB,
|
||||
$QUOTE INTEGER DEFAULT 0,
|
||||
$WIDTH INTEGER DEFAULT 0,
|
||||
$HEIGHT INTEGER DEFAULT 0,
|
||||
@@ -222,25 +212,20 @@ class AttachmentTable(
|
||||
$STICKER_PACK_KEY DEFAULT NULL,
|
||||
$STICKER_ID INTEGER DEFAULT -1,
|
||||
$STICKER_EMOJI STRING DEFAULT NULL,
|
||||
$DATA_HASH TEXT DEFAULT NULL,
|
||||
$VISUAL_HASH TEXT DEFAULT NULL,
|
||||
$BLUR_HASH TEXT DEFAULT NULL,
|
||||
$TRANSFORM_PROPERTIES TEXT DEFAULT NULL,
|
||||
$TRANSFER_FILE TEXT DEFAULT NULL,
|
||||
$DISPLAY_ORDER INTEGER DEFAULT 0,
|
||||
$UPLOAD_TIMESTAMP INTEGER DEFAULT 0,
|
||||
$CDN_NUMBER INTEGER DEFAULT 0,
|
||||
$MAC_DIGEST BLOB,
|
||||
$INCREMENTAL_MAC_CHUNK_SIZE INTEGER DEFAULT 0
|
||||
$UPLOAD_TIMESTAMP INTEGER DEFAULT 0
|
||||
)
|
||||
"""
|
||||
|
||||
@JvmField
|
||||
val CREATE_INDEXS = arrayOf(
|
||||
"CREATE INDEX IF NOT EXISTS part_mms_id_index ON $TABLE_NAME ($MMS_ID);",
|
||||
"CREATE INDEX IF NOT EXISTS pending_push_index ON $TABLE_NAME ($TRANSFER_STATE);",
|
||||
"CREATE INDEX IF NOT EXISTS part_sticker_pack_id_index ON $TABLE_NAME ($STICKER_PACK_ID);",
|
||||
"CREATE INDEX IF NOT EXISTS part_data_hash_index ON $TABLE_NAME ($DATA_HASH);",
|
||||
"CREATE INDEX IF NOT EXISTS part_data_index ON $TABLE_NAME ($DATA);"
|
||||
"CREATE INDEX IF NOT EXISTS attachment_message_id_index ON $TABLE_NAME ($MESSAGE_ID);",
|
||||
"CREATE INDEX IF NOT EXISTS attachment_transfer_state_index ON $TABLE_NAME ($TRANSFER_STATE);",
|
||||
"CREATE INDEX IF NOT EXISTS attachment_sticker_pack_id_index ON $TABLE_NAME ($STICKER_PACK_ID);",
|
||||
"CREATE INDEX IF NOT EXISTS attachment_data_hash_index ON $TABLE_NAME ($DATA_HASH);",
|
||||
"CREATE INDEX IF NOT EXISTS attachment_data_index ON $TABLE_NAME ($DATA_FILE);"
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@@ -255,7 +240,7 @@ class AttachmentTable(
|
||||
@Throws(IOException::class)
|
||||
fun getAttachmentStream(attachmentId: AttachmentId, offset: Long): InputStream {
|
||||
return try {
|
||||
getDataStream(attachmentId, DATA, offset)
|
||||
getDataStream(attachmentId, DATA_FILE, offset)
|
||||
} catch (e: FileNotFoundException) {
|
||||
throw IOException("No stream for: $attachmentId", e)
|
||||
} ?: throw IOException("No stream for: $attachmentId")
|
||||
@@ -265,7 +250,7 @@ class AttachmentTable(
|
||||
return readableDatabase
|
||||
.select(*PROJECTION)
|
||||
.from(TABLE_NAME)
|
||||
.where(PART_ID_WHERE, attachmentId.toStrings())
|
||||
.where("$ID = ?", attachmentId.id)
|
||||
.run()
|
||||
.readToList { it.readAttachments() }
|
||||
.flatten()
|
||||
@@ -276,8 +261,8 @@ class AttachmentTable(
|
||||
return readableDatabase
|
||||
.select(*PROJECTION)
|
||||
.from(TABLE_NAME)
|
||||
.where("$MMS_ID = ?", mmsId)
|
||||
.orderBy("$UNIQUE_ID ASC, $ROW_ID ASC")
|
||||
.where("$MESSAGE_ID = ?", mmsId)
|
||||
.orderBy("$ID ASC")
|
||||
.run()
|
||||
.readToList { it.readAttachments() }
|
||||
.flatten()
|
||||
@@ -288,13 +273,13 @@ class AttachmentTable(
|
||||
return emptyMap()
|
||||
}
|
||||
|
||||
val query = buildSingleCollectionQuery(MMS_ID, mmsIds)
|
||||
val query = buildSingleCollectionQuery(MESSAGE_ID, mmsIds)
|
||||
|
||||
return readableDatabase
|
||||
.select(*PROJECTION)
|
||||
.from(TABLE_NAME)
|
||||
.where(query.where, query.whereArgs)
|
||||
.orderBy("$UNIQUE_ID ASC, $ROW_ID ASC")
|
||||
.orderBy("$ID ASC")
|
||||
.run()
|
||||
.groupBy { cursor ->
|
||||
val attachment = cursor.readAttachment()
|
||||
@@ -305,7 +290,7 @@ class AttachmentTable(
|
||||
fun hasAttachment(id: AttachmentId): Boolean {
|
||||
return readableDatabase
|
||||
.exists(TABLE_NAME)
|
||||
.where(PART_ID_WHERE, id.toStrings())
|
||||
.where("$ID = ?", id.id)
|
||||
.run()
|
||||
}
|
||||
|
||||
@@ -323,27 +308,24 @@ class AttachmentTable(
|
||||
Log.d(TAG, "[deleteAttachmentsForMessage] mmsId: $mmsId")
|
||||
|
||||
return writableDatabase.withinTransaction { db ->
|
||||
db.select(DATA, CONTENT_TYPE, ROW_ID, UNIQUE_ID)
|
||||
db.select(DATA_FILE, CONTENT_TYPE, ID)
|
||||
.from(TABLE_NAME)
|
||||
.where("$MMS_ID = ?", mmsId)
|
||||
.where("$MESSAGE_ID = ?", mmsId)
|
||||
.run()
|
||||
.forEach { cursor ->
|
||||
val attachmentId = AttachmentId(
|
||||
cursor.requireLong(ROW_ID),
|
||||
cursor.requireLong(UNIQUE_ID)
|
||||
)
|
||||
val attachmentId = AttachmentId(cursor.requireLong(ID))
|
||||
|
||||
ApplicationDependencies.getJobManager().cancelAllInQueue(AttachmentDownloadJob.constructQueueString(attachmentId))
|
||||
|
||||
deleteAttachmentOnDisk(
|
||||
data = cursor.requireString(DATA),
|
||||
data = cursor.requireString(DATA_FILE),
|
||||
contentType = cursor.requireString(CONTENT_TYPE),
|
||||
attachmentId = attachmentId
|
||||
)
|
||||
}
|
||||
|
||||
val deleteCount = db.delete(TABLE_NAME)
|
||||
.where("$MMS_ID = ?", mmsId)
|
||||
.where("$MESSAGE_ID = ?", mmsId)
|
||||
.run()
|
||||
|
||||
notifyAttachmentListeners()
|
||||
@@ -363,18 +345,13 @@ class AttachmentTable(
|
||||
var count = 0
|
||||
|
||||
writableDatabase
|
||||
.select(ROW_ID, UNIQUE_ID)
|
||||
.select(ID)
|
||||
.from(TABLE_NAME)
|
||||
.where("$MMS_ID = ?", PREUPLOAD_MESSAGE_ID)
|
||||
.where("$MESSAGE_ID = ?", PREUPLOAD_MESSAGE_ID)
|
||||
.run()
|
||||
.forEach { cursor ->
|
||||
val id = AttachmentId(
|
||||
cursor.requireLong(ROW_ID),
|
||||
cursor.requireLong(UNIQUE_ID)
|
||||
)
|
||||
|
||||
val id = AttachmentId(cursor.requireLong(ID))
|
||||
deleteAttachment(id)
|
||||
|
||||
count++
|
||||
}
|
||||
|
||||
@@ -385,30 +362,30 @@ class AttachmentTable(
|
||||
Log.d(TAG, "[deleteAttachmentFilesForViewOnceMessage] mmsId: $mmsId")
|
||||
|
||||
writableDatabase.withinTransaction { db ->
|
||||
db.select(DATA, CONTENT_TYPE, ROW_ID, UNIQUE_ID)
|
||||
db.select(DATA_FILE, CONTENT_TYPE, ID)
|
||||
.from(TABLE_NAME)
|
||||
.where("$MMS_ID = ?", mmsId)
|
||||
.where("$MESSAGE_ID = ?", mmsId)
|
||||
.run()
|
||||
.forEach { cursor ->
|
||||
deleteAttachmentOnDisk(
|
||||
data = cursor.requireString(DATA),
|
||||
data = cursor.requireString(DATA_FILE),
|
||||
contentType = cursor.requireString(CONTENT_TYPE),
|
||||
attachmentId = AttachmentId(cursor.requireLong(ROW_ID), cursor.requireLong(UNIQUE_ID))
|
||||
attachmentId = AttachmentId(cursor.requireLong(ID))
|
||||
)
|
||||
}
|
||||
|
||||
db.update(TABLE_NAME)
|
||||
.values(
|
||||
DATA to null,
|
||||
DATA_FILE to null,
|
||||
DATA_RANDOM to null,
|
||||
DATA_HASH to null,
|
||||
FILE_NAME to null,
|
||||
CAPTION to null,
|
||||
SIZE to 0,
|
||||
DATA_SIZE to 0,
|
||||
WIDTH to 0,
|
||||
HEIGHT to 0,
|
||||
TRANSFER_STATE to TRANSFER_PROGRESS_DONE,
|
||||
VISUAL_HASH to null,
|
||||
BLUR_HASH to null,
|
||||
CONTENT_TYPE to MediaUtil.VIEW_ONCE
|
||||
)
|
||||
.run()
|
||||
@@ -426,9 +403,9 @@ class AttachmentTable(
|
||||
Log.d(TAG, "[deleteAttachment] attachmentId: $id")
|
||||
|
||||
writableDatabase.withinTransaction { db ->
|
||||
db.select(DATA, CONTENT_TYPE)
|
||||
db.select(DATA_FILE, CONTENT_TYPE)
|
||||
.from(TABLE_NAME)
|
||||
.where(PART_ID_WHERE, id.toStrings())
|
||||
.where("$ID = ?", id.id)
|
||||
.run()
|
||||
.use { cursor ->
|
||||
if (!cursor.moveToFirst()) {
|
||||
@@ -436,7 +413,7 @@ class AttachmentTable(
|
||||
return@withinTransaction
|
||||
}
|
||||
|
||||
val data = cursor.requireString(DATA)
|
||||
val data = cursor.requireString(DATA_FILE)
|
||||
val contentType = cursor.requireString(CONTENT_TYPE)
|
||||
|
||||
deleteAttachmentOnDisk(
|
||||
@@ -446,7 +423,7 @@ class AttachmentTable(
|
||||
)
|
||||
|
||||
db.delete(TABLE_NAME)
|
||||
.where(PART_ID_WHERE, id.toStrings())
|
||||
.where("$ID = ?", id.id)
|
||||
.run()
|
||||
|
||||
deleteAttachmentOnDisk(data, contentType, id)
|
||||
@@ -458,7 +435,7 @@ class AttachmentTable(
|
||||
fun trimAllAbandonedAttachments() {
|
||||
val deleteCount = writableDatabase
|
||||
.delete(TABLE_NAME)
|
||||
.where("$MMS_ID != $PREUPLOAD_MESSAGE_ID AND $MMS_ID NOT IN (SELECT ${MessageTable.ID} FROM ${MessageTable.TABLE_NAME})")
|
||||
.where("$MESSAGE_ID != $PREUPLOAD_MESSAGE_ID AND $MESSAGE_ID NOT IN (SELECT ${MessageTable.ID} FROM ${MessageTable.TABLE_NAME})")
|
||||
.run()
|
||||
|
||||
if (deleteCount > 0) {
|
||||
@@ -475,10 +452,10 @@ class AttachmentTable(
|
||||
.toSet()
|
||||
|
||||
val filesInDb: Set<String> = readableDatabase
|
||||
.select(DATA)
|
||||
.select(DATA_FILE)
|
||||
.from(TABLE_NAME)
|
||||
.run()
|
||||
.readToList { it.requireString(DATA) }
|
||||
.readToList { it.requireString(DATA_FILE) }
|
||||
.filterNotNull()
|
||||
.toSet() + stickers.allStickerFiles
|
||||
|
||||
@@ -510,7 +487,7 @@ class AttachmentTable(
|
||||
writableDatabase
|
||||
.update(TABLE_NAME)
|
||||
.values(TRANSFER_STATE to transferState)
|
||||
.where(PART_ID_WHERE, attachmentId.toStrings())
|
||||
.where("$ID = ?", attachmentId.id)
|
||||
.run()
|
||||
|
||||
val threadId = messages.getThreadIdForMessage(messageId)
|
||||
@@ -522,7 +499,7 @@ class AttachmentTable(
|
||||
writableDatabase
|
||||
.update(TABLE_NAME)
|
||||
.values(TRANSFER_STATE to TRANSFER_PROGRESS_FAILED)
|
||||
.where("$PART_ID_WHERE AND $TRANSFER_STATE < $TRANSFER_PROGRESS_PERMANENT_FAILURE", attachmentId.toStrings())
|
||||
.where("$ID = ? AND $TRANSFER_STATE < $TRANSFER_PROGRESS_PERMANENT_FAILURE", attachmentId.id)
|
||||
.run()
|
||||
|
||||
notifyConversationListeners(messages.getThreadIdForMessage(mmsId))
|
||||
@@ -533,7 +510,7 @@ class AttachmentTable(
|
||||
writableDatabase
|
||||
.update(TABLE_NAME)
|
||||
.values(TRANSFER_STATE to TRANSFER_PROGRESS_PERMANENT_FAILURE)
|
||||
.where(PART_ID_WHERE, attachmentId.toStrings())
|
||||
.where("$ID = ?", attachmentId.id)
|
||||
.run()
|
||||
|
||||
notifyConversationListeners(messages.getThreadIdForMessage(mmsId))
|
||||
@@ -542,7 +519,7 @@ class AttachmentTable(
|
||||
@Throws(MmsException::class)
|
||||
fun insertAttachmentsForPlaceholder(mmsId: Long, attachmentId: AttachmentId, inputStream: InputStream) {
|
||||
val placeholder = getAttachment(attachmentId)
|
||||
val oldInfo = getAttachmentDataFileInfo(attachmentId, DATA)
|
||||
val oldInfo = getAttachmentDataFileInfo(attachmentId, DATA_FILE)
|
||||
var dataInfo = storeAttachmentStream(inputStream)
|
||||
val transferFile = getTransferFile(databaseHelper.signalReadableDatabase, attachmentId)
|
||||
|
||||
@@ -554,14 +531,14 @@ class AttachmentTable(
|
||||
}
|
||||
|
||||
val values = ContentValues()
|
||||
values.put(DATA, dataInfo.file.absolutePath)
|
||||
values.put(SIZE, dataInfo.length)
|
||||
values.put(DATA_FILE, dataInfo.file.absolutePath)
|
||||
values.put(DATA_SIZE, dataInfo.length)
|
||||
values.put(DATA_RANDOM, dataInfo.random)
|
||||
values.put(DATA_HASH, dataInfo.hash)
|
||||
|
||||
val visualHashString = placeholder.getVisualHashStringOrNull()
|
||||
if (visualHashString != null) {
|
||||
values.put(VISUAL_HASH, visualHashString)
|
||||
values.put(BLUR_HASH, visualHashString)
|
||||
}
|
||||
|
||||
values.put(TRANSFER_STATE, TRANSFER_PROGRESS_DONE)
|
||||
@@ -570,7 +547,7 @@ class AttachmentTable(
|
||||
|
||||
val updateCount = db.update(TABLE_NAME)
|
||||
.values(values)
|
||||
.where(PART_ID_WHERE, attachmentId.toStrings())
|
||||
.where("$ID = ?", attachmentId.id)
|
||||
.run()
|
||||
|
||||
updateCount > 0
|
||||
@@ -606,32 +583,31 @@ class AttachmentTable(
|
||||
@Throws(MmsException::class)
|
||||
fun copyAttachmentData(sourceId: AttachmentId, destinationId: AttachmentId) {
|
||||
val sourceAttachment = getAttachment(sourceId) ?: throw MmsException("Cannot find attachment for source!")
|
||||
val sourceDataInfo = getAttachmentDataFileInfo(sourceId, DATA) ?: throw MmsException("No attachment data found for source!")
|
||||
val sourceDataInfo = getAttachmentDataFileInfo(sourceId, DATA_FILE) ?: throw MmsException("No attachment data found for source!")
|
||||
|
||||
writableDatabase
|
||||
.update(TABLE_NAME)
|
||||
.values(
|
||||
DATA to sourceDataInfo.file.absolutePath,
|
||||
DATA_FILE to sourceDataInfo.file.absolutePath,
|
||||
DATA_HASH to sourceDataInfo.hash,
|
||||
SIZE to sourceDataInfo.length,
|
||||
DATA_SIZE to sourceDataInfo.length,
|
||||
DATA_RANDOM to sourceDataInfo.random,
|
||||
TRANSFER_STATE to sourceAttachment.transferState,
|
||||
CDN_NUMBER to sourceAttachment.cdnNumber,
|
||||
CONTENT_LOCATION to sourceAttachment.location,
|
||||
DIGEST to sourceAttachment.digest,
|
||||
MAC_DIGEST to sourceAttachment.incrementalDigest,
|
||||
INCREMENTAL_MAC_CHUNK_SIZE to sourceAttachment.incrementalMacChunkSize,
|
||||
CONTENT_DISPOSITION to sourceAttachment.key,
|
||||
NAME to sourceAttachment.relay,
|
||||
SIZE to sourceAttachment.size,
|
||||
REMOTE_LOCATION to sourceAttachment.remoteLocation,
|
||||
REMOTE_DIGEST to sourceAttachment.remoteDigest,
|
||||
REMOTE_INCREMENTAL_DIGEST to sourceAttachment.incrementalDigest,
|
||||
REMOTE_INCREMENTAL_DIGEST_CHUNK_SIZE to sourceAttachment.incrementalMacChunkSize,
|
||||
REMOTE_KEY to sourceAttachment.remoteKey,
|
||||
DATA_SIZE to sourceAttachment.size,
|
||||
FAST_PREFLIGHT_ID to sourceAttachment.fastPreflightId,
|
||||
WIDTH to sourceAttachment.width,
|
||||
HEIGHT to sourceAttachment.height,
|
||||
CONTENT_TYPE to sourceAttachment.contentType,
|
||||
VISUAL_HASH to sourceAttachment.getVisualHashStringOrNull(),
|
||||
BLUR_HASH to sourceAttachment.getVisualHashStringOrNull(),
|
||||
TRANSFORM_PROPERTIES to sourceAttachment.transformProperties?.serialize()
|
||||
)
|
||||
.where(PART_ID_WHERE, destinationId.toStrings())
|
||||
.where("$ID = ?", destinationId.id)
|
||||
.run()
|
||||
}
|
||||
|
||||
@@ -639,7 +615,7 @@ class AttachmentTable(
|
||||
writableDatabase
|
||||
.update(TABLE_NAME)
|
||||
.values(CAPTION to caption)
|
||||
.where(PART_ID_WHERE, id.toStrings())
|
||||
.where("$ID = ?", id.id)
|
||||
.run()
|
||||
}
|
||||
|
||||
@@ -648,26 +624,25 @@ class AttachmentTable(
|
||||
for ((key, value) in orderMap) {
|
||||
db.update(TABLE_NAME)
|
||||
.values(DISPLAY_ORDER to value)
|
||||
.where(PART_ID_WHERE, key.toStrings())
|
||||
.where("$ID = ?", key.id)
|
||||
.run()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updateAttachmentAfterUpload(id: AttachmentId, attachment: Attachment, uploadTimestamp: Long) {
|
||||
val dataInfo = getAttachmentDataFileInfo(id, DATA)
|
||||
val dataInfo = getAttachmentDataFileInfo(id, DATA_FILE)
|
||||
val values = contentValuesOf(
|
||||
TRANSFER_STATE to TRANSFER_PROGRESS_DONE,
|
||||
CDN_NUMBER to attachment.cdnNumber,
|
||||
CONTENT_LOCATION to attachment.location,
|
||||
DIGEST to attachment.digest,
|
||||
MAC_DIGEST to attachment.incrementalDigest,
|
||||
INCREMENTAL_MAC_CHUNK_SIZE to attachment.incrementalMacChunkSize,
|
||||
CONTENT_DISPOSITION to attachment.key,
|
||||
NAME to attachment.relay,
|
||||
SIZE to attachment.size,
|
||||
REMOTE_LOCATION to attachment.remoteLocation,
|
||||
REMOTE_DIGEST to attachment.remoteDigest,
|
||||
REMOTE_INCREMENTAL_DIGEST to attachment.incrementalDigest,
|
||||
REMOTE_INCREMENTAL_DIGEST_CHUNK_SIZE to attachment.incrementalMacChunkSize,
|
||||
REMOTE_KEY to attachment.remoteKey,
|
||||
DATA_SIZE to attachment.size,
|
||||
FAST_PREFLIGHT_ID to attachment.fastPreflightId,
|
||||
VISUAL_HASH to attachment.getVisualHashStringOrNull(),
|
||||
BLUR_HASH to attachment.getVisualHashStringOrNull(),
|
||||
UPLOAD_TIMESTAMP to uploadTimestamp
|
||||
)
|
||||
|
||||
@@ -677,7 +652,7 @@ class AttachmentTable(
|
||||
writableDatabase
|
||||
.update(TABLE_NAME)
|
||||
.values(values)
|
||||
.where(PART_ID_WHERE, id.toStrings())
|
||||
.where("$ID = ?", id.id)
|
||||
.run()
|
||||
}
|
||||
}
|
||||
@@ -696,7 +671,7 @@ class AttachmentTable(
|
||||
fun updateMessageId(attachmentIds: Collection<AttachmentId>, mmsId: Long, isStory: Boolean) {
|
||||
writableDatabase.withinTransaction { db ->
|
||||
val values = ContentValues(2).apply {
|
||||
put(MMS_ID, mmsId)
|
||||
put(MESSAGE_ID, mmsId)
|
||||
if (!isStory) {
|
||||
putNull(CAPTION)
|
||||
}
|
||||
@@ -709,7 +684,7 @@ class AttachmentTable(
|
||||
updatedCount += db
|
||||
.update(TABLE_NAME)
|
||||
.values(values)
|
||||
.where(PART_ID_WHERE, attachmentId.toStrings())
|
||||
.where("$ID = ?", attachmentId.id)
|
||||
.run()
|
||||
}
|
||||
|
||||
@@ -756,7 +731,7 @@ class AttachmentTable(
|
||||
onlyModifyThisAttachment: Boolean
|
||||
) {
|
||||
val attachmentId = databaseAttachment.attachmentId
|
||||
val oldDataInfo = getAttachmentDataFileInfo(attachmentId, DATA) ?: throw MmsException("No attachment data found!")
|
||||
val oldDataInfo = getAttachmentDataFileInfo(attachmentId, DATA_FILE) ?: throw MmsException("No attachment data found!")
|
||||
var destination = oldDataInfo.file
|
||||
val isSingleUseOfData = onlyModifyThisAttachment || oldDataInfo.hash == null
|
||||
|
||||
@@ -771,11 +746,11 @@ class AttachmentTable(
|
||||
dataInfo = deduplicateAttachment(dataInfo, attachmentId, databaseAttachment.transformProperties)
|
||||
|
||||
val contentValues = contentValuesOf(
|
||||
SIZE to dataInfo.length,
|
||||
DATA_SIZE to dataInfo.length,
|
||||
CONTENT_TYPE to mediaStream.mimeType,
|
||||
WIDTH to mediaStream.width,
|
||||
HEIGHT to mediaStream.height,
|
||||
DATA to dataInfo.file.absolutePath,
|
||||
DATA_FILE to dataInfo.file.absolutePath,
|
||||
DATA_RANDOM to dataInfo.random,
|
||||
DATA_HASH to dataInfo.hash
|
||||
)
|
||||
@@ -793,14 +768,14 @@ class AttachmentTable(
|
||||
|
||||
fun duplicateAttachmentsForMessage(destinationMessageId: Long, sourceMessageId: Long, excludedIds: Collection<Long>) {
|
||||
writableDatabase.withinTransaction { db ->
|
||||
db.execSQL("CREATE TEMPORARY TABLE tmp_part AS SELECT * FROM $TABLE_NAME WHERE $MMS_ID = ?", buildArgs(sourceMessageId))
|
||||
db.execSQL("CREATE TEMPORARY TABLE tmp_part AS SELECT * FROM $TABLE_NAME WHERE $MESSAGE_ID = ?", buildArgs(sourceMessageId))
|
||||
|
||||
val queries = buildCollectionQuery(ROW_ID, excludedIds)
|
||||
val queries = buildCollectionQuery(ID, excludedIds)
|
||||
for (query in queries) {
|
||||
db.delete("tmp_part", query.where, query.whereArgs)
|
||||
}
|
||||
|
||||
db.execSQL("UPDATE tmp_part SET $ROW_ID = NULL, $MMS_ID = ?", buildArgs(destinationMessageId))
|
||||
db.execSQL("UPDATE tmp_part SET $ID = NULL, $MESSAGE_ID = ?", buildArgs(destinationMessageId))
|
||||
db.execSQL("INSERT INTO $TABLE_NAME SELECT * FROM tmp_part")
|
||||
db.execSQL("DROP TABLE tmp_part")
|
||||
}
|
||||
@@ -818,7 +793,7 @@ class AttachmentTable(
|
||||
writableDatabase
|
||||
.update(TABLE_NAME)
|
||||
.values(TRANSFER_FILE to transferFile.absolutePath)
|
||||
.where(PART_ID_WHERE, attachmentId.toStrings())
|
||||
.where("$ID = ?", attachmentId.id)
|
||||
.run()
|
||||
|
||||
return transferFile
|
||||
@@ -827,9 +802,9 @@ class AttachmentTable(
|
||||
@VisibleForTesting
|
||||
fun getAttachmentDataFileInfo(attachmentId: AttachmentId, dataType: String): DataInfo? {
|
||||
return readableDatabase
|
||||
.select(dataType, SIZE, DATA_RANDOM, DATA_HASH, TRANSFORM_PROPERTIES)
|
||||
.select(dataType, DATA_SIZE, DATA_RANDOM, DATA_HASH, TRANSFORM_PROPERTIES)
|
||||
.from(TABLE_NAME)
|
||||
.where(PART_ID_WHERE, attachmentId.toStrings())
|
||||
.where("$ID = ?", attachmentId.id)
|
||||
.run()
|
||||
.readToSingleObject { cursor ->
|
||||
if (cursor.isNull(dataType)) {
|
||||
@@ -837,7 +812,7 @@ class AttachmentTable(
|
||||
} else {
|
||||
DataInfo(
|
||||
file = File(cursor.getString(cursor.getColumnIndexOrThrow(dataType))),
|
||||
length = cursor.requireLong(SIZE),
|
||||
length = cursor.requireLong(DATA_SIZE),
|
||||
random = cursor.requireNonNullBlob(DATA_RANDOM),
|
||||
hash = cursor.requireString(DATA_HASH),
|
||||
transformProperties = TransformProperties.parse(cursor.requireString(TRANSFORM_PROPERTIES))
|
||||
@@ -872,14 +847,14 @@ class AttachmentTable(
|
||||
Log.i(TAG, "updating part audio wave form for $attachmentId")
|
||||
writableDatabase
|
||||
.update(TABLE_NAME)
|
||||
.values(VISUAL_HASH to audioWaveForm?.let { AudioHash(it).hash })
|
||||
.where(PART_ID_WHERE, attachmentId.toStrings())
|
||||
.values(BLUR_HASH to audioWaveForm?.let { AudioHash(it).hash })
|
||||
.where("$ID = ?", attachmentId.id)
|
||||
.run()
|
||||
}
|
||||
|
||||
@RequiresApi(23)
|
||||
fun mediaDataSourceFor(attachmentId: AttachmentId, allowReadingFromTempFile: Boolean): MediaDataSource? {
|
||||
val dataInfo = getAttachmentDataFileInfo(attachmentId, DATA)
|
||||
val dataInfo = getAttachmentDataFileInfo(attachmentId, DATA_FILE)
|
||||
if (dataInfo != null) {
|
||||
return EncryptedMediaDataSource.createFor(attachmentSecret, dataInfo.file, dataInfo.random, dataInfo.length)
|
||||
}
|
||||
@@ -903,7 +878,7 @@ class AttachmentTable(
|
||||
return readableDatabase
|
||||
.select(TRANSFORM_PROPERTIES)
|
||||
.from(TABLE_NAME)
|
||||
.where(PART_ID_WHERE, attachmentId.toStrings())
|
||||
.where("$ID = ?", attachmentId.id)
|
||||
.run()
|
||||
.readToSingleObject {
|
||||
TransformProperties.parse(it.requireString(TRANSFORM_PROPERTIES))
|
||||
@@ -914,7 +889,7 @@ class AttachmentTable(
|
||||
writableDatabase
|
||||
.update(TABLE_NAME)
|
||||
.values(TRANSFER_STATE to TRANSFER_PROGRESS_DONE)
|
||||
.where(PART_ID_WHERE, (attachment as DatabaseAttachment).attachmentId.toStrings())
|
||||
.where("$ID = ?", (attachment as DatabaseAttachment).attachmentId.id)
|
||||
.run()
|
||||
|
||||
val threadId = messages.getThreadIdForMessage(messageId)
|
||||
@@ -934,22 +909,21 @@ class AttachmentTable(
|
||||
for (i in 0 until array.length()) {
|
||||
val jsonObject = SaneJSONObject(array.getJSONObject(i))
|
||||
|
||||
if (!jsonObject.isNull(ROW_ID)) {
|
||||
if (!jsonObject.isNull(ID)) {
|
||||
val contentType = jsonObject.getString(CONTENT_TYPE)
|
||||
|
||||
result += DatabaseAttachment(
|
||||
attachmentId = AttachmentId(jsonObject.getLong(ROW_ID), jsonObject.getLong(UNIQUE_ID)),
|
||||
mmsId = jsonObject.getLong(MMS_ID),
|
||||
hasData = !TextUtils.isEmpty(jsonObject.getString(DATA)),
|
||||
attachmentId = AttachmentId(jsonObject.getLong(ID)),
|
||||
mmsId = jsonObject.getLong(MESSAGE_ID),
|
||||
hasData = !TextUtils.isEmpty(jsonObject.getString(DATA_FILE)),
|
||||
hasThumbnail = MediaUtil.isImageType(contentType) || MediaUtil.isVideoType(contentType),
|
||||
contentType = contentType,
|
||||
transferProgress = jsonObject.getInt(TRANSFER_STATE),
|
||||
size = jsonObject.getLong(SIZE),
|
||||
size = jsonObject.getLong(DATA_SIZE),
|
||||
fileName = jsonObject.getString(FILE_NAME),
|
||||
cdnNumber = jsonObject.getInt(CDN_NUMBER),
|
||||
location = jsonObject.getString(CONTENT_LOCATION),
|
||||
key = jsonObject.getString(CONTENT_DISPOSITION),
|
||||
relay = jsonObject.getString(NAME),
|
||||
location = jsonObject.getString(REMOTE_LOCATION),
|
||||
key = jsonObject.getString(REMOTE_KEY),
|
||||
digest = null,
|
||||
incrementalDigest = null,
|
||||
incrementalMacChunkSize = 0,
|
||||
@@ -971,8 +945,8 @@ class AttachmentTable(
|
||||
} else {
|
||||
null
|
||||
},
|
||||
blurHash = if (MediaUtil.isAudioType(contentType)) null else BlurHash.parseOrNull(jsonObject.getString(VISUAL_HASH)),
|
||||
audioHash = if (MediaUtil.isAudioType(contentType)) AudioHash.parseOrNull(jsonObject.getString(VISUAL_HASH)) else null,
|
||||
blurHash = if (MediaUtil.isAudioType(contentType)) null else BlurHash.parseOrNull(jsonObject.getString(BLUR_HASH)),
|
||||
audioHash = if (MediaUtil.isAudioType(contentType)) AudioHash.parseOrNull(jsonObject.getString(BLUR_HASH)) else null,
|
||||
transformProperties = TransformProperties.parse(jsonObject.getString(TRANSFORM_PROPERTIES)),
|
||||
displayOrder = jsonObject.getInt(DISPLAY_ORDER),
|
||||
uploadTimestamp = jsonObject.getLong(UPLOAD_TIMESTAMP)
|
||||
@@ -1043,11 +1017,11 @@ class AttachmentTable(
|
||||
deletedCount += writableDatabase
|
||||
.update(TABLE_NAME)
|
||||
.values(
|
||||
DATA to null,
|
||||
DATA_FILE to null,
|
||||
DATA_RANDOM to null,
|
||||
DATA_HASH to null
|
||||
)
|
||||
.where(PART_ID_WHERE, weakReference.toStrings())
|
||||
.where("$ID = ?", weakReference.id)
|
||||
.run()
|
||||
}
|
||||
|
||||
@@ -1079,13 +1053,13 @@ class AttachmentTable(
|
||||
val quoteRows: MutableList<AttachmentId> = mutableListOf()
|
||||
|
||||
readableDatabase
|
||||
.select(ROW_ID, UNIQUE_ID, QUOTE)
|
||||
.select(ID, QUOTE)
|
||||
.from(TABLE_NAME)
|
||||
.where("$DATA = ? AND $UNIQUE_ID != ? AND $ROW_ID != ?", data, attachmentId.uniqueId, attachmentId.rowId)
|
||||
.where("$DATA_FILE = ? AND $ID != ?", data, attachmentId.id)
|
||||
.run()
|
||||
.forEach { cursor ->
|
||||
if (cursor.requireBoolean(QUOTE)) {
|
||||
quoteRows += AttachmentId(cursor.requireLong(ROW_ID), cursor.requireLong(UNIQUE_ID))
|
||||
quoteRows += AttachmentId(cursor.requireLong(ID))
|
||||
} else {
|
||||
return DataUsageResult.IN_USE
|
||||
}
|
||||
@@ -1104,7 +1078,7 @@ class AttachmentTable(
|
||||
} else {
|
||||
readableDatabase
|
||||
.exists(TABLE_NAME)
|
||||
.where("$DATA = ? AND $DATA_HASH != ?", dataInfo.file.absolutePath, dataInfo.hash)
|
||||
.where("$DATA_FILE = ? AND $DATA_HASH != ?", dataInfo.file.absolutePath, dataInfo.hash)
|
||||
.run()
|
||||
}
|
||||
}
|
||||
@@ -1120,7 +1094,7 @@ class AttachmentTable(
|
||||
|
||||
db.update(TABLE_NAME)
|
||||
.values(
|
||||
DATA to newData.file.absolutePath,
|
||||
DATA_FILE to newData.file.absolutePath,
|
||||
DATA_RANDOM to newData.random,
|
||||
DATA_HASH to newData.hash
|
||||
)
|
||||
@@ -1129,7 +1103,7 @@ class AttachmentTable(
|
||||
}
|
||||
|
||||
private fun updateAttachmentTransformProperties(attachmentId: AttachmentId, transformProperties: TransformProperties) {
|
||||
val dataInfo = getAttachmentDataFileInfo(attachmentId, DATA)
|
||||
val dataInfo = getAttachmentDataFileInfo(attachmentId, DATA_FILE)
|
||||
if (dataInfo == null) {
|
||||
Log.w(TAG, "[updateAttachmentTransformProperties] No data info found!")
|
||||
return
|
||||
@@ -1149,7 +1123,7 @@ class AttachmentTable(
|
||||
return db
|
||||
.update(TABLE_NAME)
|
||||
.values(contentValues)
|
||||
.where("($ROW_ID = ? AND $UNIQUE_ID = ?) OR ($DATA_HASH NOT NULL AND $DATA_HASH = ?)", attachmentId.rowId.toString(), attachmentId.uniqueId.toString(), dataHash.toString())
|
||||
.where("$ID = ? OR ($DATA_HASH NOT NULL AND $DATA_HASH = ?)", attachmentId.id, dataHash.toString())
|
||||
.run()
|
||||
}
|
||||
|
||||
@@ -1161,7 +1135,7 @@ class AttachmentTable(
|
||||
return readableDatabase
|
||||
.select("1")
|
||||
.from(TABLE_NAME)
|
||||
.where("$DATA = ?", file.absolutePath)
|
||||
.where("$DATA_FILE = ?", file.absolutePath)
|
||||
.limit(2)
|
||||
.run()
|
||||
.use { cursor ->
|
||||
@@ -1297,14 +1271,14 @@ class AttachmentTable(
|
||||
val selectorArgs: Pair<String, Array<String>> = buildSharedFileSelectorArgs(hash, excludedAttachmentId)
|
||||
|
||||
return database
|
||||
.select(DATA, DATA_RANDOM, SIZE, TRANSFORM_PROPERTIES)
|
||||
.select(DATA_FILE, DATA_RANDOM, DATA_SIZE, TRANSFORM_PROPERTIES)
|
||||
.from(TABLE_NAME)
|
||||
.where(selectorArgs.first, selectorArgs.second)
|
||||
.run()
|
||||
.readToList { cursor ->
|
||||
DataInfo(
|
||||
file = File(cursor.requireNonNullString(DATA)),
|
||||
length = cursor.requireLong(SIZE),
|
||||
file = File(cursor.requireNonNullString(DATA_FILE)),
|
||||
length = cursor.requireLong(DATA_SIZE),
|
||||
random = cursor.requireNonNullBlob(DATA_RANDOM),
|
||||
hash = hash,
|
||||
transformProperties = TransformProperties.parse(cursor.requireString(TRANSFORM_PROPERTIES))
|
||||
@@ -1316,9 +1290,8 @@ class AttachmentTable(
|
||||
return if (attachmentId == null) {
|
||||
"$DATA_HASH = ?" to arrayOf(newHash)
|
||||
} else {
|
||||
"$PART_ID_WHERE_NOT AND $DATA_HASH = ?" to arrayOf(
|
||||
attachmentId.rowId.toString(),
|
||||
attachmentId.uniqueId.toString(),
|
||||
"$ID != ? AND $DATA_HASH = ?" to arrayOf(
|
||||
attachmentId.id.toString(),
|
||||
newHash
|
||||
)
|
||||
}
|
||||
@@ -1333,7 +1306,6 @@ class AttachmentTable(
|
||||
val attachmentId: AttachmentId = writableDatabase.withinTransaction { db ->
|
||||
try {
|
||||
var dataInfo: DataInfo? = null
|
||||
val uniqueId = System.currentTimeMillis()
|
||||
|
||||
if (attachment.uri != null) {
|
||||
val storeDataInfo = storeAttachmentStream(PartAuthority.getAttachmentStream(context, attachment.uri!!))
|
||||
@@ -1351,7 +1323,7 @@ class AttachmentTable(
|
||||
for (possibleTemplate in possibleTemplates) {
|
||||
useTemplateUpload = possibleTemplate.uploadTimestamp > attachment.uploadTimestamp &&
|
||||
possibleTemplate.transferState == TRANSFER_PROGRESS_DONE &&
|
||||
possibleTemplate.transformProperties?.shouldSkipTransform() == true && possibleTemplate.digest != null &&
|
||||
possibleTemplate.transformProperties?.shouldSkipTransform() == true && possibleTemplate.remoteDigest != null &&
|
||||
attachment.transformProperties?.videoEdited == false && possibleTemplate.transformProperties?.sentMediaQuality == attachment.transformProperties?.sentMediaQuality
|
||||
|
||||
if (useTemplateUpload) {
|
||||
@@ -1363,19 +1335,17 @@ class AttachmentTable(
|
||||
}
|
||||
|
||||
val contentValues = ContentValues()
|
||||
contentValues.put(MMS_ID, mmsId)
|
||||
contentValues.put(MESSAGE_ID, mmsId)
|
||||
contentValues.put(CONTENT_TYPE, template.contentType)
|
||||
contentValues.put(TRANSFER_STATE, attachment.transferState)
|
||||
contentValues.put(UNIQUE_ID, uniqueId)
|
||||
contentValues.put(CDN_NUMBER, if (useTemplateUpload) template.cdnNumber else attachment.cdnNumber)
|
||||
contentValues.put(CONTENT_LOCATION, if (useTemplateUpload) template.location else attachment.location)
|
||||
contentValues.put(DIGEST, if (useTemplateUpload) template.digest else attachment.digest)
|
||||
contentValues.put(MAC_DIGEST, if (useTemplateUpload) template.incrementalDigest else attachment.incrementalDigest)
|
||||
contentValues.put(INCREMENTAL_MAC_CHUNK_SIZE, if (useTemplateUpload) template.incrementalMacChunkSize else attachment.incrementalMacChunkSize)
|
||||
contentValues.put(CONTENT_DISPOSITION, if (useTemplateUpload) template.key else attachment.key)
|
||||
contentValues.put(NAME, if (useTemplateUpload) template.relay else attachment.relay)
|
||||
contentValues.put(REMOTE_LOCATION, if (useTemplateUpload) template.remoteLocation else attachment.remoteLocation)
|
||||
contentValues.put(REMOTE_DIGEST, if (useTemplateUpload) template.remoteDigest else attachment.remoteDigest)
|
||||
contentValues.put(REMOTE_INCREMENTAL_DIGEST, if (useTemplateUpload) template.incrementalDigest else attachment.incrementalDigest)
|
||||
contentValues.put(REMOTE_INCREMENTAL_DIGEST_CHUNK_SIZE, if (useTemplateUpload) template.incrementalMacChunkSize else attachment.incrementalMacChunkSize)
|
||||
contentValues.put(REMOTE_KEY, if (useTemplateUpload) template.remoteKey else attachment.remoteKey)
|
||||
contentValues.put(FILE_NAME, StorageUtil.getCleanFileName(attachment.fileName))
|
||||
contentValues.put(SIZE, template.size)
|
||||
contentValues.put(DATA_SIZE, template.size)
|
||||
contentValues.put(FAST_PREFLIGHT_ID, attachment.fastPreflightId)
|
||||
contentValues.put(VOICE_NOTE, if (attachment.voiceNote) 1 else 0)
|
||||
contentValues.put(BORDERLESS, if (attachment.borderless) 1 else 0)
|
||||
@@ -1387,10 +1357,10 @@ class AttachmentTable(
|
||||
contentValues.put(UPLOAD_TIMESTAMP, if (useTemplateUpload) template.uploadTimestamp else attachment.uploadTimestamp)
|
||||
|
||||
if (attachment.transformProperties?.videoEdited == true) {
|
||||
contentValues.putNull(VISUAL_HASH)
|
||||
contentValues.putNull(BLUR_HASH)
|
||||
contentValues.put(TRANSFORM_PROPERTIES, attachment.transformProperties?.serialize())
|
||||
} else {
|
||||
contentValues.put(VISUAL_HASH, template.getVisualHashStringOrNull())
|
||||
contentValues.put(BLUR_HASH, template.getVisualHashStringOrNull())
|
||||
contentValues.put(TRANSFORM_PROPERTIES, (if (useTemplateUpload) template else attachment).transformProperties?.serialize())
|
||||
}
|
||||
|
||||
@@ -1402,8 +1372,8 @@ class AttachmentTable(
|
||||
}
|
||||
|
||||
if (dataInfo != null) {
|
||||
contentValues.put(DATA, dataInfo.file.absolutePath)
|
||||
contentValues.put(SIZE, dataInfo.length)
|
||||
contentValues.put(DATA_FILE, dataInfo.file.absolutePath)
|
||||
contentValues.put(DATA_SIZE, dataInfo.length)
|
||||
contentValues.put(DATA_RANDOM, dataInfo.random)
|
||||
|
||||
if (attachment.transformProperties?.videoEdited == true) {
|
||||
@@ -1416,7 +1386,7 @@ class AttachmentTable(
|
||||
notifyPacks = attachment.isSticker && !hasStickerAttachments()
|
||||
|
||||
val rowId = db.insert(TABLE_NAME, null, contentValues)
|
||||
AttachmentId(rowId, uniqueId)
|
||||
AttachmentId(rowId)
|
||||
} catch (e: IOException) {
|
||||
throw MmsException(e)
|
||||
}
|
||||
@@ -1447,7 +1417,7 @@ class AttachmentTable(
|
||||
return db
|
||||
.select(TRANSFER_FILE)
|
||||
.from(TABLE_NAME)
|
||||
.where(PART_ID_WHERE, attachmentId.toStrings())
|
||||
.where("$ID = ?", attachmentId.id)
|
||||
.limit(1)
|
||||
.run()
|
||||
.readToSingleObject { cursor ->
|
||||
@@ -1459,21 +1429,20 @@ class AttachmentTable(
|
||||
val contentType = cursor.requireString(CONTENT_TYPE)
|
||||
|
||||
return DatabaseAttachment(
|
||||
attachmentId = AttachmentId(cursor.requireLong(ROW_ID), cursor.requireLong(UNIQUE_ID)),
|
||||
mmsId = cursor.requireLong(MMS_ID),
|
||||
hasData = !cursor.isNull(DATA),
|
||||
attachmentId = AttachmentId(cursor.requireLong(ID)),
|
||||
mmsId = cursor.requireLong(MESSAGE_ID),
|
||||
hasData = !cursor.isNull(DATA_FILE),
|
||||
hasThumbnail = MediaUtil.isImageType(contentType) || MediaUtil.isVideoType(contentType),
|
||||
contentType = contentType,
|
||||
transferProgress = cursor.requireInt(TRANSFER_STATE),
|
||||
size = cursor.requireLong(SIZE),
|
||||
size = cursor.requireLong(DATA_SIZE),
|
||||
fileName = cursor.requireString(FILE_NAME),
|
||||
cdnNumber = cursor.requireInt(CDN_NUMBER),
|
||||
location = cursor.requireString(CONTENT_LOCATION),
|
||||
key = cursor.requireString(CONTENT_DISPOSITION),
|
||||
relay = cursor.requireString(NAME),
|
||||
digest = cursor.requireBlob(DIGEST),
|
||||
incrementalDigest = cursor.requireBlob(MAC_DIGEST),
|
||||
incrementalMacChunkSize = cursor.requireInt(INCREMENTAL_MAC_CHUNK_SIZE),
|
||||
location = cursor.requireString(REMOTE_LOCATION),
|
||||
key = cursor.requireString(REMOTE_KEY),
|
||||
digest = cursor.requireBlob(REMOTE_DIGEST),
|
||||
incrementalDigest = cursor.requireBlob(REMOTE_INCREMENTAL_DIGEST),
|
||||
incrementalMacChunkSize = cursor.requireInt(REMOTE_INCREMENTAL_DIGEST_CHUNK_SIZE),
|
||||
fastPreflightId = cursor.requireString(FAST_PREFLIGHT_ID),
|
||||
voiceNote = cursor.requireBoolean(VOICE_NOTE),
|
||||
borderless = cursor.requireBoolean(BORDERLESS),
|
||||
@@ -1483,8 +1452,8 @@ class AttachmentTable(
|
||||
quote = cursor.requireBoolean(QUOTE),
|
||||
caption = cursor.requireString(CAPTION),
|
||||
stickerLocator = cursor.readStickerLocator(),
|
||||
blurHash = if (MediaUtil.isAudioType(contentType)) null else BlurHash.parseOrNull(cursor.requireString(VISUAL_HASH)),
|
||||
audioHash = if (MediaUtil.isAudioType(contentType)) AudioHash.parseOrNull(cursor.requireString(VISUAL_HASH)) else null,
|
||||
blurHash = if (MediaUtil.isAudioType(contentType)) null else BlurHash.parseOrNull(cursor.requireString(BLUR_HASH)),
|
||||
audioHash = if (MediaUtil.isAudioType(contentType)) AudioHash.parseOrNull(cursor.requireString(BLUR_HASH)) else null,
|
||||
transformProperties = TransformProperties.parse(cursor.requireString(TRANSFORM_PROPERTIES)),
|
||||
displayOrder = cursor.requireInt(DISPLAY_ORDER),
|
||||
uploadTimestamp = cursor.requireLong(UPLOAD_TIMESTAMP)
|
||||
|
||||
@@ -20,18 +20,17 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD
|
||||
private const val THREAD_RECIPIENT_ID = "THREAD_RECIPIENT_ID"
|
||||
private val BASE_MEDIA_QUERY = """
|
||||
SELECT
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.ROW_ID} AS ${AttachmentTable.ROW_ID},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.ID} AS ${AttachmentTable.ID},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.CONTENT_TYPE},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.UNIQUE_ID},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.MMS_ID},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.MESSAGE_ID},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.TRANSFER_STATE},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.SIZE},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.DATA_SIZE},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.FILE_NAME},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.DATA},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.DATA_FILE},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.CDN_NUMBER},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.CONTENT_LOCATION},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.CONTENT_DISPOSITION},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.DIGEST},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.REMOTE_LOCATION},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.REMOTE_KEY},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.REMOTE_DIGEST},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.FAST_PREFLIGHT_ID},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.VOICE_NOTE},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.BORDERLESS},
|
||||
@@ -43,14 +42,13 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.STICKER_PACK_KEY},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.STICKER_ID},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.STICKER_EMOJI},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.VISUAL_HASH},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.BLUR_HASH},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.TRANSFORM_PROPERTIES},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.DISPLAY_ORDER},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.CAPTION},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.NAME},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.UPLOAD_TIMESTAMP},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.MAC_DIGEST},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.INCREMENTAL_MAC_CHUNK_SIZE},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.REMOTE_INCREMENTAL_DIGEST},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.REMOTE_INCREMENTAL_DIGEST_CHUNK_SIZE},
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.TYPE},
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.DATE_SENT},
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.DATE_RECEIVED},
|
||||
@@ -60,10 +58,10 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD
|
||||
${ThreadTable.TABLE_NAME}.${ThreadTable.RECIPIENT_ID} as $THREAD_RECIPIENT_ID
|
||||
FROM
|
||||
${AttachmentTable.TABLE_NAME}
|
||||
LEFT JOIN ${MessageTable.TABLE_NAME} ON ${AttachmentTable.TABLE_NAME}.${AttachmentTable.MMS_ID} = ${MessageTable.TABLE_NAME}.${MessageTable.ID}
|
||||
LEFT JOIN ${MessageTable.TABLE_NAME} ON ${AttachmentTable.TABLE_NAME}.${AttachmentTable.MESSAGE_ID} = ${MessageTable.TABLE_NAME}.${MessageTable.ID}
|
||||
LEFT JOIN ${ThreadTable.TABLE_NAME} ON ${ThreadTable.TABLE_NAME}.${ThreadTable.ID} = ${MessageTable.TABLE_NAME}.${MessageTable.THREAD_ID}
|
||||
WHERE
|
||||
${AttachmentTable.MMS_ID} IN (
|
||||
${AttachmentTable.MESSAGE_ID} IN (
|
||||
SELECT ${MessageTable.ID}
|
||||
FROM ${MessageTable.TABLE_NAME}
|
||||
WHERE ${MessageTable.THREAD_ID} __EQUALITY__ ?
|
||||
@@ -86,20 +84,20 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD
|
||||
|
||||
private val UNIQUE_MEDIA_QUERY = """
|
||||
SELECT
|
||||
MAX(${AttachmentTable.SIZE}) as ${AttachmentTable.SIZE},
|
||||
MAX(${AttachmentTable.DATA_SIZE}) as ${AttachmentTable.DATA_SIZE},
|
||||
${AttachmentTable.CONTENT_TYPE}
|
||||
FROM
|
||||
${AttachmentTable.TABLE_NAME}
|
||||
WHERE
|
||||
${AttachmentTable.STICKER_PACK_ID} IS NULL AND
|
||||
${AttachmentTable.TRANSFER_STATE} = ${AttachmentTable.TRANSFER_PROGRESS_DONE}
|
||||
GROUP BY ${AttachmentTable.DATA}
|
||||
GROUP BY ${AttachmentTable.DATA_FILE}
|
||||
"""
|
||||
|
||||
private val GALLERY_MEDIA_QUERY = String.format(
|
||||
BASE_MEDIA_QUERY,
|
||||
"""
|
||||
${AttachmentTable.DATA} IS NOT NULL AND
|
||||
${AttachmentTable.DATA_FILE} IS NOT NULL AND
|
||||
${AttachmentTable.CONTENT_TYPE} NOT LIKE 'image/svg%' AND
|
||||
(${AttachmentTable.CONTENT_TYPE} LIKE 'image/%' OR ${AttachmentTable.CONTENT_TYPE} LIKE 'video/%')
|
||||
"""
|
||||
@@ -108,7 +106,7 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD
|
||||
private val GALLERY_MEDIA_QUERY_INCLUDING_TEMP_VIDEOS = String.format(
|
||||
BASE_MEDIA_QUERY,
|
||||
"""
|
||||
(${AttachmentTable.DATA} IS NOT NULL OR (${AttachmentTable.CONTENT_TYPE} LIKE 'video/%' AND ${AttachmentTable.MAC_DIGEST} IS NOT NULL)) AND
|
||||
(${AttachmentTable.DATA_FILE} IS NOT NULL OR (${AttachmentTable.CONTENT_TYPE} LIKE 'video/%' AND ${AttachmentTable.REMOTE_INCREMENTAL_DIGEST} IS NOT NULL)) AND
|
||||
${AttachmentTable.CONTENT_TYPE} NOT LIKE 'image/svg%' AND
|
||||
(${AttachmentTable.CONTENT_TYPE} LIKE 'image/%' OR ${AttachmentTable.CONTENT_TYPE} LIKE 'video/%')
|
||||
"""
|
||||
@@ -117,17 +115,17 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD
|
||||
private val AUDIO_MEDIA_QUERY = String.format(
|
||||
BASE_MEDIA_QUERY,
|
||||
"""
|
||||
${AttachmentTable.DATA} IS NOT NULL AND
|
||||
${AttachmentTable.DATA_FILE} IS NOT NULL AND
|
||||
${AttachmentTable.CONTENT_TYPE} LIKE 'audio/%'
|
||||
"""
|
||||
)
|
||||
|
||||
private val ALL_MEDIA_QUERY = String.format(BASE_MEDIA_QUERY, "${AttachmentTable.DATA} IS NOT NULL AND ${AttachmentTable.CONTENT_TYPE} NOT LIKE 'text/x-signal-plain'")
|
||||
private val ALL_MEDIA_QUERY = String.format(BASE_MEDIA_QUERY, "${AttachmentTable.DATA_FILE} IS NOT NULL AND ${AttachmentTable.CONTENT_TYPE} NOT LIKE 'text/x-signal-plain'")
|
||||
|
||||
private val DOCUMENT_MEDIA_QUERY = String.format(
|
||||
BASE_MEDIA_QUERY,
|
||||
"""
|
||||
${AttachmentTable.DATA} IS NOT NULL AND
|
||||
${AttachmentTable.DATA_FILE} IS NOT NULL AND
|
||||
(
|
||||
${AttachmentTable.CONTENT_TYPE} LIKE 'image/svg%' OR
|
||||
(
|
||||
@@ -185,7 +183,7 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD
|
||||
|
||||
readableDatabase.rawQuery(UNIQUE_MEDIA_QUERY, null).use { cursor ->
|
||||
while (cursor.moveToNext()) {
|
||||
val size: Int = cursor.requireInt(AttachmentTable.SIZE)
|
||||
val size: Int = cursor.requireInt(AttachmentTable.DATA_SIZE)
|
||||
val type: String = cursor.requireNonNullString(AttachmentTable.CONTENT_TYPE)
|
||||
|
||||
when (MediaUtil.getSlideTypeFromContentType(type)) {
|
||||
@@ -253,21 +251,21 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD
|
||||
enum class Sorting(order: String) {
|
||||
Newest(
|
||||
"""
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.MMS_ID} DESC,
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.MESSAGE_ID} DESC,
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.DISPLAY_ORDER} DESC,
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.ROW_ID} DESC
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.ID} DESC
|
||||
"""
|
||||
),
|
||||
Oldest(
|
||||
"""
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.MMS_ID} ASC,
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.MESSAGE_ID} ASC,
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.DISPLAY_ORDER} DESC,
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.ROW_ID} ASC
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.ID} ASC
|
||||
"""
|
||||
),
|
||||
Largest(
|
||||
"""
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.SIZE} DESC,
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.DATA_SIZE} DESC,
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.DISPLAY_ORDER} DESC
|
||||
"""
|
||||
);
|
||||
|
||||
@@ -92,13 +92,13 @@ class MessageSendLogTables constructor(context: Context?, databaseHelper: Signal
|
||||
"""
|
||||
CREATE TRIGGER msl_message_delete AFTER DELETE ON ${MessageTable.TABLE_NAME}
|
||||
BEGIN
|
||||
DELETE FROM $TABLE_NAME WHERE $ID IN (SELECT ${MslMessageTable.PAYLOAD_ID} FROM ${MslMessageTable.TABLE_NAME} WHERE ${MslMessageTable.MESSAGE_ID} = old.${MessageTable.ID});
|
||||
DELETE FROM $TABLE_NAME WHERE $ID IN (SELECT ${MslMessageTable.PAYLOAD_ID} FROM ${MslMessageTable.TABLE_NAME} WHERE ${MslMessageTable.MESSAGE_ID} = old.${MessageTable.ID});
|
||||
END
|
||||
""",
|
||||
"""
|
||||
CREATE TRIGGER msl_attachment_delete AFTER DELETE ON ${AttachmentTable.TABLE_NAME}
|
||||
BEGIN
|
||||
DELETE FROM $TABLE_NAME WHERE $ID IN (SELECT ${MslMessageTable.PAYLOAD_ID} FROM ${MslMessageTable.TABLE_NAME} WHERE ${MslMessageTable.MESSAGE_ID} = old.${AttachmentTable.MMS_ID});
|
||||
DELETE FROM $TABLE_NAME WHERE $ID IN (SELECT ${MslMessageTable.PAYLOAD_ID} FROM ${MslMessageTable.TABLE_NAME} WHERE ${MslMessageTable.TABLE_NAME}.${MslMessageTable.MESSAGE_ID} = old.${AttachmentTable.MESSAGE_ID});
|
||||
END
|
||||
"""
|
||||
)
|
||||
|
||||
@@ -351,15 +351,14 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
"""
|
||||
json_group_array(
|
||||
json_object(
|
||||
'${AttachmentTable.ROW_ID}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.ROW_ID},
|
||||
'${AttachmentTable.UNIQUE_ID}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.UNIQUE_ID},
|
||||
'${AttachmentTable.MMS_ID}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.MMS_ID},
|
||||
'${AttachmentTable.SIZE}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.SIZE},
|
||||
'${AttachmentTable.ID}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.ID},
|
||||
'${AttachmentTable.MESSAGE_ID}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.MESSAGE_ID},
|
||||
'${AttachmentTable.DATA_SIZE}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.DATA_SIZE},
|
||||
'${AttachmentTable.FILE_NAME}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.FILE_NAME},
|
||||
'${AttachmentTable.DATA}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.DATA},
|
||||
'${AttachmentTable.DATA_FILE}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.DATA_FILE},
|
||||
'${AttachmentTable.CONTENT_TYPE}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.CONTENT_TYPE},
|
||||
'${AttachmentTable.CDN_NUMBER}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.CDN_NUMBER},
|
||||
'${AttachmentTable.CONTENT_LOCATION}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.CONTENT_LOCATION},
|
||||
'${AttachmentTable.REMOTE_LOCATION}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.REMOTE_LOCATION},
|
||||
'${AttachmentTable.FAST_PREFLIGHT_ID}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.FAST_PREFLIGHT_ID},
|
||||
'${AttachmentTable.VOICE_NOTE}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.VOICE_NOTE},
|
||||
'${AttachmentTable.BORDERLESS}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.BORDERLESS},
|
||||
@@ -367,15 +366,14 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
'${AttachmentTable.WIDTH}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.WIDTH},
|
||||
'${AttachmentTable.HEIGHT}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.HEIGHT},
|
||||
'${AttachmentTable.QUOTE}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.QUOTE},
|
||||
'${AttachmentTable.CONTENT_DISPOSITION}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.CONTENT_DISPOSITION},
|
||||
'${AttachmentTable.NAME}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.NAME},
|
||||
'${AttachmentTable.REMOTE_KEY}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.REMOTE_KEY},
|
||||
'${AttachmentTable.TRANSFER_STATE}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.TRANSFER_STATE},
|
||||
'${AttachmentTable.CAPTION}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.CAPTION},
|
||||
'${AttachmentTable.STICKER_PACK_ID}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.STICKER_PACK_ID},
|
||||
'${AttachmentTable.STICKER_PACK_KEY}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.STICKER_PACK_KEY},
|
||||
'${AttachmentTable.STICKER_ID}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.STICKER_ID},
|
||||
'${AttachmentTable.STICKER_EMOJI}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.STICKER_EMOJI},
|
||||
'${AttachmentTable.VISUAL_HASH}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.VISUAL_HASH},
|
||||
'${AttachmentTable.BLUR_HASH}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.BLUR_HASH},
|
||||
'${AttachmentTable.TRANSFORM_PROPERTIES}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.TRANSFORM_PROPERTIES},
|
||||
'${AttachmentTable.DISPLAY_ORDER}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.DISPLAY_ORDER},
|
||||
'${AttachmentTable.UPLOAD_TIMESTAMP}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.UPLOAD_TIMESTAMP}
|
||||
@@ -1783,7 +1781,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
SELECT
|
||||
${Util.join(projection, ",")}
|
||||
FROM
|
||||
$TABLE_NAME LEFT OUTER JOIN ${AttachmentTable.TABLE_NAME} ON ($TABLE_NAME.$ID = ${AttachmentTable.TABLE_NAME}.${AttachmentTable.MMS_ID})
|
||||
$TABLE_NAME LEFT OUTER JOIN ${AttachmentTable.TABLE_NAME} ON ($TABLE_NAME.$ID = ${AttachmentTable.TABLE_NAME}.${AttachmentTable.MESSAGE_ID})
|
||||
WHERE
|
||||
$where
|
||||
GROUP BY
|
||||
@@ -2253,12 +2251,12 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
.run()
|
||||
|
||||
readableDatabase
|
||||
.select(AttachmentTable.ROW_ID, AttachmentTable.UNIQUE_ID)
|
||||
.select(AttachmentTable.ID)
|
||||
.from(AttachmentTable.TABLE_NAME)
|
||||
.where("${AttachmentTable.MMS_ID} NOT IN (SELECT $ID FROM $TABLE_NAME)")
|
||||
.where("${AttachmentTable.MESSAGE_ID} NOT IN (SELECT $ID FROM $TABLE_NAME)")
|
||||
.run()
|
||||
.forEach { cursor ->
|
||||
attachments.deleteAttachment(AttachmentId(cursor.requireLong(AttachmentTable.ROW_ID), cursor.requireLong(AttachmentTable.UNIQUE_ID)))
|
||||
attachments.deleteAttachment(AttachmentId(cursor.requireLong(AttachmentTable.ID)))
|
||||
}
|
||||
|
||||
mentions.deleteAbandonedMentions()
|
||||
@@ -2555,7 +2553,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
}
|
||||
|
||||
if (retrieved.attachments.isEmpty() && editedMessage?.id != null && attachments.getAttachmentsForMessage(editedMessage.id).isNotEmpty()) {
|
||||
val linkPreviewAttachmentIds = editedMessage.linkPreviews.mapNotNull { it.attachmentId?.rowId }.toSet()
|
||||
val linkPreviewAttachmentIds = editedMessage.linkPreviews.mapNotNull { it.attachmentId?.id }.toSet()
|
||||
attachments.duplicateAttachmentsForMessage(messageId, editedMessage.id, linkPreviewAttachmentIds)
|
||||
}
|
||||
|
||||
@@ -2928,8 +2926,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
.where("$ID_WHERE OR $LATEST_REVISION_ID = ?", message.messageToEdit, message.messageToEdit)
|
||||
.run()
|
||||
|
||||
val textAttachments = (editedMessage as? MmsMessageRecord)?.slideDeck?.asAttachments()?.filter { it.contentType == MediaUtil.LONG_TEXT }?.mapNotNull { (it as? DatabaseAttachment)?.attachmentId?.rowId } ?: emptyList()
|
||||
val linkPreviewAttachments = (editedMessage as? MmsMessageRecord)?.linkPreviews?.mapNotNull { it.attachmentId?.rowId } ?: emptyList()
|
||||
val textAttachments = (editedMessage as? MmsMessageRecord)?.slideDeck?.asAttachments()?.filter { it.contentType == MediaUtil.LONG_TEXT }?.mapNotNull { (it as? DatabaseAttachment)?.attachmentId?.id } ?: emptyList()
|
||||
val linkPreviewAttachments = (editedMessage as? MmsMessageRecord)?.linkPreviews?.mapNotNull { it.attachmentId?.id } ?: emptyList()
|
||||
val excludeIds = HashSet<Long>()
|
||||
excludeIds += textAttachments
|
||||
excludeIds += linkPreviewAttachments
|
||||
@@ -3305,9 +3303,9 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
val fileSize: Long = readableDatabase.rawQuery(
|
||||
"""
|
||||
SELECT
|
||||
SUM(${AttachmentTable.TABLE_NAME}.${AttachmentTable.SIZE}) AS s
|
||||
SUM(${AttachmentTable.TABLE_NAME}.${AttachmentTable.DATA_SIZE}) AS s
|
||||
FROM
|
||||
$TABLE_NAME INNER JOIN ${AttachmentTable.TABLE_NAME} ON $TABLE_NAME.$ID = ${AttachmentTable.TABLE_NAME}.${AttachmentTable.MMS_ID}
|
||||
$TABLE_NAME INNER JOIN ${AttachmentTable.TABLE_NAME} ON $TABLE_NAME.$ID = ${AttachmentTable.TABLE_NAME}.${AttachmentTable.MESSAGE_ID}
|
||||
WHERE
|
||||
${getInsecureMessageClause()} AND $EXPORTED < ${MessageExportStatus.EXPORTED.serialize()}
|
||||
""",
|
||||
@@ -3415,10 +3413,10 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
$VIEW_ONCE,
|
||||
$DATE_RECEIVED
|
||||
FROM
|
||||
$TABLE_NAME INNER JOIN ${AttachmentTable.TABLE_NAME} ON $TABLE_NAME.$ID = ${AttachmentTable.TABLE_NAME}.${AttachmentTable.MMS_ID}
|
||||
$TABLE_NAME INNER JOIN ${AttachmentTable.TABLE_NAME} ON $TABLE_NAME.$ID = ${AttachmentTable.TABLE_NAME}.${AttachmentTable.MESSAGE_ID}
|
||||
WHERE
|
||||
$VIEW_ONCE > 0 AND
|
||||
(${AttachmentTable.DATA} NOT NULL OR ${AttachmentTable.TRANSFER_STATE} != ?)
|
||||
(${AttachmentTable.DATA_FILE} NOT NULL OR ${AttachmentTable.TRANSFER_STATE} != ?)
|
||||
"""
|
||||
|
||||
val args = buildArgs(AttachmentTable.TRANSFER_PROGRESS_DONE)
|
||||
|
||||
@@ -72,6 +72,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V211_ReceiptColumnR
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V212_RemoveDistributionListUniqueConstraint
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V213_FixUsernameInE164Column
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V214_PhoneNumberSharingColumn
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V215_RemoveAttachmentUniqueId
|
||||
|
||||
/**
|
||||
* Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness.
|
||||
@@ -146,10 +147,11 @@ object SignalDatabaseMigrations {
|
||||
211 to V211_ReceiptColumnRenames,
|
||||
212 to V212_RemoveDistributionListUniqueConstraint,
|
||||
213 to V213_FixUsernameInE164Column,
|
||||
214 to V214_PhoneNumberSharingColumn
|
||||
214 to V214_PhoneNumberSharingColumn,
|
||||
215 to V215_RemoveAttachmentUniqueId
|
||||
)
|
||||
|
||||
const val DATABASE_VERSION = 214
|
||||
const val DATABASE_VERSION = 215
|
||||
|
||||
@JvmStatic
|
||||
fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2024 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.database.helpers.migration
|
||||
|
||||
import android.app.Application
|
||||
import net.zetetic.database.sqlcipher.SQLiteDatabase
|
||||
import org.signal.core.util.Stopwatch
|
||||
import org.signal.core.util.logging.Log
|
||||
|
||||
object V215_RemoveAttachmentUniqueId : SignalDatabaseMigration {
|
||||
|
||||
private val TAG = Log.tag(V215_RemoveAttachmentUniqueId::class.java)
|
||||
|
||||
override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
val stopwatch = Stopwatch("migration", decimalPlaces = 2)
|
||||
|
||||
db.execSQL(
|
||||
"""
|
||||
CREATE TABLE attachment (
|
||||
_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
message_id INTEGER,
|
||||
content_type TEXT,
|
||||
remote_key TEXT,
|
||||
remote_location TEXT,
|
||||
remote_digest BLOB,
|
||||
remote_incremental_digest BLOB,
|
||||
remote_incremental_digest_chunk_size INTEGER DEFAULT 0,
|
||||
cdn_number INTEGER DEFAULT 0,
|
||||
transfer_state INTEGER,
|
||||
transfer_file TEXT DEFAULT NULL,
|
||||
data_file TEXT,
|
||||
data_size INTEGER,
|
||||
data_random BLOB,
|
||||
data_hash TEXT DEFAULT NULL,
|
||||
file_name TEXT,
|
||||
fast_preflight_id TEXT,
|
||||
voice_note INTEGER DEFAULT 0,
|
||||
borderless INTEGER DEFAULT 0,
|
||||
video_gif INTEGER DEFAULT 0,
|
||||
quote INTEGER DEFAULT 0,
|
||||
width INTEGER DEFAULT 0,
|
||||
height INTEGER DEFAULT 0,
|
||||
caption TEXT DEFAULT NULL,
|
||||
sticker_pack_id TEXT DEFAULT NULL,
|
||||
sticker_pack_key DEFAULT NULL,
|
||||
sticker_id INTEGER DEFAULT -1,
|
||||
sticker_emoji STRING DEFAULT NULL,
|
||||
blur_hash TEXT DEFAULT NULL,
|
||||
transform_properties TEXT DEFAULT NULL,
|
||||
display_order INTEGER DEFAULT 0,
|
||||
upload_timestamp INTEGER DEFAULT 0
|
||||
)
|
||||
"""
|
||||
)
|
||||
|
||||
db.execSQL(
|
||||
"""
|
||||
INSERT INTO attachment
|
||||
SELECT
|
||||
_id,
|
||||
mid,
|
||||
ct,
|
||||
cd,
|
||||
cl,
|
||||
digest,
|
||||
incremental_mac_digest,
|
||||
incremental_mac_chunk_size,
|
||||
cdn_number,
|
||||
pending_push,
|
||||
transfer_file,
|
||||
_data,
|
||||
data_size,
|
||||
data_random,
|
||||
data_hash,
|
||||
file_name,
|
||||
fast_preflight_id,
|
||||
voice_note,
|
||||
borderless,
|
||||
video_gif,
|
||||
quote,
|
||||
width,
|
||||
height,
|
||||
caption,
|
||||
sticker_pack_id,
|
||||
sticker_pack_key,
|
||||
sticker_id,
|
||||
sticker_emoji,
|
||||
blur_hash,
|
||||
transform_properties,
|
||||
display_order,
|
||||
upload_timestamp
|
||||
FROM part
|
||||
"""
|
||||
)
|
||||
stopwatch.split("copy-data")
|
||||
|
||||
db.execSQL("DROP TABLE part")
|
||||
stopwatch.split("drop-old")
|
||||
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS attachment_message_id_index ON attachment (message_id)")
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS attachment_transfer_state_index ON attachment (transfer_state)")
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS attachment_sticker_pack_id_index ON attachment (sticker_pack_id)")
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS attachment_data_hash_index ON attachment (data_hash)")
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS attachment_data_index ON attachment (data_file)")
|
||||
stopwatch.split("create-indexes")
|
||||
|
||||
db.execSQL(
|
||||
"""
|
||||
CREATE TRIGGER msl_attachment_delete AFTER DELETE ON attachment
|
||||
BEGIN
|
||||
DELETE FROM msl_payload WHERE _id IN (SELECT payload_id FROM msl_message WHERE msl_message.message_id = old.message_id);
|
||||
END
|
||||
"""
|
||||
)
|
||||
|
||||
stopwatch.stop(TAG)
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ public final class PagingMediaLoader extends AsyncLoader<Pair<Cursor, Integer>>
|
||||
Cursor cursor = SignalDatabase.media().getGalleryMediaForThread(threadId, sorting);
|
||||
|
||||
while (cursor.moveToNext()) {
|
||||
AttachmentId attachmentId = new AttachmentId(cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentTable.ROW_ID)), cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentTable.UNIQUE_ID)));
|
||||
AttachmentId attachmentId = new AttachmentId(cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentTable.ID)));
|
||||
Uri attachmentUri = PartAuthority.getAttachmentDataUri(attachmentId);
|
||||
|
||||
if (attachmentUri.equals(uri)) {
|
||||
|
||||
@@ -59,9 +59,8 @@ public final class AttachmentCompressionJob extends BaseJob {
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = Log.tag(AttachmentCompressionJob.class);
|
||||
|
||||
private static final String KEY_ROW_ID = "row_id";
|
||||
private static final String KEY_UNIQUE_ID = "unique_id";
|
||||
private static final String KEY_MMS = "mms";
|
||||
private static final String KEY_ATTACHMENT_ID = "row_id";
|
||||
private static final String KEY_MMS = "mms";
|
||||
private static final String KEY_MMS_SUBSCRIPTION_ID = "mms_subscription_id";
|
||||
|
||||
private final AttachmentId attachmentId;
|
||||
@@ -107,8 +106,7 @@ public final class AttachmentCompressionJob extends BaseJob {
|
||||
|
||||
@Override
|
||||
public @Nullable byte [] serialize() {
|
||||
return new JsonJobData.Builder().putLong(KEY_ROW_ID, attachmentId.getRowId())
|
||||
.putLong(KEY_UNIQUE_ID, attachmentId.getUniqueId())
|
||||
return new JsonJobData.Builder().putLong(KEY_ATTACHMENT_ID, attachmentId.id)
|
||||
.putBoolean(KEY_MMS, mms)
|
||||
.putInt(KEY_MMS_SUBSCRIPTION_ID, mmsSubscriptionId)
|
||||
.serialize();
|
||||
@@ -391,7 +389,7 @@ public final class AttachmentCompressionJob extends BaseJob {
|
||||
}
|
||||
|
||||
JsonJobData data = JsonJobData.deserialize(serializedData);
|
||||
final AttachmentId parsed = new AttachmentId(data.getLong(KEY_ROW_ID), data.getLong(KEY_UNIQUE_ID));
|
||||
final AttachmentId parsed = new AttachmentId(data.getLong(KEY_ATTACHMENT_ID));
|
||||
return attachmentId.equals(parsed);
|
||||
}
|
||||
|
||||
@@ -401,7 +399,7 @@ public final class AttachmentCompressionJob extends BaseJob {
|
||||
JsonJobData data = JsonJobData.deserialize(serializedData);
|
||||
|
||||
return new AttachmentCompressionJob(parameters,
|
||||
new AttachmentId(data.getLong(KEY_ROW_ID), data.getLong(KEY_UNIQUE_ID)),
|
||||
new AttachmentId(data.getLong(KEY_ATTACHMENT_ID)),
|
||||
data.getBoolean(KEY_MMS),
|
||||
data.getInt(KEY_MMS_SUBSCRIPTION_ID));
|
||||
}
|
||||
|
||||
@@ -64,14 +64,12 @@ public final class AttachmentDownloadJob extends BaseJob {
|
||||
|
||||
private static final String TAG = Log.tag(AttachmentDownloadJob.class);
|
||||
|
||||
private static final String KEY_MESSAGE_ID = "message_id";
|
||||
private static final String KEY_ROW_ID = "part_row_id";
|
||||
private static final String KEY_UNIQUE_ID = "part_unique_id";
|
||||
private static final String KEY_MANUAL = "part_manual";
|
||||
private static final String KEY_MESSAGE_ID = "message_id";
|
||||
private static final String KEY_ATTACHMENT_ID = "part_row_id";
|
||||
private static final String KEY_MANUAL = "part_manual";
|
||||
|
||||
private final long messageId;
|
||||
private final long partRowId;
|
||||
private final long partUniqueId;
|
||||
private final long messageId;
|
||||
private final long attachmentId;
|
||||
private final boolean manual;
|
||||
|
||||
public AttachmentDownloadJob(long messageId, AttachmentId attachmentId, boolean manual) {
|
||||
@@ -90,16 +88,14 @@ public final class AttachmentDownloadJob extends BaseJob {
|
||||
super(parameters);
|
||||
|
||||
this.messageId = messageId;
|
||||
this.partRowId = attachmentId.getRowId();
|
||||
this.partUniqueId = attachmentId.getUniqueId();
|
||||
this.attachmentId = attachmentId.id;
|
||||
this.manual = manual;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable byte[] serialize() {
|
||||
return new JsonJobData.Builder().putLong(KEY_MESSAGE_ID, messageId)
|
||||
.putLong(KEY_ROW_ID, partRowId)
|
||||
.putLong(KEY_UNIQUE_ID, partUniqueId)
|
||||
.putLong(KEY_ATTACHMENT_ID, attachmentId)
|
||||
.putBoolean(KEY_MANUAL, manual)
|
||||
.serialize();
|
||||
}
|
||||
@@ -110,18 +106,18 @@ public final class AttachmentDownloadJob extends BaseJob {
|
||||
}
|
||||
|
||||
public static String constructQueueString(AttachmentId attachmentId) {
|
||||
return "AttachmentDownloadJob" + attachmentId.getRowId() + "-" + attachmentId.getUniqueId();
|
||||
return "AttachmentDownloadJob-" + attachmentId.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAdded() {
|
||||
Log.i(TAG, "onAdded() messageId: " + messageId + " partRowId: " + partRowId + " partUniqueId: " + partUniqueId + " manual: " + manual);
|
||||
Log.i(TAG, "onAdded() messageId: " + messageId + " attachmentId: " + attachmentId + " manual: " + manual);
|
||||
|
||||
final AttachmentTable database = SignalDatabase.attachments();
|
||||
final AttachmentId attachmentId = new AttachmentId(partRowId, partUniqueId);
|
||||
final AttachmentId attachmentId = new AttachmentId(this.attachmentId);
|
||||
final DatabaseAttachment attachment = database.getAttachment(attachmentId);
|
||||
final boolean pending = attachment != null && attachment.transferState != AttachmentTable.TRANSFER_PROGRESS_DONE
|
||||
&& attachment.transferState != AttachmentTable.TRANSFER_PROGRESS_PERMANENT_FAILURE;
|
||||
final boolean pending = attachment != null && attachment.transferState != AttachmentTable.TRANSFER_PROGRESS_DONE
|
||||
&& attachment.transferState != AttachmentTable.TRANSFER_PROGRESS_PERMANENT_FAILURE;
|
||||
|
||||
if (pending && (manual || AttachmentUtil.isAutoDownloadPermitted(context, attachment))) {
|
||||
Log.i(TAG, "onAdded() Marking attachment progress as 'started'");
|
||||
@@ -139,10 +135,10 @@ public final class AttachmentDownloadJob extends BaseJob {
|
||||
}
|
||||
|
||||
public void doWork() throws IOException, RetryLaterException {
|
||||
Log.i(TAG, "onRun() messageId: " + messageId + " partRowId: " + partRowId + " partUniqueId: " + partUniqueId + " manual: " + manual);
|
||||
Log.i(TAG, "onRun() messageId: " + messageId + " attachmentId: " + attachmentId + " manual: " + manual);
|
||||
|
||||
final AttachmentTable database = SignalDatabase.attachments();
|
||||
final AttachmentId attachmentId = new AttachmentId(partRowId, partUniqueId);
|
||||
final AttachmentId attachmentId = new AttachmentId(this.attachmentId);
|
||||
final DatabaseAttachment attachment = database.getAttachment(attachmentId);
|
||||
|
||||
if (attachment == null) {
|
||||
@@ -178,9 +174,9 @@ public final class AttachmentDownloadJob extends BaseJob {
|
||||
|
||||
@Override
|
||||
public void onFailure() {
|
||||
Log.w(TAG, JobLogger.format(this, "onFailure() messageId: " + messageId + " partRowId: " + partRowId + " partUniqueId: " + partUniqueId + " manual: " + manual));
|
||||
Log.w(TAG, JobLogger.format(this, "onFailure() messageId: " + messageId + " attachmentId: " + attachmentId + " manual: " + manual));
|
||||
|
||||
final AttachmentId attachmentId = new AttachmentId(partRowId, partUniqueId);
|
||||
final AttachmentId attachmentId = new AttachmentId(this.attachmentId);
|
||||
markFailed(messageId, attachmentId);
|
||||
}
|
||||
|
||||
@@ -244,20 +240,20 @@ public final class AttachmentDownloadJob extends BaseJob {
|
||||
}
|
||||
|
||||
private SignalServiceAttachmentPointer createAttachmentPointer(Attachment attachment) throws InvalidPartException {
|
||||
if (TextUtils.isEmpty(attachment.location)) {
|
||||
if (TextUtils.isEmpty(attachment.remoteLocation)) {
|
||||
throw new InvalidPartException("empty content id");
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(attachment.key)) {
|
||||
if (TextUtils.isEmpty(attachment.remoteKey)) {
|
||||
throw new InvalidPartException("empty encrypted key");
|
||||
}
|
||||
|
||||
try {
|
||||
final SignalServiceAttachmentRemoteId remoteId = SignalServiceAttachmentRemoteId.from(attachment.location);
|
||||
final byte[] key = Base64.decode(attachment.key);
|
||||
final SignalServiceAttachmentRemoteId remoteId = SignalServiceAttachmentRemoteId.from(attachment.remoteLocation);
|
||||
final byte[] key = Base64.decode(attachment.remoteKey);
|
||||
|
||||
if (attachment.digest != null) {
|
||||
Log.i(TAG, "Downloading attachment with digest: " + Hex.toString(attachment.digest));
|
||||
if (attachment.remoteDigest != null) {
|
||||
Log.i(TAG, "Downloading attachment with digest: " + Hex.toString(attachment.remoteDigest));
|
||||
} else {
|
||||
Log.i(TAG, "Downloading attachment with no digest...");
|
||||
}
|
||||
@@ -266,7 +262,7 @@ public final class AttachmentDownloadJob extends BaseJob {
|
||||
Optional.of(Util.toIntExact(attachment.size)),
|
||||
Optional.empty(),
|
||||
0, 0,
|
||||
Optional.ofNullable(attachment.digest),
|
||||
Optional.ofNullable(attachment.remoteDigest),
|
||||
Optional.ofNullable(attachment.getIncrementalDigest()),
|
||||
attachment.incrementalMacChunkSize,
|
||||
Optional.ofNullable(attachment.fileName),
|
||||
@@ -330,7 +326,7 @@ public final class AttachmentDownloadJob extends BaseJob {
|
||||
}
|
||||
|
||||
JsonJobData data = JsonJobData.deserialize(serializedData);
|
||||
final AttachmentId parsed = new AttachmentId(data.getLong(KEY_ROW_ID), data.getLong(KEY_UNIQUE_ID));
|
||||
final AttachmentId parsed = new AttachmentId(data.getLong(KEY_ATTACHMENT_ID));
|
||||
return attachmentId.equals(parsed);
|
||||
}
|
||||
|
||||
@@ -347,7 +343,7 @@ public final class AttachmentDownloadJob extends BaseJob {
|
||||
|
||||
return new AttachmentDownloadJob(parameters,
|
||||
data.getLong(KEY_MESSAGE_ID),
|
||||
new AttachmentId(data.getLong(KEY_ROW_ID), data.getLong(KEY_UNIQUE_ID)),
|
||||
new AttachmentId(data.getLong(KEY_ATTACHMENT_ID)),
|
||||
data.getBoolean(KEY_MANUAL));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,9 +24,8 @@ public final class AttachmentMarkUploadedJob extends BaseJob {
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = Log.tag(AttachmentMarkUploadedJob.class);
|
||||
|
||||
private static final String KEY_ROW_ID = "row_id";
|
||||
private static final String KEY_UNIQUE_ID = "unique_id";
|
||||
private static final String KEY_MESSAGE_ID = "message_id";
|
||||
private static final String KEY_ATTACHMENT_ID = "row_id";
|
||||
private static final String KEY_MESSAGE_ID = "message_id";
|
||||
|
||||
private final AttachmentId attachmentId;
|
||||
private final long messageId;
|
||||
@@ -48,8 +47,7 @@ public final class AttachmentMarkUploadedJob extends BaseJob {
|
||||
|
||||
@Override
|
||||
public @Nullable byte[] serialize() {
|
||||
return new JsonJobData.Builder().putLong(KEY_ROW_ID, attachmentId.getRowId())
|
||||
.putLong(KEY_UNIQUE_ID, attachmentId.getUniqueId())
|
||||
return new JsonJobData.Builder().putLong(KEY_ATTACHMENT_ID, attachmentId.id)
|
||||
.putLong(KEY_MESSAGE_ID, messageId)
|
||||
.serialize();
|
||||
}
|
||||
@@ -93,7 +91,7 @@ public final class AttachmentMarkUploadedJob extends BaseJob {
|
||||
|
||||
return new AttachmentMarkUploadedJob(parameters,
|
||||
data.getLong(KEY_MESSAGE_ID),
|
||||
new AttachmentId(data.getLong(KEY_ROW_ID), data.getLong(KEY_UNIQUE_ID)));
|
||||
new AttachmentId(data.getLong(KEY_ATTACHMENT_ID)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ class AttachmentUploadJob private constructor(
|
||||
}
|
||||
val serializedData = jobSpec.serializedData ?: return false
|
||||
val data = AttachmentUploadJobData.ADAPTER.decode(serializedData)
|
||||
val parsed = AttachmentId(data.attachmentRowId, data.attachmentUniqueId)
|
||||
val parsed = AttachmentId(data.attachmentId)
|
||||
return attachmentId == parsed
|
||||
}
|
||||
}
|
||||
@@ -99,8 +99,7 @@ class AttachmentUploadJob private constructor(
|
||||
|
||||
override fun serialize(): ByteArray {
|
||||
return AttachmentUploadJobData(
|
||||
attachmentRowId = attachmentId.rowId,
|
||||
attachmentUniqueId = attachmentId.uniqueId,
|
||||
attachmentId = attachmentId.id,
|
||||
uploadSpec = uploadSpec
|
||||
).encode()
|
||||
}
|
||||
@@ -138,7 +137,7 @@ class AttachmentUploadJob private constructor(
|
||||
val databaseAttachment = SignalDatabase.attachments.getAttachment(attachmentId) ?: throw InvalidAttachmentException("Cannot find the specified attachment.")
|
||||
|
||||
val timeSinceUpload = System.currentTimeMillis() - databaseAttachment.uploadTimestamp
|
||||
if (timeSinceUpload < UPLOAD_REUSE_THRESHOLD && !TextUtils.isEmpty(databaseAttachment.location)) {
|
||||
if (timeSinceUpload < UPLOAD_REUSE_THRESHOLD && !TextUtils.isEmpty(databaseAttachment.remoteLocation)) {
|
||||
Log.i(TAG, "We can re-use an already-uploaded file. It was uploaded $timeSinceUpload ms (${timeSinceUpload.milliseconds.inRoundedDays()} days) ago. Skipping.")
|
||||
return
|
||||
} else if (databaseAttachment.uploadTimestamp > 0) {
|
||||
@@ -297,7 +296,7 @@ class AttachmentUploadJob private constructor(
|
||||
val data = AttachmentUploadJobData.ADAPTER.decode(serializedData!!)
|
||||
return AttachmentUploadJob(
|
||||
parameters = parameters,
|
||||
attachmentId = AttachmentId(data.attachmentRowId, data.attachmentUniqueId),
|
||||
attachmentId = AttachmentId(data.attachmentId),
|
||||
data.uploadSpec
|
||||
)
|
||||
}
|
||||
|
||||
@@ -22,8 +22,7 @@ class GenerateAudioWaveFormJob private constructor(private val attachmentId: Att
|
||||
companion object {
|
||||
private val TAG = Log.tag(GenerateAudioWaveFormJob::class.java)
|
||||
|
||||
private const val KEY_PART_ROW_ID = "part_row_id"
|
||||
private const val KEY_PAR_UNIQUE_ID = "part_unique_id"
|
||||
private const val KEY_ATTACHMENT_ID = "part_row_id"
|
||||
|
||||
const val KEY = "GenerateAudioWaveFormJob"
|
||||
|
||||
@@ -48,8 +47,7 @@ class GenerateAudioWaveFormJob private constructor(private val attachmentId: Att
|
||||
|
||||
override fun serialize(): ByteArray? {
|
||||
return JsonJobData.Builder()
|
||||
.putLong(KEY_PART_ROW_ID, attachmentId.rowId)
|
||||
.putLong(KEY_PAR_UNIQUE_ID, attachmentId.uniqueId)
|
||||
.putLong(KEY_ATTACHMENT_ID, attachmentId.id)
|
||||
.serialize()
|
||||
}
|
||||
|
||||
@@ -89,7 +87,7 @@ class GenerateAudioWaveFormJob private constructor(private val attachmentId: Att
|
||||
class Factory : Job.Factory<GenerateAudioWaveFormJob> {
|
||||
override fun create(parameters: Parameters, serializedData: ByteArray?): GenerateAudioWaveFormJob {
|
||||
val data = JsonJobData.deserialize(serializedData)
|
||||
return GenerateAudioWaveFormJob(AttachmentId(data.getLong(KEY_PART_ROW_ID), data.getLong(KEY_PAR_UNIQUE_ID)), parameters)
|
||||
return GenerateAudioWaveFormJob(AttachmentId(data.getLong(KEY_ATTACHMENT_ID)), parameters)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,9 +60,8 @@ public final class LegacyAttachmentUploadJob extends BaseJob {
|
||||
|
||||
private static final long UPLOAD_REUSE_THRESHOLD = TimeUnit.DAYS.toMillis(3);
|
||||
|
||||
private static final String KEY_ROW_ID = "row_id";
|
||||
private static final String KEY_UNIQUE_ID = "unique_id";
|
||||
private static final String KEY_FORCE_V2 = "force_v2";
|
||||
private static final String KEY_ROW_ID = "row_id";
|
||||
private static final String KEY_FORCE_V2 = "force_v2";
|
||||
|
||||
/**
|
||||
* Foreground notification shows while uploading attachments above this.
|
||||
@@ -81,8 +80,7 @@ public final class LegacyAttachmentUploadJob extends BaseJob {
|
||||
|
||||
@Override
|
||||
public @Nullable byte[] serialize() {
|
||||
return new JsonJobData.Builder().putLong(KEY_ROW_ID, attachmentId.getRowId())
|
||||
.putLong(KEY_UNIQUE_ID, attachmentId.getUniqueId())
|
||||
return new JsonJobData.Builder().putLong(KEY_ROW_ID, attachmentId.id)
|
||||
.putBoolean(KEY_FORCE_V2, forceV2)
|
||||
.serialize();
|
||||
}
|
||||
@@ -127,7 +125,7 @@ public final class LegacyAttachmentUploadJob extends BaseJob {
|
||||
}
|
||||
|
||||
long timeSinceUpload = System.currentTimeMillis() - databaseAttachment.uploadTimestamp;
|
||||
if (timeSinceUpload < UPLOAD_REUSE_THRESHOLD && !TextUtils.isEmpty(databaseAttachment.location)) {
|
||||
if (timeSinceUpload < UPLOAD_REUSE_THRESHOLD && !TextUtils.isEmpty(databaseAttachment.remoteLocation)) {
|
||||
Log.i(TAG, "We can re-use an already-uploaded file. It was uploaded " + timeSinceUpload + " ms ago. Skipping.");
|
||||
return;
|
||||
} else if (databaseAttachment.uploadTimestamp > 0) {
|
||||
@@ -276,7 +274,7 @@ public final class LegacyAttachmentUploadJob extends BaseJob {
|
||||
public @NonNull LegacyAttachmentUploadJob create(@NonNull Parameters parameters, @Nullable byte[] serializedData) {
|
||||
JsonJobData data = JsonJobData.deserialize(serializedData);
|
||||
|
||||
return new LegacyAttachmentUploadJob(parameters, new AttachmentId(data.getLong(KEY_ROW_ID), data.getLong(KEY_UNIQUE_ID)), data.getBooleanOrDefault(KEY_FORCE_V2, false));
|
||||
return new LegacyAttachmentUploadJob(parameters, new AttachmentId(data.getLong(KEY_ROW_ID)), data.getBooleanOrDefault(KEY_FORCE_V2, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,19 +262,19 @@ public abstract class PushSendJob extends SendJob {
|
||||
}
|
||||
|
||||
protected @Nullable SignalServiceAttachment getAttachmentPointerFor(Attachment attachment) {
|
||||
if (TextUtils.isEmpty(attachment.location)) {
|
||||
if (TextUtils.isEmpty(attachment.remoteLocation)) {
|
||||
Log.w(TAG, "empty content id");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(attachment.key)) {
|
||||
if (TextUtils.isEmpty(attachment.remoteKey)) {
|
||||
Log.w(TAG, "empty encrypted key");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
final SignalServiceAttachmentRemoteId remoteId = SignalServiceAttachmentRemoteId.from(attachment.location);
|
||||
final byte[] key = Base64.decode(attachment.key);
|
||||
final SignalServiceAttachmentRemoteId remoteId = SignalServiceAttachmentRemoteId.from(attachment.remoteLocation);
|
||||
final byte[] key = Base64.decode(attachment.remoteKey);
|
||||
|
||||
int width = attachment.width;
|
||||
int height = attachment.height;
|
||||
@@ -296,7 +296,7 @@ public abstract class PushSendJob extends SendJob {
|
||||
Optional.empty(),
|
||||
width,
|
||||
height,
|
||||
Optional.ofNullable(attachment.digest),
|
||||
Optional.ofNullable(attachment.remoteDigest),
|
||||
Optional.ofNullable(attachment.getIncrementalDigest()),
|
||||
attachment.incrementalMacChunkSize,
|
||||
Optional.ofNullable(attachment.fileName),
|
||||
|
||||
@@ -47,9 +47,7 @@ class MediaPreviewRepository {
|
||||
val mediaRecords = mutableListOf<MediaTable.MediaRecord>()
|
||||
var startingRow = -1
|
||||
while (cursor.moveToNext()) {
|
||||
if (startingAttachmentId.rowId == cursor.requireLong(AttachmentTable.ROW_ID) &&
|
||||
startingAttachmentId.uniqueId == cursor.requireLong(AttachmentTable.UNIQUE_ID)
|
||||
) {
|
||||
if (startingAttachmentId.id == cursor.requireLong(AttachmentTable.ID)) {
|
||||
startingRow = cursor.position
|
||||
break
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ public class PartAuthority {
|
||||
|
||||
static {
|
||||
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
|
||||
uriMatcher.addURI(AUTHORITY, "part/*/#", PART_ROW);
|
||||
uriMatcher.addURI(AUTHORITY, "part/#", PART_ROW);
|
||||
uriMatcher.addURI(AUTHORITY, "sticker/#", STICKER_ROW);
|
||||
uriMatcher.addURI(AUTHORITY, "wallpaper/*", WALLPAPER_ROW);
|
||||
uriMatcher.addURI(AUTHORITY, "emoji/*", EMOJI_ROW);
|
||||
@@ -174,8 +174,7 @@ public class PartAuthority {
|
||||
}
|
||||
|
||||
public static Uri getAttachmentDataUri(AttachmentId attachmentId) {
|
||||
Uri uri = Uri.withAppendedPath(PART_CONTENT_URI, String.valueOf(attachmentId.getUniqueId()));
|
||||
return ContentUris.withAppendedId(uri, attachmentId.getRowId());
|
||||
return ContentUris.withAppendedId(PART_CONTENT_URI, attachmentId.id);
|
||||
}
|
||||
|
||||
public static Uri getAttachmentThumbnailUri(AttachmentId attachmentId) {
|
||||
|
||||
@@ -14,7 +14,7 @@ public class PartUriParser {
|
||||
}
|
||||
|
||||
public AttachmentId getPartId() {
|
||||
return new AttachmentId(getId(), getUniqueId());
|
||||
return new AttachmentId(getId());
|
||||
}
|
||||
|
||||
private long getId() {
|
||||
|
||||
@@ -78,8 +78,7 @@ public final class PartProvider extends BaseContentProvider {
|
||||
}
|
||||
|
||||
public static Uri getContentUri(AttachmentId attachmentId) {
|
||||
Uri uri = Uri.withAppendedPath(CONTENT_URI, String.valueOf(attachmentId.getUniqueId()));
|
||||
return ContentUris.withAppendedId(uri, attachmentId.getRowId());
|
||||
return ContentUris.withAppendedId(CONTENT_URI, attachmentId.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -723,7 +723,7 @@ public class MessageSender {
|
||||
|
||||
@Override
|
||||
public @NonNull String toString() {
|
||||
return "{ID: " + attachmentId.getRowId() + ", URI: " + media.getUri() + ", Jobs: " + jobIds.stream().map(j -> "JOB::" + j).collect(Collectors.toList()) + "}";
|
||||
return "{ID: " + attachmentId.id + ", URI: " + media.getUri() + ", Jobs: " + jobIds.stream().map(j -> "JOB::" + j).collect(Collectors.toList()) + "}";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,14 +58,14 @@ class PartDataSource implements DataSource {
|
||||
|
||||
final boolean hasIncrementalDigest = attachment.getIncrementalDigest() != null;
|
||||
final boolean inProgress = attachment.isInProgress();
|
||||
final String attachmentKey = attachment.key;
|
||||
final String attachmentKey = attachment.remoteKey;
|
||||
final boolean hasData = attachment.hasData;
|
||||
|
||||
if (inProgress && !hasData && hasIncrementalDigest && attachmentKey != null && FeatureFlags.instantVideoPlayback()) {
|
||||
final byte[] decode = Base64.decode(attachmentKey);
|
||||
final File transferFile = attachmentDatabase.getOrCreateTransferFile(attachment.attachmentId);
|
||||
try {
|
||||
this.inputStream = AttachmentCipherInputStream.createForAttachment(transferFile, attachment.size, decode, attachment.digest, attachment.getIncrementalDigest(), attachment.incrementalMacChunkSize);
|
||||
this.inputStream = AttachmentCipherInputStream.createForAttachment(transferFile, attachment.size, decode, attachment.remoteDigest, attachment.getIncrementalDigest(), attachment.incrementalMacChunkSize);
|
||||
|
||||
long skipped = 0;
|
||||
while (skipped < dataSpec.position) {
|
||||
|
||||
@@ -33,7 +33,7 @@ message CallLinkUpdateSendJobData {
|
||||
}
|
||||
|
||||
message AttachmentUploadJobData {
|
||||
uint64 attachmentRowId = 1;
|
||||
uint64 attachmentUniqueId = 2;
|
||||
uint64 attachmentId = 1;
|
||||
reserved /*attachmentUniqueId*/ 2;
|
||||
optional ResumableUpload uploadSpec = 3;
|
||||
}
|
||||
Reference in New Issue
Block a user