Clean up AttachmentTable schema.

This commit is contained in:
Greyson Parrelli
2024-01-09 09:21:23 -05:00
committed by Alex Hart
parent 62b142cdeb
commit fe39b5e4e2
40 changed files with 486 additions and 502 deletions

View File

@@ -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)

View File

@@ -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];
}
};
}

View File

@@ -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"
}
}

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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
"""
}

View File

@@ -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());

View File

@@ -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);
}

View File

@@ -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)

View File

@@ -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);
}

View File

@@ -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()
)

View File

@@ -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)

View File

@@ -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
"""
);

View File

@@ -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
"""
)

View File

@@ -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)

View File

@@ -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) {

View File

@@ -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)
}
}

View File

@@ -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)) {

View File

@@ -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));
}

View File

@@ -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));
}
}

View File

@@ -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)));
}
}
}

View File

@@ -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
)
}

View File

@@ -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)
}
}
}

View File

@@ -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));
}
}
}

View File

@@ -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),

View File

@@ -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
}

View File

@@ -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) {

View File

@@ -14,7 +14,7 @@ public class PartUriParser {
}
public AttachmentId getPartId() {
return new AttachmentId(getId(), getUniqueId());
return new AttachmentId(getId());
}
private long getId() {

View File

@@ -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

View File

@@ -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()) + "}";
}
}

View File

@@ -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) {

View File

@@ -33,7 +33,7 @@ message CallLinkUpdateSendJobData {
}
message AttachmentUploadJobData {
uint64 attachmentRowId = 1;
uint64 attachmentUniqueId = 2;
uint64 attachmentId = 1;
reserved /*attachmentUniqueId*/ 2;
optional ResumableUpload uploadSpec = 3;
}