kopia lustrzana https://github.com/ryukoposting/Signal-Android
Improve constraints on thread and message tables.
rodzic
5d9f00b268
commit
95eba78d9c
|
@ -332,11 +332,6 @@
|
|||
android:theme="@style/Signal.DayNight.NoActionBar"
|
||||
android:windowSoftInputMode="adjustResize"/>
|
||||
|
||||
<activity android:name=".DatabaseMigrationActivity"
|
||||
android:theme="@style/NoAnimation.Theme.AppCompat.Light.DarkActionBar"
|
||||
android:launchMode="singleTask"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
|
||||
<activity android:name=".migrations.ApplicationMigrationActivity"
|
||||
android:theme="@style/Theme.Signal.DayNight.NoActionBar"
|
||||
android:launchMode="singleTask"
|
||||
|
@ -702,7 +697,6 @@
|
|||
|
||||
<service android:enabled="true" android:name=".exporter.SignalSmsExportService" android:foregroundServiceType="dataSync" />
|
||||
<service android:enabled="true" android:name=".service.webrtc.WebRtcCallService" android:foregroundServiceType="camera|microphone"/>
|
||||
<service android:enabled="true" android:name=".service.ApplicationMigrationService"/>
|
||||
<service android:enabled="true" android:exported="false" android:name=".service.KeyCachingService"/>
|
||||
<service android:enabled="true" android:name=".messages.IncomingMessageObserver$ForegroundService"/>
|
||||
<service android:name=".service.webrtc.AndroidCallConnectionService"
|
||||
|
|
|
@ -146,7 +146,6 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr
|
|||
SignalDatabase.init(this,
|
||||
DatabaseSecretProvider.getOrCreateDatabaseSecret(this),
|
||||
AttachmentSecretProvider.getInstance(this).getOrCreateAttachmentSecret());
|
||||
SignalDatabase.triggerDatabaseAccess();
|
||||
})
|
||||
.addBlocking("logging", () -> {
|
||||
initializeLogging();
|
||||
|
|
|
@ -1,201 +0,0 @@
|
|||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.Parcelable;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.thoughtcrime.securesms.database.SmsMigrator.ProgressDescription;
|
||||
import org.thoughtcrime.securesms.service.ApplicationMigrationService;
|
||||
import org.thoughtcrime.securesms.service.ApplicationMigrationService.ImportState;
|
||||
|
||||
public class DatabaseMigrationActivity extends PassphraseRequiredActivity {
|
||||
|
||||
private final ImportServiceConnection serviceConnection = new ImportServiceConnection();
|
||||
private final ImportStateHandler importStateHandler = new ImportStateHandler();
|
||||
private final BroadcastReceiver completedReceiver = new NullReceiver();
|
||||
|
||||
private LinearLayout promptLayout;
|
||||
private LinearLayout progressLayout;
|
||||
private Button skipButton;
|
||||
private Button importButton;
|
||||
private ProgressBar progress;
|
||||
private TextView progressLabel;
|
||||
|
||||
private ApplicationMigrationService importService;
|
||||
private boolean isVisible = false;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle bundle, boolean ready) {
|
||||
setContentView(R.layout.database_migration_activity);
|
||||
|
||||
initializeResources();
|
||||
initializeServiceBinding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
isVisible = true;
|
||||
registerForCompletedNotification();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
isVisible = false;
|
||||
unregisterForCompletedNotification();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
shutdownServiceBinding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
|
||||
}
|
||||
|
||||
private void initializeServiceBinding() {
|
||||
Intent intent = new Intent(this, ApplicationMigrationService.class);
|
||||
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
|
||||
}
|
||||
|
||||
private void initializeResources() {
|
||||
this.promptLayout = (LinearLayout)findViewById(R.id.prompt_layout);
|
||||
this.progressLayout = (LinearLayout)findViewById(R.id.progress_layout);
|
||||
this.skipButton = (Button) findViewById(R.id.skip_button);
|
||||
this.importButton = (Button) findViewById(R.id.import_button);
|
||||
this.progress = (ProgressBar) findViewById(R.id.import_progress);
|
||||
this.progressLabel = (TextView) findViewById(R.id.import_status);
|
||||
|
||||
this.progressLayout.setVisibility(View.GONE);
|
||||
this.promptLayout.setVisibility(View.GONE);
|
||||
|
||||
this.importButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent intent = new Intent(DatabaseMigrationActivity.this, ApplicationMigrationService.class);
|
||||
intent.setAction(ApplicationMigrationService.MIGRATE_DATABASE);
|
||||
intent.putExtra("master_secret", (Parcelable)getIntent().getParcelableExtra("master_secret"));
|
||||
startService(intent);
|
||||
|
||||
promptLayout.setVisibility(View.GONE);
|
||||
progressLayout.setVisibility(View.VISIBLE);
|
||||
}
|
||||
});
|
||||
|
||||
this.skipButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
ApplicationMigrationService.setDatabaseImported(DatabaseMigrationActivity.this);
|
||||
handleImportComplete();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void registerForCompletedNotification() {
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(ApplicationMigrationService.COMPLETED_ACTION);
|
||||
filter.setPriority(1000);
|
||||
|
||||
registerReceiver(completedReceiver, filter);
|
||||
}
|
||||
|
||||
private void unregisterForCompletedNotification() {
|
||||
unregisterReceiver(completedReceiver);
|
||||
}
|
||||
|
||||
private void shutdownServiceBinding() {
|
||||
unbindService(serviceConnection);
|
||||
}
|
||||
|
||||
private void handleStateIdle() {
|
||||
this.promptLayout.setVisibility(View.VISIBLE);
|
||||
this.progressLayout.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
private void handleStateProgress(ProgressDescription update) {
|
||||
this.promptLayout.setVisibility(View.GONE);
|
||||
this.progressLayout.setVisibility(View.VISIBLE);
|
||||
this.progressLabel.setText(update.primaryComplete + "/" + update.primaryTotal);
|
||||
|
||||
double max = this.progress.getMax();
|
||||
double primaryTotal = update.primaryTotal;
|
||||
double primaryComplete = update.primaryComplete;
|
||||
double secondaryTotal = update.secondaryTotal;
|
||||
double secondaryComplete = update.secondaryComplete;
|
||||
|
||||
this.progress.setProgress((int)Math.round((primaryComplete / primaryTotal) * max));
|
||||
this.progress.setSecondaryProgress((int)Math.round((secondaryComplete / secondaryTotal) * max));
|
||||
}
|
||||
|
||||
private void handleImportComplete() {
|
||||
if (isVisible) {
|
||||
if (getIntent().hasExtra("next_intent")) {
|
||||
startActivity((Intent)getIntent().getParcelableExtra("next_intent"));
|
||||
} else {
|
||||
// TODO [greyson] Navigation
|
||||
startActivity(MainActivity.clearTop(this));
|
||||
}
|
||||
}
|
||||
|
||||
finish();
|
||||
}
|
||||
|
||||
private class ImportStateHandler extends Handler {
|
||||
|
||||
public ImportStateHandler() {
|
||||
super(Looper.getMainLooper());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message message) {
|
||||
switch (message.what) {
|
||||
case ImportState.STATE_IDLE: handleStateIdle(); break;
|
||||
case ImportState.STATE_MIGRATING_IN_PROGRESS: handleStateProgress((ProgressDescription)message.obj); break;
|
||||
case ImportState.STATE_MIGRATING_COMPLETE: handleImportComplete(); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ImportServiceConnection implements ServiceConnection {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName className, IBinder service) {
|
||||
importService = ((ApplicationMigrationService.ApplicationMigrationBinder)service).getService();
|
||||
importService.setImportStateHandler(importStateHandler);
|
||||
|
||||
ImportState state = importService.getState();
|
||||
importStateHandler.obtainMessage(state.state, state.progress).sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
importService.setImportStateHandler(null);
|
||||
}
|
||||
}
|
||||
|
||||
private static class NullReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
abortBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
package org.thoughtcrime.securesms.components.reminder;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
|
||||
import org.thoughtcrime.securesms.DatabaseMigrationActivity;
|
||||
import org.thoughtcrime.securesms.MainActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.service.ApplicationMigrationService;
|
||||
|
||||
public class SystemSmsImportReminder extends Reminder {
|
||||
|
||||
public SystemSmsImportReminder(final Context context) {
|
||||
super(context.getString(R.string.reminder_header_sms_import_title),
|
||||
context.getString(R.string.reminder_header_sms_import_text));
|
||||
|
||||
final OnClickListener okListener = v -> {
|
||||
Intent intent = new Intent(context, ApplicationMigrationService.class);
|
||||
intent.setAction(ApplicationMigrationService.MIGRATE_DATABASE);
|
||||
context.startService(intent);
|
||||
|
||||
// TODO [greyson] Navigation
|
||||
Intent nextIntent = MainActivity.clearTop(context);
|
||||
Intent activityIntent = new Intent(context, DatabaseMigrationActivity.class);
|
||||
activityIntent.putExtra("next_intent", nextIntent);
|
||||
context.startActivity(activityIntent);
|
||||
};
|
||||
final OnClickListener cancelListener = new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
ApplicationMigrationService.setDatabaseImported(context);
|
||||
}
|
||||
};
|
||||
setOkListener(okListener);
|
||||
setDismissListener(cancelListener);
|
||||
}
|
||||
|
||||
public static boolean isEligible(Context context) {
|
||||
return !ApplicationMigrationService.isDatabaseImported(context);
|
||||
}
|
||||
}
|
|
@ -137,7 +137,7 @@ public class GroupTable extends DatabaseTable implements RecipientIdDatabaseRefe
|
|||
TIMESTAMP, ACTIVE, MMS, V2_MASTER_KEY, V2_REVISION, V2_DECRYPTED_GROUP, LAST_FORCE_UPDATE_TIMESTAMP
|
||||
};
|
||||
|
||||
static final List<String> TYPED_GROUP_PROJECTION = Stream.of(GROUP_PROJECTION).map(columnName -> TABLE_NAME + "." + columnName).toList();
|
||||
static final List<String> TYPED_GROUP_PROJECTION = Stream.of(GROUP_PROJECTION).filterNot(it -> it.equals(RECIPIENT_ID)).map(columnName -> TABLE_NAME + "." + columnName).toList();
|
||||
|
||||
public GroupTable(Context context, SignalDatabase databaseHelper) {
|
||||
super(context, databaseHelper);
|
||||
|
|
|
@ -48,7 +48,7 @@ public class MediaTable extends DatabaseTable {
|
|||
+ AttachmentTable.TABLE_NAME + "." + AttachmentTable.CAPTION + ", "
|
||||
+ AttachmentTable.TABLE_NAME + "." + AttachmentTable.NAME + ", "
|
||||
+ AttachmentTable.TABLE_NAME + "." + AttachmentTable.UPLOAD_TIMESTAMP + ", "
|
||||
+ MmsTable.TABLE_NAME + "." + MmsTable.MESSAGE_BOX + ", "
|
||||
+ MmsTable.TABLE_NAME + "." + MmsTable.TYPE + ", "
|
||||
+ MmsTable.TABLE_NAME + "." + MmsTable.DATE_SENT + ", "
|
||||
+ MmsTable.TABLE_NAME + "." + MmsTable.DATE_RECEIVED + ", "
|
||||
+ MmsTable.TABLE_NAME + "." + MmsTable.DATE_SERVER + ", "
|
||||
|
@ -67,7 +67,7 @@ public class MediaTable extends DatabaseTable {
|
|||
+ AttachmentTable.DATA + " IS NOT NULL AND "
|
||||
+ "(" + AttachmentTable.QUOTE + " = 0 OR (" + AttachmentTable.QUOTE + " = 1 AND " + AttachmentTable.DATA_HASH + " IS NULL)) AND "
|
||||
+ AttachmentTable.STICKER_PACK_ID + " IS NULL AND "
|
||||
+ MmsTable.RECIPIENT_ID + " > 0 AND "
|
||||
+ MmsTable.TABLE_NAME + "." + MmsTable.RECIPIENT_ID + " > 0 AND "
|
||||
+ THREAD_RECIPIENT_ID + " > 0";
|
||||
|
||||
private static final String UNIQUE_MEDIA_QUERY = "SELECT "
|
||||
|
@ -194,11 +194,11 @@ public class MediaTable extends DatabaseTable {
|
|||
List<DatabaseAttachment> attachments = attachmentDatabase.getAttachments(cursor);
|
||||
RecipientId recipientId = RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.RECIPIENT_ID)));
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.THREAD_ID));
|
||||
boolean outgoing = MessageTable.Types.isOutgoingMessageType(cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.MESSAGE_BOX)));
|
||||
boolean outgoing = MessageTable.Types.isOutgoingMessageType(cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.TYPE)));
|
||||
|
||||
long date;
|
||||
|
||||
if (MmsTable.Types.isPushType(cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.MESSAGE_BOX)))) {
|
||||
if (MmsTable.Types.isPushType(cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.TYPE)))) {
|
||||
date = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.DATE_SENT));
|
||||
} else {
|
||||
date = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.DATE_RECEIVED));
|
||||
|
|
|
@ -197,7 +197,6 @@ public abstract class MessageTable extends DatabaseTable implements MmsSmsColumn
|
|||
public abstract void endTransaction(SQLiteDatabase database);
|
||||
public abstract void setTransactionSuccessful();
|
||||
public abstract void endTransaction();
|
||||
public abstract SQLiteStatement createInsertStatement(SQLiteDatabase database);
|
||||
|
||||
public abstract void ensureMigration();
|
||||
|
||||
|
@ -233,7 +232,7 @@ public abstract class MessageTable extends DatabaseTable implements MmsSmsColumn
|
|||
final @NonNull String getOutgoingTypeClause() {
|
||||
List<String> segments = new ArrayList<>(Types.OUTGOING_MESSAGE_TYPES.length);
|
||||
for (long outgoingMessageType : Types.OUTGOING_MESSAGE_TYPES) {
|
||||
segments.add("(" + getTypeField() + " & " + Types.BASE_TYPE_MASK + " = " + outgoingMessageType + ")");
|
||||
segments.add("(" + getTableName() + "." + getTypeField() + " & " + Types.BASE_TYPE_MASK + " = " + outgoingMessageType + ")");
|
||||
}
|
||||
|
||||
return Util.join(segments, " OR ");
|
||||
|
|
|
@ -4,21 +4,21 @@ package org.thoughtcrime.securesms.database;
|
|||
public interface MmsSmsColumns {
|
||||
|
||||
public static final String ID = "_id";
|
||||
public static final String NORMALIZED_DATE_SENT = "date_sent";
|
||||
public static final String NORMALIZED_DATE_RECEIVED = "date_received";
|
||||
public static final String NORMALIZED_TYPE = "type";
|
||||
public static final String DATE_SENT = "date_sent";
|
||||
public static final String DATE_RECEIVED = "date_received";
|
||||
public static final String TYPE = "type";
|
||||
public static final String DATE_SERVER = "date_server";
|
||||
public static final String THREAD_ID = "thread_id";
|
||||
public static final String READ = "read";
|
||||
public static final String BODY = "body";
|
||||
public static final String RECIPIENT_ID = "address";
|
||||
public static final String ADDRESS_DEVICE_ID = "address_device_id";
|
||||
public static final String RECIPIENT_ID = "recipient_id";
|
||||
public static final String RECIPIENT_DEVICE_ID = "recipient_device_id";
|
||||
public static final String DELIVERY_RECEIPT_COUNT = "delivery_receipt_count";
|
||||
public static final String READ_RECEIPT_COUNT = "read_receipt_count";
|
||||
public static final String VIEWED_RECEIPT_COUNT = "viewed_receipt_count";
|
||||
public static final String MISMATCHED_IDENTITIES = "mismatched_identities";
|
||||
public static final String UNIQUE_ROW_ID = "unique_row_id";
|
||||
public static final String SUBSCRIPTION_ID = "subscription_id";
|
||||
public static final String SMS_SUBSCRIPTION_ID = "subscription_id";
|
||||
public static final String EXPIRES_IN = "expires_in";
|
||||
public static final String EXPIRE_STARTED = "expire_started";
|
||||
public static final String NOTIFIED = "notified";
|
||||
|
|
|
@ -70,30 +70,27 @@ public class MmsSmsTable extends DatabaseTable {
|
|||
|
||||
private static final String[] PROJECTION = { MmsSmsColumns.ID,
|
||||
MmsSmsColumns.UNIQUE_ROW_ID,
|
||||
SmsTable.BODY,
|
||||
SmsTable.TYPE,
|
||||
MmsSmsColumns.BODY,
|
||||
MmsSmsColumns.TYPE,
|
||||
MmsSmsColumns.THREAD_ID,
|
||||
SmsTable.RECIPIENT_ID,
|
||||
SmsTable.ADDRESS_DEVICE_ID,
|
||||
SmsTable.SUBJECT,
|
||||
MmsSmsColumns.NORMALIZED_DATE_SENT,
|
||||
MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
|
||||
SmsTable.RECIPIENT_DEVICE_ID,
|
||||
MmsSmsColumns.DATE_SENT,
|
||||
MmsSmsColumns.DATE_RECEIVED,
|
||||
MmsSmsColumns.DATE_SERVER,
|
||||
MmsTable.MESSAGE_TYPE,
|
||||
MmsTable.MESSAGE_BOX,
|
||||
SmsTable.STATUS,
|
||||
MmsTable.MMS_MESSAGE_TYPE,
|
||||
SmsTable.SMS_STATUS,
|
||||
MmsSmsColumns.UNIDENTIFIED,
|
||||
MmsTable.PART_COUNT,
|
||||
MmsTable.CONTENT_LOCATION,
|
||||
MmsTable.TRANSACTION_ID,
|
||||
MmsTable.MESSAGE_SIZE,
|
||||
MmsTable.EXPIRY,
|
||||
MmsTable.STATUS,
|
||||
MmsTable.MMS_CONTENT_LOCATION,
|
||||
MmsTable.MMS_TRANSACTION_ID,
|
||||
MmsTable.MMS_MESSAGE_SIZE,
|
||||
MmsTable.MMS_EXPIRY,
|
||||
MmsTable.MMS_STATUS,
|
||||
MmsSmsColumns.DELIVERY_RECEIPT_COUNT,
|
||||
MmsSmsColumns.READ_RECEIPT_COUNT,
|
||||
MmsSmsColumns.MISMATCHED_IDENTITIES,
|
||||
MmsTable.NETWORK_FAILURE,
|
||||
MmsSmsColumns.SUBSCRIPTION_ID,
|
||||
MmsTable.NETWORK_FAILURES,
|
||||
MmsSmsColumns.SMS_SUBSCRIPTION_ID,
|
||||
MmsSmsColumns.EXPIRES_IN,
|
||||
MmsSmsColumns.EXPIRE_STARTED,
|
||||
MmsSmsColumns.NOTIFIED,
|
||||
|
@ -103,7 +100,6 @@ public class MmsSmsTable extends DatabaseTable {
|
|||
MmsTable.QUOTE_AUTHOR,
|
||||
MmsTable.QUOTE_BODY,
|
||||
MmsTable.QUOTE_MISSING,
|
||||
MmsTable.QUOTE_ATTACHMENT,
|
||||
MmsTable.QUOTE_TYPE,
|
||||
MmsTable.QUOTE_MENTIONS,
|
||||
MmsTable.SHARED_CONTACTS,
|
||||
|
@ -121,12 +117,12 @@ public class MmsSmsTable extends DatabaseTable {
|
|||
MmsTable.STORY_TYPE,
|
||||
MmsTable.PARENT_STORY_ID};
|
||||
|
||||
private static final String SNIPPET_QUERY = "SELECT " + MmsSmsColumns.ID + ", 0 AS " + TRANSPORT + ", " + SmsTable.TYPE + " AS " + MmsSmsColumns.NORMALIZED_TYPE + ", " + SmsTable.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " FROM " + SmsTable.TABLE_NAME + " " +
|
||||
"WHERE " + MmsSmsColumns.THREAD_ID + " = ? AND " + SmsTable.TYPE + " NOT IN (" + SmsTable.Types.PROFILE_CHANGE_TYPE + ", " + SmsTable.Types.GV1_MIGRATION_TYPE + ", " + SmsTable.Types.CHANGE_NUMBER_TYPE + ", " + SmsTable.Types.BOOST_REQUEST_TYPE + ", " + SmsTable.Types.SMS_EXPORT_TYPE + ") AND " + SmsTable.TYPE + " & " + GROUP_V2_LEAVE_BITS + " != " + GROUP_V2_LEAVE_BITS + " " +
|
||||
private static final String SNIPPET_QUERY = "SELECT " + MmsSmsColumns.ID + ", 0 AS " + TRANSPORT + ", " + MmsSmsColumns.TYPE + ", " + MmsSmsColumns.DATE_RECEIVED + " FROM " + SmsTable.TABLE_NAME + " " +
|
||||
"WHERE " + MmsSmsColumns.THREAD_ID + " = ? AND " + MmsSmsColumns.TYPE + " NOT IN (" + SmsTable.Types.PROFILE_CHANGE_TYPE + ", " + SmsTable.Types.GV1_MIGRATION_TYPE + ", " + SmsTable.Types.CHANGE_NUMBER_TYPE + ", " + SmsTable.Types.BOOST_REQUEST_TYPE + ", " + SmsTable.Types.SMS_EXPORT_TYPE + ") AND " + SmsTable.TYPE + " & " + GROUP_V2_LEAVE_BITS + " != " + GROUP_V2_LEAVE_BITS + " " +
|
||||
"UNION ALL " +
|
||||
"SELECT " + MmsSmsColumns.ID + ", 1 AS " + TRANSPORT + ", " + MmsTable.MESSAGE_BOX + " AS " + MmsSmsColumns.NORMALIZED_TYPE + ", " + MmsTable.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " FROM " + MmsTable.TABLE_NAME + " " +
|
||||
"WHERE " + MmsSmsColumns.THREAD_ID + " = ? AND " + MmsTable.MESSAGE_BOX + " & " + GROUP_V2_LEAVE_BITS + " != " + GROUP_V2_LEAVE_BITS + " AND " + MmsTable.STORY_TYPE + " = 0 AND " + MmsTable.PARENT_STORY_ID + " <= 0 " +
|
||||
"ORDER BY " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC " +
|
||||
"SELECT " + MmsSmsColumns.ID + ", 1 AS " + TRANSPORT + ", " + MmsSmsColumns.TYPE + ", " + MmsTable.DATE_RECEIVED + " FROM " + MmsTable.TABLE_NAME + " " +
|
||||
"WHERE " + MmsSmsColumns.THREAD_ID + " = ? AND " + MmsTable.TYPE + " & " + GROUP_V2_LEAVE_BITS + " != " + GROUP_V2_LEAVE_BITS + " AND " + MmsTable.STORY_TYPE + " = 0 AND " + MmsTable.PARENT_STORY_ID + " <= 0 " +
|
||||
"ORDER BY " + MmsSmsColumns.DATE_RECEIVED + " DESC " +
|
||||
"LIMIT 1";
|
||||
|
||||
public MmsSmsTable(Context context, SignalDatabase databaseHelper) {
|
||||
|
@ -165,7 +161,7 @@ public class MmsSmsTable extends DatabaseTable {
|
|||
public int getMessagePositionOnOrAfterTimestamp(long threadId, long timestamp) {
|
||||
String[] projection = new String[] { "COUNT(*)" };
|
||||
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId + " AND " +
|
||||
MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " >= " + timestamp + " AND " +
|
||||
MmsSmsColumns.DATE_RECEIVED + " >= " + timestamp + " AND " +
|
||||
MmsTable.STORY_TYPE + " = 0 AND " + MmsTable.PARENT_STORY_ID + " <= 0";
|
||||
|
||||
try (Cursor cursor = queryTables(projection, selection, null, null, false)) {
|
||||
|
@ -179,7 +175,7 @@ public class MmsSmsTable extends DatabaseTable {
|
|||
public @Nullable MessageRecord getMessageFor(long timestamp, RecipientId authorId) {
|
||||
Recipient author = Recipient.resolved(authorId);
|
||||
|
||||
try (Cursor cursor = queryTables(PROJECTION, MmsSmsColumns.NORMALIZED_DATE_SENT + " = " + timestamp, null, null, true)) {
|
||||
try (Cursor cursor = queryTables(PROJECTION, MmsSmsColumns.DATE_SENT + " = " + timestamp, null, null, true)) {
|
||||
MmsSmsTable.Reader reader = readerFor(cursor);
|
||||
|
||||
MessageRecord messageRecord;
|
||||
|
@ -210,7 +206,7 @@ public class MmsSmsTable extends DatabaseTable {
|
|||
|
||||
public Cursor getConversation(long threadId, long offset, long limit) {
|
||||
SQLiteDatabase db = databaseHelper.getSignalReadableDatabase();
|
||||
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC";
|
||||
String order = MmsSmsColumns.DATE_RECEIVED + " DESC";
|
||||
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId + " AND " + MmsTable.STORY_TYPE + " = 0 AND " + MmsTable.PARENT_STORY_ID + " <= 0";
|
||||
String limitStr = limit > 0 || offset > 0 ? offset + ", " + limit : null;
|
||||
String query = buildQuery(PROJECTION, selection, order, limitStr, false);
|
||||
|
@ -249,7 +245,7 @@ public class MmsSmsTable extends DatabaseTable {
|
|||
SQLiteDatabase db = databaseHelper.getSignalReadableDatabase();
|
||||
try (Cursor cursor = db.rawQuery(SNIPPET_QUERY, SqlUtil.buildArgs(threadId, threadId))) {
|
||||
if (cursor.moveToFirst()) {
|
||||
return CursorUtil.requireLong(cursor, MmsSmsColumns.NORMALIZED_TYPE);
|
||||
return CursorUtil.requireLong(cursor, MmsSmsColumns.TYPE);
|
||||
} else {
|
||||
throw new NoSuchMessageException("no message");
|
||||
}
|
||||
|
@ -266,14 +262,14 @@ public class MmsSmsTable extends DatabaseTable {
|
|||
.append(MmsSmsColumns.THREAD_ID + " = ")
|
||||
.append(stickyThread.getConversationId().getThreadId())
|
||||
.append(" AND ")
|
||||
.append(MmsSmsColumns.NORMALIZED_DATE_RECEIVED)
|
||||
.append(MmsSmsColumns.DATE_RECEIVED)
|
||||
.append(" >= ")
|
||||
.append(stickyThread.getEarliestTimestamp())
|
||||
.append(getStickyWherePartForParentStoryId(stickyThread.getConversationId().getGroupStoryId()))
|
||||
.append(")");
|
||||
}
|
||||
|
||||
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " ASC";
|
||||
String order = MmsSmsColumns.DATE_RECEIVED + " ASC";
|
||||
String selection = MmsSmsColumns.NOTIFIED + " = 0 AND " + MmsTable.STORY_TYPE + " = 0 AND (" + MmsSmsColumns.READ + " = 0 OR " + MmsSmsColumns.REACTIONS_UNREAD + " = 1" + (stickyQuery.length() > 0 ? " OR (" + stickyQuery + ")" : "") + ")";
|
||||
|
||||
return queryTables(PROJECTION, selection, order, null, true);
|
||||
|
@ -304,7 +300,7 @@ public class MmsSmsTable extends DatabaseTable {
|
|||
|
||||
RecipientId author = targetMessage.isOutgoing() ? Recipient.self().getId() : targetMessage.getRecipient().getId();
|
||||
String query = MmsTable.QUOTE_ID + " = " + targetMessage.getDateSent() + " AND " + MmsTable.QUOTE_AUTHOR + " = " + author.serialize();
|
||||
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC";
|
||||
String order = MmsSmsColumns.DATE_RECEIVED + " DESC";
|
||||
|
||||
List<MessageRecord> records = new ArrayList<>();
|
||||
|
||||
|
@ -421,7 +417,7 @@ public class MmsSmsTable extends DatabaseTable {
|
|||
}
|
||||
|
||||
public int getMessageCountBeforeDate(long date) {
|
||||
String selection = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " < " + date;
|
||||
String selection = MmsSmsColumns.DATE_RECEIVED + " < " + date;
|
||||
|
||||
try (Cursor cursor = queryTables(new String[] { "COUNT(*)" }, selection, null, null, false)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
|
@ -761,10 +757,10 @@ public class MmsSmsTable extends DatabaseTable {
|
|||
}
|
||||
|
||||
public int getQuotedMessagePosition(long threadId, long quoteId, @NonNull RecipientId recipientId) {
|
||||
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC";
|
||||
String order = MmsSmsColumns.DATE_RECEIVED + " DESC";
|
||||
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId + " AND " + MmsTable.STORY_TYPE + " = 0" + " AND " + MmsTable.PARENT_STORY_ID + " <= 0";
|
||||
|
||||
try (Cursor cursor = queryTables(new String[]{ MmsSmsColumns.NORMALIZED_DATE_SENT, MmsSmsColumns.RECIPIENT_ID, MmsSmsColumns.REMOTE_DELETED}, selection, order, null, false)) {
|
||||
try (Cursor cursor = queryTables(new String[]{ MmsSmsColumns.DATE_SENT, MmsSmsColumns.RECIPIENT_ID, MmsSmsColumns.REMOTE_DELETED}, selection, order, null, false)) {
|
||||
boolean isOwnNumber = Recipient.resolved(recipientId).isSelf();
|
||||
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
|
@ -784,10 +780,10 @@ public class MmsSmsTable extends DatabaseTable {
|
|||
}
|
||||
|
||||
public int getMessagePositionInConversation(long threadId, long receivedTimestamp, @NonNull RecipientId recipientId) {
|
||||
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC";
|
||||
String order = MmsSmsColumns.DATE_RECEIVED + " DESC";
|
||||
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId + " AND " + MmsTable.STORY_TYPE + " = 0" + " AND " + MmsTable.PARENT_STORY_ID + " <= 0";
|
||||
|
||||
try (Cursor cursor = queryTables(new String[]{ MmsSmsColumns.NORMALIZED_DATE_RECEIVED, MmsSmsColumns.RECIPIENT_ID, MmsSmsColumns.REMOTE_DELETED}, selection, order, null, false)) {
|
||||
try (Cursor cursor = queryTables(new String[]{ MmsSmsColumns.DATE_RECEIVED, MmsSmsColumns.RECIPIENT_ID, MmsSmsColumns.REMOTE_DELETED}, selection, order, null, false)) {
|
||||
boolean isOwnNumber = Recipient.resolved(recipientId).isSelf();
|
||||
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
|
@ -831,14 +827,14 @@ public class MmsSmsTable extends DatabaseTable {
|
|||
final String selection;
|
||||
|
||||
if (groupStoryId > 0) {
|
||||
order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " ASC";
|
||||
order = MmsSmsColumns.DATE_RECEIVED + " ASC";
|
||||
selection = MmsSmsColumns.THREAD_ID + " = " + threadId + " AND " +
|
||||
MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " < " + receivedTimestamp + " AND " +
|
||||
MmsSmsColumns.DATE_RECEIVED + " < " + receivedTimestamp + " AND " +
|
||||
MmsTable.STORY_TYPE + " = 0 AND " + MmsTable.PARENT_STORY_ID + " = " + groupStoryId;
|
||||
} else {
|
||||
order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC";
|
||||
order = MmsSmsColumns.DATE_RECEIVED + " DESC";
|
||||
selection = MmsSmsColumns.THREAD_ID + " = " + threadId + " AND " +
|
||||
MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " > " + receivedTimestamp + " AND " +
|
||||
MmsSmsColumns.DATE_RECEIVED + " > " + receivedTimestamp + " AND " +
|
||||
MmsTable.STORY_TYPE + " = 0 AND " + MmsTable.PARENT_STORY_ID + " <= 0";
|
||||
}
|
||||
|
||||
|
@ -851,10 +847,10 @@ public class MmsSmsTable extends DatabaseTable {
|
|||
}
|
||||
|
||||
public long getTimestampForFirstMessageAfterDate(long date) {
|
||||
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " ASC";
|
||||
String selection = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " > " + date;
|
||||
String order = MmsSmsColumns.DATE_RECEIVED + " ASC";
|
||||
String selection = MmsSmsColumns.DATE_RECEIVED + " > " + date;
|
||||
|
||||
try (Cursor cursor = queryTables(new String[] { MmsSmsColumns.NORMALIZED_DATE_RECEIVED }, selection, order, "1", false)) {
|
||||
try (Cursor cursor = queryTables(new String[] { MmsSmsColumns.DATE_RECEIVED }, selection, order, "1", false)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
return cursor.getLong(0);
|
||||
}
|
||||
|
@ -926,41 +922,37 @@ public class MmsSmsTable extends DatabaseTable {
|
|||
attachmentJsonJoin = "NULL";
|
||||
}
|
||||
|
||||
String[] mmsProjection = { MmsTable.DATE_SENT + " AS " + MmsSmsColumns.NORMALIZED_DATE_SENT,
|
||||
MmsTable.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
|
||||
String[] mmsProjection = { MmsSmsColumns.DATE_SENT,
|
||||
MmsSmsColumns.DATE_RECEIVED,
|
||||
MmsTable.TABLE_NAME + "." + MmsTable.ID + " AS " + MmsSmsColumns.ID,
|
||||
"'MMS::' || " + MmsTable.TABLE_NAME + "." + MmsTable.ID + " || '::' || " + MmsTable.DATE_SENT + " AS " + MmsSmsColumns.UNIQUE_ROW_ID,
|
||||
attachmentJsonJoin + " AS " + AttachmentTable.ATTACHMENT_JSON_ALIAS,
|
||||
attachmentJsonJoin + " AS " + AttachmentTable.ATTACHMENT_JSON_ALIAS,
|
||||
SmsTable.BODY,
|
||||
MmsSmsColumns.READ,
|
||||
MmsSmsColumns.THREAD_ID,
|
||||
SmsTable.TYPE,
|
||||
SmsTable.RECIPIENT_ID,
|
||||
SmsTable.ADDRESS_DEVICE_ID,
|
||||
SmsTable.SUBJECT,
|
||||
MmsTable.MESSAGE_TYPE,
|
||||
MmsTable.MESSAGE_BOX,
|
||||
SmsTable.STATUS,
|
||||
MmsTable.PART_COUNT,
|
||||
MmsTable.CONTENT_LOCATION,
|
||||
MmsTable.TRANSACTION_ID,
|
||||
MmsTable.MESSAGE_SIZE,
|
||||
MmsTable.EXPIRY,
|
||||
MmsTable.STATUS,
|
||||
MmsSmsColumns.TYPE,
|
||||
MmsSmsColumns.RECIPIENT_ID,
|
||||
MmsSmsColumns.RECIPIENT_DEVICE_ID,
|
||||
MmsTable.MMS_MESSAGE_TYPE,
|
||||
SmsTable.SMS_STATUS,
|
||||
MmsTable.MMS_CONTENT_LOCATION,
|
||||
MmsTable.MMS_TRANSACTION_ID,
|
||||
MmsTable.MMS_MESSAGE_SIZE,
|
||||
MmsTable.MMS_EXPIRY,
|
||||
MmsTable.MMS_STATUS,
|
||||
MmsTable.UNIDENTIFIED,
|
||||
MmsSmsColumns.DELIVERY_RECEIPT_COUNT,
|
||||
MmsSmsColumns.READ_RECEIPT_COUNT,
|
||||
MmsSmsColumns.MISMATCHED_IDENTITIES,
|
||||
MmsSmsColumns.SUBSCRIPTION_ID,
|
||||
MmsSmsColumns.SMS_SUBSCRIPTION_ID,
|
||||
MmsSmsColumns.EXPIRES_IN,
|
||||
MmsSmsColumns.EXPIRE_STARTED,
|
||||
MmsSmsColumns.NOTIFIED,
|
||||
MmsTable.NETWORK_FAILURE, TRANSPORT,
|
||||
MmsTable.NETWORK_FAILURES, TRANSPORT,
|
||||
MmsTable.QUOTE_ID,
|
||||
MmsTable.QUOTE_AUTHOR,
|
||||
MmsTable.QUOTE_BODY,
|
||||
MmsTable.QUOTE_MISSING,
|
||||
MmsTable.QUOTE_ATTACHMENT,
|
||||
MmsTable.QUOTE_TYPE,
|
||||
MmsTable.QUOTE_MENTIONS,
|
||||
MmsTable.SHARED_CONTACTS,
|
||||
|
@ -978,26 +970,36 @@ public class MmsSmsTable extends DatabaseTable {
|
|||
MmsTable.STORY_TYPE,
|
||||
MmsTable.PARENT_STORY_ID};
|
||||
|
||||
String[] smsProjection = { SmsTable.DATE_SENT + " AS " + MmsSmsColumns.NORMALIZED_DATE_SENT,
|
||||
SmsTable.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
|
||||
String[] smsProjection = { MmsSmsColumns.DATE_SENT,
|
||||
MmsSmsColumns.DATE_RECEIVED,
|
||||
MmsSmsColumns.ID, "'SMS::' || " + MmsSmsColumns.ID + " || '::' || " + SmsTable.DATE_SENT + " AS " + MmsSmsColumns.UNIQUE_ROW_ID,
|
||||
"NULL AS " + AttachmentTable.ATTACHMENT_JSON_ALIAS,
|
||||
SmsTable.BODY, MmsSmsColumns.READ, MmsSmsColumns.THREAD_ID,
|
||||
SmsTable.TYPE, SmsTable.RECIPIENT_ID, SmsTable.ADDRESS_DEVICE_ID, SmsTable.SUBJECT, MmsTable.MESSAGE_TYPE,
|
||||
MmsTable.MESSAGE_BOX, SmsTable.STATUS, MmsTable.PART_COUNT,
|
||||
MmsTable.CONTENT_LOCATION, MmsTable.TRANSACTION_ID,
|
||||
MmsTable.MESSAGE_SIZE, MmsTable.EXPIRY, MmsTable.STATUS,
|
||||
"NULL AS " + AttachmentTable.ATTACHMENT_JSON_ALIAS,
|
||||
SmsTable.BODY,
|
||||
MmsSmsColumns.READ,
|
||||
MmsSmsColumns.THREAD_ID,
|
||||
MmsSmsColumns.TYPE,
|
||||
SmsTable.RECIPIENT_ID,
|
||||
SmsTable.RECIPIENT_DEVICE_ID,
|
||||
MmsTable.MMS_MESSAGE_TYPE,
|
||||
SmsTable.SMS_STATUS,
|
||||
MmsTable.MMS_CONTENT_LOCATION,
|
||||
MmsTable.MMS_TRANSACTION_ID,
|
||||
MmsTable.MMS_MESSAGE_SIZE,
|
||||
MmsTable.MMS_EXPIRY,
|
||||
MmsTable.MMS_STATUS,
|
||||
MmsTable.UNIDENTIFIED,
|
||||
MmsSmsColumns.DELIVERY_RECEIPT_COUNT, MmsSmsColumns.READ_RECEIPT_COUNT,
|
||||
MmsSmsColumns.DELIVERY_RECEIPT_COUNT,
|
||||
MmsSmsColumns.READ_RECEIPT_COUNT,
|
||||
MmsSmsColumns.MISMATCHED_IDENTITIES,
|
||||
MmsSmsColumns.SUBSCRIPTION_ID, MmsSmsColumns.EXPIRES_IN, MmsSmsColumns.EXPIRE_STARTED,
|
||||
MmsSmsColumns.SMS_SUBSCRIPTION_ID,
|
||||
MmsSmsColumns.EXPIRES_IN,
|
||||
MmsSmsColumns.EXPIRE_STARTED,
|
||||
MmsSmsColumns.NOTIFIED,
|
||||
MmsTable.NETWORK_FAILURE, TRANSPORT,
|
||||
MmsTable.NETWORK_FAILURES, TRANSPORT,
|
||||
MmsTable.QUOTE_ID,
|
||||
MmsTable.QUOTE_AUTHOR,
|
||||
MmsTable.QUOTE_BODY,
|
||||
MmsTable.QUOTE_MISSING,
|
||||
MmsTable.QUOTE_ATTACHMENT,
|
||||
MmsTable.QUOTE_TYPE,
|
||||
MmsTable.QUOTE_MENTIONS,
|
||||
MmsTable.SHARED_CONTACTS,
|
||||
|
@ -1038,32 +1040,30 @@ public class MmsSmsTable extends DatabaseTable {
|
|||
mmsColumnsPresent.add(MmsSmsColumns.THREAD_ID);
|
||||
mmsColumnsPresent.add(MmsSmsColumns.BODY);
|
||||
mmsColumnsPresent.add(MmsSmsColumns.RECIPIENT_ID);
|
||||
mmsColumnsPresent.add(MmsSmsColumns.ADDRESS_DEVICE_ID);
|
||||
mmsColumnsPresent.add(MmsSmsColumns.RECIPIENT_DEVICE_ID);
|
||||
mmsColumnsPresent.add(MmsSmsColumns.DELIVERY_RECEIPT_COUNT);
|
||||
mmsColumnsPresent.add(MmsSmsColumns.READ_RECEIPT_COUNT);
|
||||
mmsColumnsPresent.add(MmsSmsColumns.MISMATCHED_IDENTITIES);
|
||||
mmsColumnsPresent.add(MmsSmsColumns.SUBSCRIPTION_ID);
|
||||
mmsColumnsPresent.add(MmsSmsColumns.SMS_SUBSCRIPTION_ID);
|
||||
mmsColumnsPresent.add(MmsSmsColumns.EXPIRES_IN);
|
||||
mmsColumnsPresent.add(MmsSmsColumns.EXPIRE_STARTED);
|
||||
mmsColumnsPresent.add(MmsTable.MESSAGE_TYPE);
|
||||
mmsColumnsPresent.add(MmsTable.MESSAGE_BOX);
|
||||
mmsColumnsPresent.add(MmsTable.MMS_MESSAGE_TYPE);
|
||||
mmsColumnsPresent.add(MmsTable.TYPE);
|
||||
mmsColumnsPresent.add(MmsTable.DATE_SENT);
|
||||
mmsColumnsPresent.add(MmsTable.DATE_RECEIVED);
|
||||
mmsColumnsPresent.add(MmsTable.DATE_SERVER);
|
||||
mmsColumnsPresent.add(MmsTable.PART_COUNT);
|
||||
mmsColumnsPresent.add(MmsTable.CONTENT_LOCATION);
|
||||
mmsColumnsPresent.add(MmsTable.TRANSACTION_ID);
|
||||
mmsColumnsPresent.add(MmsTable.MESSAGE_SIZE);
|
||||
mmsColumnsPresent.add(MmsTable.EXPIRY);
|
||||
mmsColumnsPresent.add(MmsTable.MMS_CONTENT_LOCATION);
|
||||
mmsColumnsPresent.add(MmsTable.MMS_TRANSACTION_ID);
|
||||
mmsColumnsPresent.add(MmsTable.MMS_MESSAGE_SIZE);
|
||||
mmsColumnsPresent.add(MmsTable.MMS_EXPIRY);
|
||||
mmsColumnsPresent.add(MmsTable.NOTIFIED);
|
||||
mmsColumnsPresent.add(MmsTable.STATUS);
|
||||
mmsColumnsPresent.add(MmsTable.MMS_STATUS);
|
||||
mmsColumnsPresent.add(MmsTable.UNIDENTIFIED);
|
||||
mmsColumnsPresent.add(MmsTable.NETWORK_FAILURE);
|
||||
mmsColumnsPresent.add(MmsTable.NETWORK_FAILURES);
|
||||
mmsColumnsPresent.add(MmsTable.QUOTE_ID);
|
||||
mmsColumnsPresent.add(MmsTable.QUOTE_AUTHOR);
|
||||
mmsColumnsPresent.add(MmsTable.QUOTE_BODY);
|
||||
mmsColumnsPresent.add(MmsTable.QUOTE_MISSING);
|
||||
mmsColumnsPresent.add(MmsTable.QUOTE_ATTACHMENT);
|
||||
mmsColumnsPresent.add(MmsTable.QUOTE_TYPE);
|
||||
mmsColumnsPresent.add(MmsTable.QUOTE_MENTIONS);
|
||||
mmsColumnsPresent.add(MmsTable.SHARED_CONTACTS);
|
||||
|
@ -1084,22 +1084,21 @@ public class MmsSmsTable extends DatabaseTable {
|
|||
smsColumnsPresent.add(MmsSmsColumns.ID);
|
||||
smsColumnsPresent.add(MmsSmsColumns.BODY);
|
||||
smsColumnsPresent.add(MmsSmsColumns.RECIPIENT_ID);
|
||||
smsColumnsPresent.add(MmsSmsColumns.ADDRESS_DEVICE_ID);
|
||||
smsColumnsPresent.add(MmsSmsColumns.RECIPIENT_DEVICE_ID);
|
||||
smsColumnsPresent.add(MmsSmsColumns.READ);
|
||||
smsColumnsPresent.add(MmsSmsColumns.THREAD_ID);
|
||||
smsColumnsPresent.add(MmsSmsColumns.DELIVERY_RECEIPT_COUNT);
|
||||
smsColumnsPresent.add(MmsSmsColumns.READ_RECEIPT_COUNT);
|
||||
smsColumnsPresent.add(MmsSmsColumns.MISMATCHED_IDENTITIES);
|
||||
smsColumnsPresent.add(MmsSmsColumns.SUBSCRIPTION_ID);
|
||||
smsColumnsPresent.add(MmsSmsColumns.SMS_SUBSCRIPTION_ID);
|
||||
smsColumnsPresent.add(MmsSmsColumns.EXPIRES_IN);
|
||||
smsColumnsPresent.add(MmsSmsColumns.EXPIRE_STARTED);
|
||||
smsColumnsPresent.add(MmsSmsColumns.NOTIFIED);
|
||||
smsColumnsPresent.add(SmsTable.TYPE);
|
||||
smsColumnsPresent.add(SmsTable.SUBJECT);
|
||||
smsColumnsPresent.add(SmsTable.DATE_SENT);
|
||||
smsColumnsPresent.add(SmsTable.DATE_RECEIVED);
|
||||
smsColumnsPresent.add(SmsTable.DATE_SERVER);
|
||||
smsColumnsPresent.add(SmsTable.STATUS);
|
||||
smsColumnsPresent.add(SmsTable.SMS_STATUS);
|
||||
smsColumnsPresent.add(SmsTable.UNIDENTIFIED);
|
||||
smsColumnsPresent.add(SmsTable.REACTIONS_UNREAD);
|
||||
smsColumnsPresent.add(SmsTable.REACTIONS_LAST_SEEN);
|
||||
|
|
|
@ -31,8 +31,6 @@ import com.google.android.mms.pdu_alt.NotificationInd;
|
|||
import com.google.android.mms.pdu_alt.PduHeaders;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
|
||||
import net.zetetic.database.sqlcipher.SQLiteStatement;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
@ -121,80 +119,73 @@ public class MmsTable extends MessageTable {
|
|||
|
||||
private static final String TAG = Log.tag(MmsTable.class);
|
||||
|
||||
public static final String TABLE_NAME = "mms";
|
||||
static final String DATE_SENT = "date";
|
||||
static final String DATE_RECEIVED = "date_received";
|
||||
public static final String MESSAGE_BOX = "msg_box";
|
||||
static final String CONTENT_LOCATION = "ct_l";
|
||||
static final String EXPIRY = "exp";
|
||||
public static final String MESSAGE_TYPE = "m_type";
|
||||
static final String MESSAGE_SIZE = "m_size";
|
||||
static final String STATUS = "st";
|
||||
static final String TRANSACTION_ID = "tr_id";
|
||||
static final String PART_COUNT = "part_count";
|
||||
static final String NETWORK_FAILURE = "network_failures";
|
||||
public static final String TABLE_NAME = "mms";
|
||||
static final String MMS_CONTENT_LOCATION = "ct_l";
|
||||
static final String MMS_EXPIRY = "exp";
|
||||
public static final String MMS_MESSAGE_TYPE = "m_type";
|
||||
static final String MMS_MESSAGE_SIZE = "m_size";
|
||||
static final String MMS_STATUS = "st";
|
||||
static final String MMS_TRANSACTION_ID = "tr_id";
|
||||
static final String NETWORK_FAILURES = "network_failures";
|
||||
|
||||
static final String QUOTE_ID = "quote_id";
|
||||
static final String QUOTE_AUTHOR = "quote_author";
|
||||
static final String QUOTE_BODY = "quote_body";
|
||||
static final String QUOTE_ATTACHMENT = "quote_attachment";
|
||||
static final String QUOTE_MISSING = "quote_missing";
|
||||
static final String QUOTE_MENTIONS = "quote_mentions";
|
||||
static final String QUOTE_TYPE = "quote_type";
|
||||
|
||||
static final String SHARED_CONTACTS = "shared_contacts";
|
||||
static final String LINK_PREVIEWS = "previews";
|
||||
static final String LINK_PREVIEWS = "link_previews";
|
||||
static final String MENTIONS_SELF = "mentions_self";
|
||||
static final String MESSAGE_RANGES = "ranges";
|
||||
static final String MESSAGE_RANGES = "message_ranges";
|
||||
|
||||
public static final String VIEW_ONCE = "reveal_duration";
|
||||
public static final String STORY_TYPE = "is_story";
|
||||
public static final String VIEW_ONCE = "view_once";
|
||||
public static final String STORY_TYPE = "story_type";
|
||||
static final String PARENT_STORY_ID = "parent_story_id";
|
||||
|
||||
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
|
||||
THREAD_ID + " INTEGER, " +
|
||||
DATE_SENT + " INTEGER, " +
|
||||
DATE_RECEIVED + " INTEGER, " +
|
||||
DATE_SENT + " INTEGER NOT NULL, " +
|
||||
DATE_RECEIVED + " INTEGER NOT NULL, " +
|
||||
DATE_SERVER + " INTEGER DEFAULT -1, " +
|
||||
MESSAGE_BOX + " INTEGER, " +
|
||||
READ + " INTEGER DEFAULT 0, " +
|
||||
THREAD_ID + " INTEGER NOT NULL REFERENCES " + ThreadTable.TABLE_NAME + " (" + ThreadTable.ID + ") ON DELETE CASCADE, " +
|
||||
RECIPIENT_ID + " INTEGER NOT NULL REFERENCES " + RecipientTable.TABLE_NAME + " (" + RecipientTable.ID + ") ON DELETE CASCADE, " +
|
||||
RECIPIENT_DEVICE_ID + " INTEGER, " +
|
||||
TYPE + " INTEGER NOT NULL, " +
|
||||
BODY + " TEXT, " +
|
||||
PART_COUNT + " INTEGER, " +
|
||||
CONTENT_LOCATION + " TEXT, " +
|
||||
RECIPIENT_ID + " INTEGER, " +
|
||||
ADDRESS_DEVICE_ID + " INTEGER, " +
|
||||
EXPIRY + " INTEGER, " +
|
||||
MESSAGE_TYPE + " INTEGER, " +
|
||||
MESSAGE_SIZE + " INTEGER, " +
|
||||
STATUS + " INTEGER, " +
|
||||
TRANSACTION_ID + " TEXT, " +
|
||||
READ + " INTEGER DEFAULT 0, " +
|
||||
MMS_CONTENT_LOCATION + " TEXT, " +
|
||||
MMS_EXPIRY + " INTEGER, " +
|
||||
MMS_MESSAGE_TYPE + " INTEGER, " +
|
||||
MMS_MESSAGE_SIZE + " INTEGER, " +
|
||||
MMS_STATUS + " INTEGER, " +
|
||||
MMS_TRANSACTION_ID + " TEXT, " +
|
||||
SMS_SUBSCRIPTION_ID + " INTEGER DEFAULT -1, " +
|
||||
RECEIPT_TIMESTAMP + " INTEGER DEFAULT -1, " +
|
||||
DELIVERY_RECEIPT_COUNT + " INTEGER DEFAULT 0, " +
|
||||
READ_RECEIPT_COUNT + " INTEGER DEFAULT 0, " +
|
||||
VIEWED_RECEIPT_COUNT + " INTEGER DEFAULT 0, " +
|
||||
MISMATCHED_IDENTITIES + " TEXT DEFAULT NULL, " +
|
||||
NETWORK_FAILURE + " TEXT DEFAULT NULL," +
|
||||
SUBSCRIPTION_ID + " INTEGER DEFAULT -1, " +
|
||||
NETWORK_FAILURES + " TEXT DEFAULT NULL," +
|
||||
EXPIRES_IN + " INTEGER DEFAULT 0, " +
|
||||
EXPIRE_STARTED + " INTEGER DEFAULT 0, " +
|
||||
NOTIFIED + " INTEGER DEFAULT 0, " +
|
||||
READ_RECEIPT_COUNT + " INTEGER DEFAULT 0, " +
|
||||
QUOTE_ID + " INTEGER DEFAULT 0, " +
|
||||
QUOTE_AUTHOR + " TEXT, " +
|
||||
QUOTE_BODY + " TEXT, " +
|
||||
QUOTE_ATTACHMENT + " INTEGER DEFAULT -1, " +
|
||||
QUOTE_AUTHOR + " INTEGER DEFAULT 0, " +
|
||||
QUOTE_BODY + " TEXT DEFAULT NULL, " +
|
||||
QUOTE_MISSING + " INTEGER DEFAULT 0, " +
|
||||
QUOTE_MENTIONS + " BLOB DEFAULT NULL," +
|
||||
QUOTE_TYPE + " INTEGER DEFAULT 0," +
|
||||
SHARED_CONTACTS + " TEXT, " +
|
||||
SHARED_CONTACTS + " TEXT DEFAULT NULL, " +
|
||||
UNIDENTIFIED + " INTEGER DEFAULT 0, " +
|
||||
LINK_PREVIEWS + " TEXT, " +
|
||||
LINK_PREVIEWS + " TEXT DEFAULT NULL, " +
|
||||
VIEW_ONCE + " INTEGER DEFAULT 0, " +
|
||||
REACTIONS_UNREAD + " INTEGER DEFAULT 0, " +
|
||||
REACTIONS_LAST_SEEN + " INTEGER DEFAULT -1, " +
|
||||
REMOTE_DELETED + " INTEGER DEFAULT 0, " +
|
||||
MENTIONS_SELF + " INTEGER DEFAULT 0, " +
|
||||
NOTIFIED_TIMESTAMP + " INTEGER DEFAULT 0, " +
|
||||
VIEWED_RECEIPT_COUNT + " INTEGER DEFAULT 0, " +
|
||||
SERVER_GUID + " TEXT DEFAULT NULL, " +
|
||||
RECEIPT_TIMESTAMP + " INTEGER DEFAULT -1, " +
|
||||
MESSAGE_RANGES + " BLOB DEFAULT NULL, " +
|
||||
STORY_TYPE + " INTEGER DEFAULT 0, " +
|
||||
PARENT_STORY_ID + " INTEGER DEFAULT 0, " +
|
||||
|
@ -203,33 +194,64 @@ public class MmsTable extends MessageTable {
|
|||
|
||||
public static final String[] CREATE_INDEXS = {
|
||||
"CREATE INDEX IF NOT EXISTS mms_read_and_notified_and_thread_id_index ON " + TABLE_NAME + "(" + READ + "," + NOTIFIED + "," + THREAD_ID + ");",
|
||||
"CREATE INDEX IF NOT EXISTS mms_message_box_index ON " + TABLE_NAME + " (" + MESSAGE_BOX + ");",
|
||||
"CREATE INDEX IF NOT EXISTS mms_type_index ON " + TABLE_NAME + " (" + TYPE + ");",
|
||||
"CREATE INDEX IF NOT EXISTS mms_date_sent_index ON " + TABLE_NAME + " (" + DATE_SENT + ", " + RECIPIENT_ID + ", " + THREAD_ID + ");",
|
||||
"CREATE INDEX IF NOT EXISTS mms_date_server_index ON " + TABLE_NAME + " (" + DATE_SERVER + ");",
|
||||
"CREATE INDEX IF NOT EXISTS mms_thread_date_index ON " + TABLE_NAME + " (" + THREAD_ID + ", " + DATE_RECEIVED + ");",
|
||||
"CREATE INDEX IF NOT EXISTS mms_reactions_unread_index ON " + TABLE_NAME + " (" + REACTIONS_UNREAD + ");",
|
||||
"CREATE INDEX IF NOT EXISTS mms_is_story_index ON " + TABLE_NAME + " (" + STORY_TYPE + ");",
|
||||
"CREATE INDEX IF NOT EXISTS mms_story_type_index ON " + TABLE_NAME + " (" + STORY_TYPE + ");",
|
||||
"CREATE INDEX IF NOT EXISTS mms_parent_story_id_index ON " + TABLE_NAME + " (" + PARENT_STORY_ID + ");",
|
||||
"CREATE INDEX IF NOT EXISTS mms_thread_story_parent_story_index ON " + TABLE_NAME + " (" + THREAD_ID + ", " + DATE_RECEIVED + "," + STORY_TYPE + "," + PARENT_STORY_ID + ");",
|
||||
"CREATE INDEX IF NOT EXISTS mms_quote_id_quote_author_index ON " + TABLE_NAME + "(" + QUOTE_ID + ", " + QUOTE_AUTHOR + ");",
|
||||
"CREATE INDEX IF NOT EXISTS mms_exported_index ON " + TABLE_NAME + " (" + EXPORTED + ");",
|
||||
"CREATE INDEX IF NOT EXISTS mms_id_msg_box_payment_transactions_index ON " + TABLE_NAME + " (" + ID + "," + MESSAGE_BOX + ") WHERE " + MESSAGE_BOX + " & " + Types.SPECIAL_TYPE_PAYMENTS_NOTIFICATION + " != 0;"
|
||||
"CREATE INDEX IF NOT EXISTS mms_id_type_payment_transactions_index ON " + TABLE_NAME + " (" + ID + "," + TYPE + ") WHERE " + TYPE + " & " + Types.SPECIAL_TYPE_PAYMENTS_NOTIFICATION + " != 0;"
|
||||
};
|
||||
|
||||
private static final String[] MMS_PROJECTION = new String[] {
|
||||
MmsTable.TABLE_NAME + "." + ID + " AS " + ID,
|
||||
THREAD_ID, DATE_SENT + " AS " + NORMALIZED_DATE_SENT,
|
||||
DATE_RECEIVED + " AS " + NORMALIZED_DATE_RECEIVED,
|
||||
THREAD_ID,
|
||||
DATE_SENT,
|
||||
DATE_RECEIVED,
|
||||
DATE_SERVER,
|
||||
MESSAGE_BOX, READ,
|
||||
CONTENT_LOCATION, EXPIRY, MESSAGE_TYPE,
|
||||
MESSAGE_SIZE, STATUS, TRANSACTION_ID,
|
||||
BODY, PART_COUNT, RECIPIENT_ID, ADDRESS_DEVICE_ID,
|
||||
DELIVERY_RECEIPT_COUNT, READ_RECEIPT_COUNT, MISMATCHED_IDENTITIES, NETWORK_FAILURE, SUBSCRIPTION_ID,
|
||||
EXPIRES_IN, EXPIRE_STARTED, NOTIFIED, QUOTE_ID, QUOTE_AUTHOR, QUOTE_BODY, QUOTE_ATTACHMENT, QUOTE_TYPE, QUOTE_MISSING, QUOTE_MENTIONS,
|
||||
SHARED_CONTACTS, LINK_PREVIEWS, UNIDENTIFIED, VIEW_ONCE, REACTIONS_UNREAD, REACTIONS_LAST_SEEN,
|
||||
REMOTE_DELETED, MENTIONS_SELF, NOTIFIED_TIMESTAMP, VIEWED_RECEIPT_COUNT, RECEIPT_TIMESTAMP, MESSAGE_RANGES,
|
||||
STORY_TYPE, PARENT_STORY_ID,
|
||||
TYPE,
|
||||
READ,
|
||||
MMS_CONTENT_LOCATION,
|
||||
MMS_EXPIRY,
|
||||
MMS_MESSAGE_TYPE,
|
||||
MMS_MESSAGE_SIZE,
|
||||
MMS_STATUS,
|
||||
MMS_TRANSACTION_ID,
|
||||
BODY,
|
||||
RECIPIENT_ID,
|
||||
RECIPIENT_DEVICE_ID,
|
||||
DELIVERY_RECEIPT_COUNT,
|
||||
READ_RECEIPT_COUNT,
|
||||
MISMATCHED_IDENTITIES,
|
||||
NETWORK_FAILURES,
|
||||
SMS_SUBSCRIPTION_ID,
|
||||
EXPIRES_IN,
|
||||
EXPIRE_STARTED,
|
||||
NOTIFIED,
|
||||
QUOTE_ID,
|
||||
QUOTE_AUTHOR,
|
||||
QUOTE_BODY,
|
||||
QUOTE_TYPE,
|
||||
QUOTE_MISSING,
|
||||
QUOTE_MENTIONS,
|
||||
SHARED_CONTACTS,
|
||||
LINK_PREVIEWS,
|
||||
UNIDENTIFIED,
|
||||
VIEW_ONCE,
|
||||
REACTIONS_UNREAD,
|
||||
REACTIONS_LAST_SEEN,
|
||||
REMOTE_DELETED,
|
||||
MENTIONS_SELF,
|
||||
NOTIFIED_TIMESTAMP,
|
||||
VIEWED_RECEIPT_COUNT,
|
||||
RECEIPT_TIMESTAMP,
|
||||
MESSAGE_RANGES,
|
||||
STORY_TYPE,
|
||||
PARENT_STORY_ID,
|
||||
"json_group_array(json_object(" +
|
||||
"'" + AttachmentTable.ROW_ID + "', " + AttachmentTable.TABLE_NAME + "." + AttachmentTable.ROW_ID + ", " +
|
||||
"'" + AttachmentTable.UNIQUE_ID + "', " + AttachmentTable.TABLE_NAME + "." + AttachmentTable.UNIQUE_ID + ", " +
|
||||
|
@ -266,9 +288,6 @@ public class MmsTable extends MessageTable {
|
|||
|
||||
private static final String RAW_ID_WHERE = TABLE_NAME + "._id = ?";
|
||||
|
||||
private static final String OUTGOING_INSECURE_MESSAGES_CLAUSE = "(" + MESSAGE_BOX + " & " + Types.BASE_TYPE_MASK + ") = " + Types.BASE_SENT_TYPE + " AND NOT (" + MESSAGE_BOX + " & " + Types.SECURE_MESSAGE_BIT + ")";
|
||||
private static final String OUTGOING_SECURE_MESSAGES_CLAUSE = "(" + MESSAGE_BOX + " & " + Types.BASE_TYPE_MASK + ") = " + Types.BASE_SENT_TYPE + " AND (" + MESSAGE_BOX + " & " + (Types.SECURE_MESSAGE_BIT | Types.PUSH_MESSAGE_BIT) + ")";
|
||||
|
||||
private final EarlyReceiptCache earlyDeliveryReceiptCache = new EarlyReceiptCache("MmsDelivery");
|
||||
|
||||
public MmsTable(Context context, SignalDatabase databaseHelper) {
|
||||
|
@ -292,7 +311,7 @@ public class MmsTable extends MessageTable {
|
|||
|
||||
@Override
|
||||
protected String getTypeField() {
|
||||
return MESSAGE_BOX;
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -384,8 +403,8 @@ public class MmsTable extends MessageTable {
|
|||
@Override
|
||||
public @NonNull List<MarkedMessageInfo> getViewedIncomingMessages(long threadId) {
|
||||
SQLiteDatabase db = databaseHelper.getSignalReadableDatabase();
|
||||
String[] columns = new String[]{ID, RECIPIENT_ID, DATE_SENT, MESSAGE_BOX, THREAD_ID, STORY_TYPE};
|
||||
String where = THREAD_ID + " = ? AND " + VIEWED_RECEIPT_COUNT + " > 0 AND " + MESSAGE_BOX + " & " + Types.BASE_INBOX_TYPE + " = " + Types.BASE_INBOX_TYPE;
|
||||
String[] columns = new String[]{ ID, RECIPIENT_ID, DATE_SENT, TYPE, THREAD_ID, STORY_TYPE};
|
||||
String where = THREAD_ID + " = ? AND " + VIEWED_RECEIPT_COUNT + " > 0 AND " + TYPE + " & " + Types.BASE_INBOX_TYPE + " = " + Types.BASE_INBOX_TYPE;
|
||||
String[] args = SqlUtil.buildArgs(threadId);
|
||||
|
||||
|
||||
|
@ -427,21 +446,20 @@ public class MmsTable extends MessageTable {
|
|||
}
|
||||
|
||||
SQLiteDatabase database = databaseHelper.getSignalWritableDatabase();
|
||||
String[] columns = new String[]{ID, RECIPIENT_ID, DATE_SENT, MESSAGE_BOX, THREAD_ID, STORY_TYPE};
|
||||
String[] columns = new String[]{ ID, RECIPIENT_ID, DATE_SENT, TYPE, THREAD_ID, STORY_TYPE};
|
||||
String where = ID + " IN (" + Util.join(messageIds, ",") + ") AND " + VIEWED_RECEIPT_COUNT + " = 0";
|
||||
List<MarkedMessageInfo> results = new LinkedList<>();
|
||||
|
||||
database.beginTransaction();
|
||||
try (Cursor cursor = database.query(TABLE_NAME, columns, where, null, null, null, null)) {
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
long type = CursorUtil.requireLong(cursor, MESSAGE_BOX);
|
||||
long type = CursorUtil.requireLong(cursor, TYPE);
|
||||
if (Types.isSecureType(type) && Types.isInboxType(type)) {
|
||||
long messageId = CursorUtil.requireLong(cursor, ID);
|
||||
long threadId = CursorUtil.requireLong(cursor, THREAD_ID);
|
||||
RecipientId recipientId = RecipientId.from(CursorUtil.requireLong(cursor, RECIPIENT_ID));
|
||||
long dateSent = CursorUtil.requireLong(cursor, DATE_SENT);
|
||||
SyncMessageId syncMessageId = new SyncMessageId(recipientId, dateSent);
|
||||
StoryType storyType = StoryType.fromCode(CursorUtil.requireInt(cursor, STORY_TYPE));
|
||||
|
||||
results.add(new MarkedMessageInfo(threadId, syncMessageId, new MessageId(messageId, true), null));
|
||||
|
||||
|
@ -599,11 +617,6 @@ public class MmsTable extends MessageTable {
|
|||
database.endTransaction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SQLiteStatement createInsertStatement(SQLiteDatabase database) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ensureMigration() {
|
||||
databaseHelper.getSignalWritableDatabase();
|
||||
|
@ -827,7 +840,7 @@ public class MmsTable extends MessageTable {
|
|||
@Override
|
||||
public @NonNull List<RecipientId> getUnreadStoryThreadRecipientIds() {
|
||||
SQLiteDatabase db = getReadableDatabase();
|
||||
String query = "SELECT DISTINCT " + ThreadTable.RECIPIENT_ID + "\n"
|
||||
String query = "SELECT DISTINCT " + ThreadTable.TABLE_NAME + "." + ThreadTable.RECIPIENT_ID + "\n"
|
||||
+ "FROM " + TABLE_NAME + "\n"
|
||||
+ "JOIN " + ThreadTable.TABLE_NAME + "\n"
|
||||
+ "ON " + TABLE_NAME + "." + THREAD_ID + " = " + ThreadTable.TABLE_NAME + "." + ThreadTable.ID + "\n"
|
||||
|
@ -849,27 +862,27 @@ public class MmsTable extends MessageTable {
|
|||
|
||||
@Override
|
||||
public @NonNull List<StoryResult> getOrderedStoryRecipientsAndIds(boolean isOutgoingOnly) {
|
||||
String where = "WHERE is_story > 0 AND remote_deleted = 0" + (isOutgoingOnly ? " AND is_outgoing != 0" : "") + "\n";
|
||||
String where = "WHERE " + STORY_TYPE + " > 0 AND " + REMOTE_DELETED + " = 0" + (isOutgoingOnly ? " AND is_outgoing != 0" : "") + "\n";
|
||||
SQLiteDatabase db = getReadableDatabase();
|
||||
String query = "SELECT\n"
|
||||
+ " mms.date AS sent_timestamp,\n"
|
||||
+ " mms._id AS mms_id,\n"
|
||||
+ " thread_recipient_id,\n"
|
||||
+ " " + TABLE_NAME + "." + DATE_SENT + " AS sent_timestamp,\n"
|
||||
+ " " + TABLE_NAME + "." + ID + " AS mms_id,\n"
|
||||
+ " " + ThreadTable.TABLE_NAME + "." + ThreadTable.RECIPIENT_ID + ",\n"
|
||||
+ " (" + getOutgoingTypeClause() + ") AS is_outgoing,\n"
|
||||
+ " viewed_receipt_count,\n"
|
||||
+ " mms.date,\n"
|
||||
+ " receipt_timestamp,\n"
|
||||
+ " (" + getOutgoingTypeClause() + ") = 0 AND viewed_receipt_count = 0 AS is_unread\n"
|
||||
+ "FROM mms\n"
|
||||
+ "JOIN thread\n"
|
||||
+ "ON mms.thread_id = thread._id\n"
|
||||
+ " " + VIEWED_RECEIPT_COUNT + ",\n"
|
||||
+ " " + TABLE_NAME + "." + DATE_SENT + ",\n"
|
||||
+ " " + RECEIPT_TIMESTAMP + ",\n"
|
||||
+ " (" + getOutgoingTypeClause() + ") = 0 AND " + VIEWED_RECEIPT_COUNT + " = 0 AS is_unread\n"
|
||||
+ "FROM " + TABLE_NAME + "\n"
|
||||
+ "JOIN " + ThreadTable.TABLE_NAME + "\n"
|
||||
+ "ON " + TABLE_NAME + "." + THREAD_ID + " = " + ThreadTable.TABLE_NAME + "." + ThreadTable.ID + "\n"
|
||||
+ where
|
||||
+ "ORDER BY\n"
|
||||
+ "is_unread DESC,\n"
|
||||
+ "CASE\n"
|
||||
+ "WHEN is_outgoing = 0 AND viewed_receipt_count = 0 THEN mms.date\n"
|
||||
+ "WHEN is_outgoing = 0 AND viewed_receipt_count > 0 THEN receipt_timestamp\n"
|
||||
+ "WHEN is_outgoing = 1 THEN mms.date\n"
|
||||
+ "WHEN is_outgoing = 0 AND " + VIEWED_RECEIPT_COUNT + " = 0 THEN " + MmsTable.TABLE_NAME + "." + MmsTable.DATE_SENT + "\n"
|
||||
+ "WHEN is_outgoing = 0 AND viewed_receipt_count > 0 THEN " + MmsTable.RECEIPT_TIMESTAMP + "\n"
|
||||
+ "WHEN is_outgoing = 1 THEN " + MmsTable.TABLE_NAME + "." + MmsTable.DATE_SENT + "\n"
|
||||
+ "END DESC";
|
||||
|
||||
List<StoryResult> results;
|
||||
|
@ -1047,7 +1060,7 @@ public class MmsTable extends MessageTable {
|
|||
|
||||
String[] columns = new String[]{ID};
|
||||
long type = Types.getOutgoingEncryptedMessageType() | Types.GROUP_LEAVE_BIT;
|
||||
String query = ID + " = ? AND " + MESSAGE_BOX + " & " + type + " = " + type + " AND " + MESSAGE_BOX + " & " + Types.GROUP_V2_BIT + " = 0";
|
||||
String query = ID + " = ? AND " + TYPE + " & " + type + " = " + type + " AND " + TYPE + " & " + Types.GROUP_V2_BIT + " = 0";
|
||||
String[] args = SqlUtil.buildArgs(messageId);
|
||||
|
||||
try (Cursor cursor = db.query(TABLE_NAME, columns, query, args, null, null, null, null)) {
|
||||
|
@ -1065,7 +1078,7 @@ public class MmsTable extends MessageTable {
|
|||
|
||||
String[] columns = new String[]{DATE_SENT};
|
||||
long type = Types.getOutgoingEncryptedMessageType() | Types.GROUP_LEAVE_BIT;
|
||||
String query = THREAD_ID + " = ? AND " + MESSAGE_BOX + " & " + type + " = " + type + " AND " + MESSAGE_BOX + " & " + Types.GROUP_V2_BIT + " = 0 AND " + DATE_SENT + " < ?";
|
||||
String query = THREAD_ID + " = ? AND " + TYPE + " & " + type + " = " + type + " AND " + TYPE + " & " + Types.GROUP_V2_BIT + " = 0 AND " + DATE_SENT + " < ?";
|
||||
String[] args = new String[]{String.valueOf(threadId), String.valueOf(quitTimeBarrier)};
|
||||
String orderBy = DATE_SENT + " DESC";
|
||||
String limit = "1";
|
||||
|
@ -1139,7 +1152,7 @@ public class MmsTable extends MessageTable {
|
|||
@Override
|
||||
public void addFailures(long messageId, List<NetworkFailure> failure) {
|
||||
try {
|
||||
addToDocument(messageId, NETWORK_FAILURE, failure, NetworkFailureSet.class);
|
||||
addToDocument(messageId, NETWORK_FAILURES, failure, NetworkFailureSet.class);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
|
@ -1148,7 +1161,7 @@ public class MmsTable extends MessageTable {
|
|||
@Override
|
||||
public void setNetworkFailures(long messageId, Set<NetworkFailure> failures) {
|
||||
try {
|
||||
setDocument(databaseHelper.getSignalWritableDatabase(), messageId, NETWORK_FAILURE, new NetworkFailureSet(failures));
|
||||
setDocument(databaseHelper.getSignalWritableDatabase(), messageId, NETWORK_FAILURES, new NetworkFailureSet(failures));
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
|
@ -1174,13 +1187,13 @@ public class MmsTable extends MessageTable {
|
|||
throw new IllegalArgumentException("Unsupported qualifier: " + messageQualifier);
|
||||
}
|
||||
|
||||
try (Cursor cursor = SQLiteDatabaseExtensionsKt.select(database, ID, THREAD_ID, MESSAGE_BOX, RECIPIENT_ID, receiptType.getColumnName(), RECEIPT_TIMESTAMP)
|
||||
try (Cursor cursor = SQLiteDatabaseExtensionsKt.select(database, ID, THREAD_ID, TYPE, RECIPIENT_ID, receiptType.getColumnName(), RECEIPT_TIMESTAMP)
|
||||
.from(TABLE_NAME)
|
||||
.where(DATE_SENT + " = ?" + qualifierWhere, messageId.getTimetamp())
|
||||
.run())
|
||||
{
|
||||
while (cursor.moveToNext()) {
|
||||
if (Types.isOutgoingMessageType(CursorUtil.requireLong(cursor, MESSAGE_BOX))) {
|
||||
if (Types.isOutgoingMessageType(CursorUtil.requireLong(cursor, TYPE))) {
|
||||
RecipientId theirRecipientId = RecipientId.from(CursorUtil.requireLong(cursor, RECIPIENT_ID));
|
||||
RecipientId ourRecipientId = messageId.getRecipientId();
|
||||
String columnName = receiptType.getColumnName();
|
||||
|
@ -1340,7 +1353,7 @@ public class MmsTable extends MessageTable {
|
|||
db.beginTransaction();
|
||||
try {
|
||||
db.execSQL("UPDATE " + TABLE_NAME +
|
||||
" SET " + MESSAGE_BOX + " = (" + MESSAGE_BOX + " & " + (Types.TOTAL_MASK - maskOff) + " | " + maskOn + " )" +
|
||||
" SET " + TYPE + " = (" + TYPE + " & " + (Types.TOTAL_MASK - maskOff) + " | " + maskOn + " )" +
|
||||
" WHERE " + ID + " = ?", new String[] { id + "" });
|
||||
|
||||
if (threadId.isPresent()) {
|
||||
|
@ -1435,7 +1448,6 @@ public class MmsTable extends MessageTable {
|
|||
values.putNull(BODY);
|
||||
values.putNull(QUOTE_BODY);
|
||||
values.putNull(QUOTE_AUTHOR);
|
||||
values.putNull(QUOTE_ATTACHMENT);
|
||||
values.putNull(QUOTE_TYPE);
|
||||
values.putNull(QUOTE_ID);
|
||||
values.putNull(LINK_PREVIEWS);
|
||||
|
@ -1469,7 +1481,7 @@ public class MmsTable extends MessageTable {
|
|||
public void markDownloadState(long messageId, long state) {
|
||||
SQLiteDatabase database = databaseHelper.getSignalWritableDatabase();
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(STATUS, state);
|
||||
contentValues.put(MMS_STATUS, state);
|
||||
|
||||
database.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {messageId + ""});
|
||||
ApplicationDependencies.getDatabaseObserver().notifyMessageUpdateObservers(new MessageId(messageId, true));
|
||||
|
@ -1608,10 +1620,10 @@ public class MmsTable extends MessageTable {
|
|||
database.beginTransaction();
|
||||
|
||||
try {
|
||||
cursor = database.query(TABLE_NAME, new String[] {ID, RECIPIENT_ID, DATE_SENT, MESSAGE_BOX, EXPIRES_IN, EXPIRE_STARTED, THREAD_ID, STORY_TYPE }, where, arguments, null, null, null);
|
||||
cursor = database.query(TABLE_NAME, new String[] { ID, RECIPIENT_ID, DATE_SENT, TYPE, EXPIRES_IN, EXPIRE_STARTED, THREAD_ID, STORY_TYPE }, where, arguments, null, null, null);
|
||||
|
||||
while(cursor != null && cursor.moveToNext()) {
|
||||
if (Types.isSecureType(CursorUtil.requireLong(cursor, MESSAGE_BOX))) {
|
||||
if (Types.isSecureType(CursorUtil.requireLong(cursor, TYPE))) {
|
||||
long threadId = CursorUtil.requireLong(cursor, THREAD_ID);
|
||||
RecipientId recipientId = RecipientId.from(CursorUtil.requireLong(cursor, RECIPIENT_ID));
|
||||
long dateSent = CursorUtil.requireLong(cursor, DATE_SENT);
|
||||
|
@ -1712,9 +1724,9 @@ public class MmsTable extends MessageTable {
|
|||
|
||||
if (cursor != null && cursor.moveToNext()) {
|
||||
return Optional.of(new MmsNotificationInfo(RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(RECIPIENT_ID))),
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(CONTENT_LOCATION)),
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(TRANSACTION_ID)),
|
||||
cursor.getInt(cursor.getColumnIndexOrThrow(SUBSCRIPTION_ID))));
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(MMS_CONTENT_LOCATION)),
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(MMS_TRANSACTION_ID)),
|
||||
cursor.getInt(cursor.getColumnIndexOrThrow(SMS_SUBSCRIPTION_ID))));
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
@ -1739,17 +1751,17 @@ public class MmsTable extends MessageTable {
|
|||
List<DatabaseAttachment> associatedAttachments = attachmentDatabase.getAttachmentsForMessage(messageId);
|
||||
List<Mention> mentions = mentionDatabase.getMentionsForMessage(messageId);
|
||||
|
||||
long outboxType = cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX));
|
||||
long outboxType = cursor.getLong(cursor.getColumnIndexOrThrow(TYPE));
|
||||
String body = cursor.getString(cursor.getColumnIndexOrThrow(BODY));
|
||||
long timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(NORMALIZED_DATE_SENT));
|
||||
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SUBSCRIPTION_ID));
|
||||
long timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(DATE_SENT));
|
||||
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SMS_SUBSCRIPTION_ID));
|
||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN));
|
||||
boolean viewOnce = cursor.getLong(cursor.getColumnIndexOrThrow(VIEW_ONCE)) == 1;
|
||||
long recipientId = cursor.getLong(cursor.getColumnIndexOrThrow(RECIPIENT_ID));
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
|
||||
int distributionType = SignalDatabase.threads().getDistributionType(threadId);
|
||||
String mismatchDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsTable.MISMATCHED_IDENTITIES));
|
||||
String networkDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsTable.NETWORK_FAILURE));
|
||||
String networkDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsTable.NETWORK_FAILURES));
|
||||
StoryType storyType = StoryType.fromCode(CursorUtil.requireInt(cursor, STORY_TYPE));
|
||||
ParentStoryId parentStoryId = ParentStoryId.deserialize(CursorUtil.requireLong(cursor, PARENT_STORY_ID));
|
||||
|
||||
|
@ -1942,14 +1954,13 @@ public class MmsTable extends MessageTable {
|
|||
contentValues.put(DATE_SERVER, retrieved.getServerTimeMillis());
|
||||
contentValues.put(RECIPIENT_ID, retrieved.getFrom().serialize());
|
||||
|
||||
contentValues.put(MESSAGE_BOX, mailbox);
|
||||
contentValues.put(MESSAGE_TYPE, PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF);
|
||||
contentValues.put(TYPE, mailbox);
|
||||
contentValues.put(MMS_MESSAGE_TYPE, PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF);
|
||||
contentValues.put(THREAD_ID, threadId);
|
||||
contentValues.put(CONTENT_LOCATION, contentLocation);
|
||||
contentValues.put(STATUS, Status.DOWNLOAD_INITIALIZED);
|
||||
contentValues.put(MMS_CONTENT_LOCATION, contentLocation);
|
||||
contentValues.put(MMS_STATUS, Status.DOWNLOAD_INITIALIZED);
|
||||
contentValues.put(DATE_RECEIVED, retrieved.isPushMessage() ? retrieved.getReceivedTimeMillis() : generatePduCompatTimestamp(retrieved.getReceivedTimeMillis()));
|
||||
contentValues.put(PART_COUNT, retrieved.getAttachments().size());
|
||||
contentValues.put(SUBSCRIPTION_ID, retrieved.getSubscriptionId());
|
||||
contentValues.put(SMS_SUBSCRIPTION_ID, retrieved.getSubscriptionId());
|
||||
contentValues.put(EXPIRES_IN, retrieved.getExpiresIn());
|
||||
contentValues.put(VIEW_ONCE, retrieved.isViewOnce() ? 1 : 0);
|
||||
contentValues.put(STORY_TYPE, retrieved.getStoryType().getCode());
|
||||
|
@ -2101,12 +2112,12 @@ public class MmsTable extends MessageTable {
|
|||
|
||||
Log.i(TAG, "Message received type: " + notification.getMessageType());
|
||||
|
||||
contentBuilder.add(CONTENT_LOCATION, notification.getContentLocation());
|
||||
contentBuilder.add(MMS_CONTENT_LOCATION, notification.getContentLocation());
|
||||
contentBuilder.add(DATE_SENT, System.currentTimeMillis());
|
||||
contentBuilder.add(EXPIRY, notification.getExpiry());
|
||||
contentBuilder.add(MESSAGE_SIZE, notification.getMessageSize());
|
||||
contentBuilder.add(TRANSACTION_ID, notification.getTransactionId());
|
||||
contentBuilder.add(MESSAGE_TYPE, notification.getMessageType());
|
||||
contentBuilder.add(MMS_EXPIRY, notification.getExpiry());
|
||||
contentBuilder.add(MMS_MESSAGE_SIZE, notification.getMessageSize());
|
||||
contentBuilder.add(MMS_TRANSACTION_ID, notification.getTransactionId());
|
||||
contentBuilder.add(MMS_MESSAGE_TYPE, notification.getMessageType());
|
||||
|
||||
if (notification.getFrom() != null) {
|
||||
Recipient recipient = Recipient.external(context, Util.toIsoString(notification.getFrom().getTextString()));
|
||||
|
@ -2115,12 +2126,12 @@ public class MmsTable extends MessageTable {
|
|||
contentValues.put(RECIPIENT_ID, RecipientId.UNKNOWN.serialize());
|
||||
}
|
||||
|
||||
contentValues.put(MESSAGE_BOX, Types.BASE_INBOX_TYPE);
|
||||
contentValues.put(TYPE, Types.BASE_INBOX_TYPE);
|
||||
contentValues.put(THREAD_ID, threadId);
|
||||
contentValues.put(STATUS, Status.DOWNLOAD_INITIALIZED);
|
||||
contentValues.put(MMS_STATUS, Status.DOWNLOAD_INITIALIZED);
|
||||
contentValues.put(DATE_RECEIVED, generatePduCompatTimestamp(System.currentTimeMillis()));
|
||||
contentValues.put(READ, Util.isDefaultSmsProvider(context) ? 0 : 1);
|
||||
contentValues.put(SUBSCRIPTION_ID, subscriptionId);
|
||||
contentValues.put(SMS_SUBSCRIPTION_ID, subscriptionId);
|
||||
|
||||
if (!contentValues.containsKey(DATE_SENT))
|
||||
contentValues.put(DATE_SENT, contentValues.getAsLong(DATE_RECEIVED));
|
||||
|
@ -2170,7 +2181,7 @@ public class MmsTable extends MessageTable {
|
|||
|
||||
private void markGiftRedemptionState(long messageId, @NonNull GiftBadge.RedemptionState redemptionState) {
|
||||
String[] projection = SqlUtil.buildArgs(BODY, THREAD_ID);
|
||||
String where = "(" + MESSAGE_BOX + " & " + Types.SPECIAL_TYPES_MASK + " = " + Types.SPECIAL_TYPE_GIFT_BADGE + ") AND " +
|
||||
String where = "(" + TYPE + " & " + Types.SPECIAL_TYPES_MASK + " = " + Types.SPECIAL_TYPE_GIFT_BADGE + ") AND " +
|
||||
ID + " = ?";
|
||||
String[] args = SqlUtil.buildArgs(messageId);
|
||||
boolean updated = false;
|
||||
|
@ -2282,13 +2293,13 @@ public class MmsTable extends MessageTable {
|
|||
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(DATE_SENT, message.getSentTimeMillis());
|
||||
contentValues.put(MESSAGE_TYPE, PduHeaders.MESSAGE_TYPE_SEND_REQ);
|
||||
contentValues.put(MMS_MESSAGE_TYPE, PduHeaders.MESSAGE_TYPE_SEND_REQ);
|
||||
|
||||
contentValues.put(MESSAGE_BOX, type);
|
||||
contentValues.put(TYPE, type);
|
||||
contentValues.put(THREAD_ID, threadId);
|
||||
contentValues.put(READ, 1);
|
||||
contentValues.put(DATE_RECEIVED, System.currentTimeMillis());
|
||||
contentValues.put(SUBSCRIPTION_ID, message.getSubscriptionId());
|
||||
contentValues.put(SMS_SUBSCRIPTION_ID, message.getSubscriptionId());
|
||||
contentValues.put(EXPIRES_IN, message.getExpiresIn());
|
||||
contentValues.put(VIEW_ONCE, message.isViewOnce());
|
||||
contentValues.put(RECIPIENT_ID, message.getRecipient().getId().serialize());
|
||||
|
@ -2415,7 +2426,6 @@ public class MmsTable extends MessageTable {
|
|||
allAttachments.addAll(previewAttachments);
|
||||
|
||||
contentValues.put(BODY, body);
|
||||
contentValues.put(PART_COUNT, allAttachments.size());
|
||||
contentValues.put(MENTIONS_SELF, mentionsSelf ? 1 : 0);
|
||||
|
||||
if (messageRanges != null) {
|
||||
|
@ -2568,9 +2578,9 @@ public class MmsTable extends MessageTable {
|
|||
@Override
|
||||
public boolean isSent(long messageId) {
|
||||
SQLiteDatabase database = databaseHelper.getSignalReadableDatabase();
|
||||
try (Cursor cursor = database.query(TABLE_NAME, new String[] { MESSAGE_BOX }, ID + " = ?", new String[] { String.valueOf(messageId)}, null, null, null)) {
|
||||
try (Cursor cursor = database.query(TABLE_NAME, new String[] { TYPE }, ID + " = ?", new String[] { String.valueOf(messageId)}, null, null, null)) {
|
||||
if (cursor != null && cursor.moveToNext()) {
|
||||
long type = cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX));
|
||||
long type = cursor.getLong(cursor.getColumnIndexOrThrow(TYPE));
|
||||
return Types.isSentType(type);
|
||||
}
|
||||
}
|
||||
|
@ -2585,7 +2595,7 @@ public class MmsTable extends MessageTable {
|
|||
@Override
|
||||
public Set<Long> getAllRateLimitedMessageIds() {
|
||||
SQLiteDatabase db = databaseHelper.getSignalReadableDatabase();
|
||||
String where = "(" + MESSAGE_BOX + " & " + Types.TOTAL_MASK + " & " + Types.MESSAGE_RATE_LIMITED_BIT + ") > 0";
|
||||
String where = "(" + TYPE + " & " + Types.TOTAL_MASK + " & " + Types.MESSAGE_RATE_LIMITED_BIT + ") > 0";
|
||||
|
||||
Set<Long> ids = new HashSet<>();
|
||||
|
||||
|
@ -2851,7 +2861,6 @@ public class MmsTable extends MessageTable {
|
|||
0,
|
||||
threadId, message.getBody(),
|
||||
slideDeck,
|
||||
slideDeck.getSlides().size(),
|
||||
message.isSecure() ? MmsSmsColumns.Types.getOutgoingEncryptedMessageType() : MmsSmsColumns.Types.getOutgoingSmsMessageType(),
|
||||
Collections.emptySet(),
|
||||
Collections.emptySet(),
|
||||
|
@ -2915,7 +2924,7 @@ public class MmsTable extends MessageTable {
|
|||
|
||||
@Override
|
||||
public MessageRecord getCurrent() {
|
||||
long mmsType = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.MESSAGE_TYPE));
|
||||
long mmsType = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.MMS_MESSAGE_TYPE));
|
||||
|
||||
if (mmsType == PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND) {
|
||||
return getNotificationMmsMessageRecord(cursor);
|
||||
|
@ -2945,22 +2954,22 @@ public class MmsTable extends MessageTable {
|
|||
|
||||
private NotificationMmsMessageRecord getNotificationMmsMessageRecord(Cursor cursor) {
|
||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.ID));
|
||||
long dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.NORMALIZED_DATE_SENT));
|
||||
long dateReceived = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.NORMALIZED_DATE_RECEIVED));
|
||||
long dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.DATE_SENT));
|
||||
long dateReceived = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.DATE_RECEIVED));
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.THREAD_ID));
|
||||
long mailbox = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.MESSAGE_BOX));
|
||||
long mailbox = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.TYPE));
|
||||
long recipientId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.RECIPIENT_ID));
|
||||
int addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.ADDRESS_DEVICE_ID));
|
||||
int addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.RECIPIENT_DEVICE_ID));
|
||||
Recipient recipient = Recipient.live(RecipientId.from(recipientId)).get();
|
||||
|
||||
String contentLocation = cursor.getString(cursor.getColumnIndexOrThrow(MmsTable.CONTENT_LOCATION));
|
||||
String transactionId = cursor.getString(cursor.getColumnIndexOrThrow(MmsTable.TRANSACTION_ID));
|
||||
long messageSize = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.MESSAGE_SIZE));
|
||||
long expiry = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.EXPIRY));
|
||||
int status = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.STATUS));
|
||||
String contentLocation = cursor.getString(cursor.getColumnIndexOrThrow(MmsTable.MMS_CONTENT_LOCATION));
|
||||
String transactionId = cursor.getString(cursor.getColumnIndexOrThrow(MmsTable.MMS_TRANSACTION_ID));
|
||||
long messageSize = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.MMS_MESSAGE_SIZE));
|
||||
long expiry = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.MMS_EXPIRY));
|
||||
int status = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.MMS_STATUS));
|
||||
int deliveryReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.DELIVERY_RECEIPT_COUNT));
|
||||
int readReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.READ_RECEIPT_COUNT));
|
||||
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.SUBSCRIPTION_ID));
|
||||
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.SMS_SUBSCRIPTION_ID));
|
||||
int viewedReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsSmsColumns.VIEWED_RECEIPT_COUNT));
|
||||
long receiptTimestamp = CursorUtil.requireLong(cursor, MmsSmsColumns.RECEIPT_TIMESTAMP);
|
||||
StoryType storyType = StoryType.fromCode(CursorUtil.requireInt(cursor, STORY_TYPE));
|
||||
|
@ -3001,20 +3010,19 @@ public class MmsTable extends MessageTable {
|
|||
|
||||
private MediaMmsMessageRecord getMediaMmsMessageRecord(Cursor cursor) {
|
||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.ID));
|
||||
long dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.NORMALIZED_DATE_SENT));
|
||||
long dateReceived = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.NORMALIZED_DATE_RECEIVED));
|
||||
long dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.DATE_SENT));
|
||||
long dateReceived = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.DATE_RECEIVED));
|
||||
long dateServer = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.DATE_SERVER));
|
||||
long box = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.MESSAGE_BOX));
|
||||
long box = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.TYPE));
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.THREAD_ID));
|
||||
long recipientId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.RECIPIENT_ID));
|
||||
int addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.ADDRESS_DEVICE_ID));
|
||||
int addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.RECIPIENT_DEVICE_ID));
|
||||
int deliveryReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.DELIVERY_RECEIPT_COUNT));
|
||||
int readReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.READ_RECEIPT_COUNT));
|
||||
String body = cursor.getString(cursor.getColumnIndexOrThrow(MmsTable.BODY));
|
||||
int partCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.PART_COUNT));
|
||||
String mismatchDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsTable.MISMATCHED_IDENTITIES));
|
||||
String networkDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsTable.NETWORK_FAILURE));
|
||||
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.SUBSCRIPTION_ID));
|
||||
String networkDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsTable.NETWORK_FAILURES));
|
||||
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.SMS_SUBSCRIPTION_ID));
|
||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.EXPIRES_IN));
|
||||
long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.EXPIRE_STARTED));
|
||||
boolean unidentified = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.UNIDENTIFIED)) == 1;
|
||||
|
@ -3067,7 +3075,7 @@ public class MmsTable extends MessageTable {
|
|||
|
||||
return new MediaMmsMessageRecord(id, recipient, recipient,
|
||||
addressDeviceId, dateSent, dateReceived, dateServer, deliveryReceiptCount,
|
||||
threadId, body, slideDeck, partCount, box, mismatches,
|
||||
threadId, body, slideDeck, box, mismatches,
|
||||
networkFailures, subscriptionId, expiresIn, expireStarted,
|
||||
isViewOnce, readReceiptCount, quote, contacts, previews, unidentified, Collections.emptyList(),
|
||||
remoteDelete, mentionsSelf, notifiedTimestamp, viewedReceiptCount, receiptTimestamp, messageRanges,
|
||||
|
|
|
@ -61,9 +61,9 @@ public class SearchTable extends DatabaseTable {
|
|||
private static final String MESSAGES_QUERY =
|
||||
"SELECT " +
|
||||
ThreadTable.TABLE_NAME + "." + ThreadTable.RECIPIENT_ID + " AS " + CONVERSATION_RECIPIENT + ", " +
|
||||
MmsSmsColumns.RECIPIENT_ID + " AS " + MESSAGE_RECIPIENT + ", " +
|
||||
SmsTable.TABLE_NAME + "." + MmsSmsColumns.RECIPIENT_ID + " AS " + MESSAGE_RECIPIENT + ", " +
|
||||
"snippet(" + SMS_FTS_TABLE_NAME + ", -1, '', '', '" + SNIPPET_WRAP + "', 7) AS " + SNIPPET + ", " +
|
||||
SmsTable.TABLE_NAME + "." + SmsTable.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + ", " +
|
||||
SmsTable.TABLE_NAME + "." + MmsSmsColumns.DATE_RECEIVED + ", " +
|
||||
SMS_FTS_TABLE_NAME + "." + THREAD_ID + ", " +
|
||||
SMS_FTS_TABLE_NAME + "." + BODY + ", " +
|
||||
SMS_FTS_TABLE_NAME + "." + ID + " AS " + MESSAGE_ID + ", " +
|
||||
|
@ -78,9 +78,9 @@ public class SearchTable extends DatabaseTable {
|
|||
"UNION ALL " +
|
||||
"SELECT " +
|
||||
ThreadTable.TABLE_NAME + "." + ThreadTable.RECIPIENT_ID + " AS " + CONVERSATION_RECIPIENT + ", " +
|
||||
MmsSmsColumns.RECIPIENT_ID + " AS " + MESSAGE_RECIPIENT + ", " +
|
||||
MmsTable.TABLE_NAME + "." + MmsSmsColumns.RECIPIENT_ID + " AS " + MESSAGE_RECIPIENT + ", " +
|
||||
"snippet(" + MMS_FTS_TABLE_NAME + ", -1, '', '', '" + SNIPPET_WRAP + "', 7) AS " + SNIPPET + ", " +
|
||||
MmsTable.TABLE_NAME + "." + MmsTable.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + ", " +
|
||||
MmsTable.TABLE_NAME + "." + MmsSmsColumns.DATE_RECEIVED + ", " +
|
||||
MMS_FTS_TABLE_NAME + "." + THREAD_ID + ", " +
|
||||
MMS_FTS_TABLE_NAME + "." + BODY + ", " +
|
||||
MMS_FTS_TABLE_NAME + "." + ID + " AS " + MESSAGE_ID + ", " +
|
||||
|
@ -89,17 +89,17 @@ public class SearchTable extends DatabaseTable {
|
|||
"INNER JOIN " + MMS_FTS_TABLE_NAME + " ON " + MMS_FTS_TABLE_NAME + "." + ID + " = " + MmsTable.TABLE_NAME + "." + MmsTable.ID + " " +
|
||||
"INNER JOIN " + ThreadTable.TABLE_NAME + " ON " + MMS_FTS_TABLE_NAME + "." + THREAD_ID + " = " + ThreadTable.TABLE_NAME + "." + ThreadTable.ID + " " +
|
||||
"WHERE " + MMS_FTS_TABLE_NAME + " MATCH ? " +
|
||||
"AND " + MmsTable.TABLE_NAME + "." + MmsTable.MESSAGE_BOX + " & " + MmsSmsColumns.Types.GROUP_V2_BIT + " = 0 " +
|
||||
"AND " + MmsTable.TABLE_NAME + "." + MmsTable.MESSAGE_BOX + " & " + MmsSmsColumns.Types.SPECIAL_TYPE_PAYMENTS_NOTIFICATION + " = 0 " +
|
||||
"ORDER BY " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC " +
|
||||
"AND " + MmsTable.TABLE_NAME + "." + MmsTable.TYPE + " & " + MmsSmsColumns.Types.GROUP_V2_BIT + " = 0 " +
|
||||
"AND " + MmsTable.TABLE_NAME + "." + MmsTable.TYPE + " & " + MmsSmsColumns.Types.SPECIAL_TYPE_PAYMENTS_NOTIFICATION + " = 0 " +
|
||||
"ORDER BY " + MmsSmsColumns.DATE_RECEIVED + " DESC " +
|
||||
"LIMIT 500";
|
||||
|
||||
private static final String MESSAGES_FOR_THREAD_QUERY =
|
||||
"SELECT " +
|
||||
ThreadTable.TABLE_NAME + "." + ThreadTable.RECIPIENT_ID + " AS " + CONVERSATION_RECIPIENT + ", " +
|
||||
MmsSmsColumns.RECIPIENT_ID + " AS " + MESSAGE_RECIPIENT + ", " +
|
||||
SmsTable.TABLE_NAME + "." + MmsSmsColumns.RECIPIENT_ID + " AS " + MESSAGE_RECIPIENT + ", " +
|
||||
"snippet(" + SMS_FTS_TABLE_NAME + ", -1, '', '', '" + SNIPPET_WRAP + "', 7) AS " + SNIPPET + ", " +
|
||||
SmsTable.TABLE_NAME + "." + SmsTable.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + ", " +
|
||||
SmsTable.TABLE_NAME + "." + MmsSmsColumns.DATE_RECEIVED + ", " +
|
||||
SMS_FTS_TABLE_NAME + "." + THREAD_ID + ", " +
|
||||
SMS_FTS_TABLE_NAME + "." + BODY + ", " +
|
||||
SMS_FTS_TABLE_NAME + "." + ID + " AS " + MESSAGE_ID + ", " +
|
||||
|
@ -111,9 +111,9 @@ public class SearchTable extends DatabaseTable {
|
|||
"UNION ALL " +
|
||||
"SELECT " +
|
||||
ThreadTable.TABLE_NAME + "." + ThreadTable.RECIPIENT_ID + " AS " + CONVERSATION_RECIPIENT + ", " +
|
||||
MmsSmsColumns.RECIPIENT_ID + " AS " + MESSAGE_RECIPIENT + ", " +
|
||||
MmsTable.TABLE_NAME + "." + MmsSmsColumns.RECIPIENT_ID + " AS " + MESSAGE_RECIPIENT + ", " +
|
||||
"snippet(" + MMS_FTS_TABLE_NAME + ", -1, '', '', '" + SNIPPET_WRAP + "', 7) AS " + SNIPPET + ", " +
|
||||
MmsTable.TABLE_NAME + "." + MmsTable.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + ", " +
|
||||
MmsTable.TABLE_NAME + "." + MmsSmsColumns.DATE_RECEIVED + ", " +
|
||||
MMS_FTS_TABLE_NAME + "." + THREAD_ID + ", " +
|
||||
MMS_FTS_TABLE_NAME + "." + BODY + ", " +
|
||||
MMS_FTS_TABLE_NAME + "." + ID + " AS " + MESSAGE_ID + ", " +
|
||||
|
@ -122,7 +122,7 @@ public class SearchTable extends DatabaseTable {
|
|||
"INNER JOIN " + MMS_FTS_TABLE_NAME + " ON " + MMS_FTS_TABLE_NAME + "." + ID + " = " + MmsTable.TABLE_NAME + "." + MmsTable.ID + " " +
|
||||
"INNER JOIN " + ThreadTable.TABLE_NAME + " ON " + MMS_FTS_TABLE_NAME + "." + THREAD_ID + " = " + ThreadTable.TABLE_NAME + "." + ThreadTable.ID + " " +
|
||||
"WHERE " + MMS_FTS_TABLE_NAME + " MATCH ? AND " + MmsTable.TABLE_NAME + "." + MmsSmsColumns.THREAD_ID + " = ? " +
|
||||
"ORDER BY " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC " +
|
||||
"ORDER BY " + MmsSmsColumns.DATE_RECEIVED + " DESC " +
|
||||
"LIMIT 500";
|
||||
|
||||
public SearchTable(@NonNull Context context, @NonNull SignalDatabase databaseHelper) {
|
||||
|
|
|
@ -156,15 +156,25 @@ open class SignalDatabase(private val context: Application, databaseSecret: Data
|
|||
}
|
||||
|
||||
override fun onUpgrade(db: net.zetetic.database.sqlcipher.SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
// The caller of onUpgrade starts a transaction, which prevents us from turning off foreign keys.
|
||||
// At this point it hasn't done anything, so we can just end it and then start it again ourselves.
|
||||
db.endTransaction()
|
||||
|
||||
Log.i(TAG, "Upgrading database: $oldVersion, $newVersion")
|
||||
val startTime = System.currentTimeMillis()
|
||||
db.setForeignKeyConstraintsEnabled(false)
|
||||
db.beginTransaction()
|
||||
try {
|
||||
migrate(context, db, oldVersion, newVersion)
|
||||
db.setTransactionSuccessful()
|
||||
} finally {
|
||||
db.endTransaction()
|
||||
db.setForeignKeyConstraintsEnabled(true)
|
||||
|
||||
// We have to re-begin the transaction for the calling code (see comment at start of method)
|
||||
db.beginTransaction()
|
||||
}
|
||||
|
||||
migratePostTransaction(context, oldVersion)
|
||||
Log.i(TAG, "Upgrade complete. Took " + (System.currentTimeMillis() - startTime) + " ms.")
|
||||
}
|
||||
|
|
|
@ -1,288 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.thoughtcrime.securesms.database;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteException;
|
||||
import android.net.Uri;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
import net.zetetic.database.sqlcipher.SQLiteStatement;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.groups.GroupId;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
public class SmsMigrator {
|
||||
|
||||
private static final String TAG = Log.tag(SmsMigrator.class);
|
||||
|
||||
private static class SystemColumns {
|
||||
private static final String ADDRESS = "address";
|
||||
private static final String PERSON = "person";
|
||||
private static final String DATE_RECEIVED = "date";
|
||||
private static final String PROTOCOL = "protocol";
|
||||
private static final String READ = "read";
|
||||
private static final String STATUS = "status";
|
||||
private static final String TYPE = "type";
|
||||
private static final String SUBJECT = "subject";
|
||||
private static final String REPLY_PATH_PRESENT = "reply_path_present";
|
||||
private static final String BODY = "body";
|
||||
private static final String SERVICE_CENTER = "service_center";
|
||||
}
|
||||
|
||||
private static void addStringToStatement(SQLiteStatement statement, Cursor cursor,
|
||||
int index, String key)
|
||||
{
|
||||
int columnIndex = cursor.getColumnIndexOrThrow(key);
|
||||
|
||||
if (cursor.isNull(columnIndex)) {
|
||||
statement.bindNull(index);
|
||||
} else {
|
||||
statement.bindString(index, cursor.getString(columnIndex));
|
||||
}
|
||||
}
|
||||
|
||||
private static void addIntToStatement(SQLiteStatement statement, Cursor cursor,
|
||||
int index, String key)
|
||||
{
|
||||
int columnIndex = cursor.getColumnIndexOrThrow(key);
|
||||
|
||||
if (cursor.isNull(columnIndex)) {
|
||||
statement.bindNull(index);
|
||||
} else {
|
||||
statement.bindLong(index, cursor.getLong(columnIndex));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
private static void addTranslatedTypeToStatement(SQLiteStatement statement, Cursor cursor, int index, String key)
|
||||
{
|
||||
int columnIndex = cursor.getColumnIndexOrThrow(key);
|
||||
|
||||
if (cursor.isNull(columnIndex)) {
|
||||
statement.bindLong(index, SmsTable.Types.BASE_INBOX_TYPE);
|
||||
} else {
|
||||
long theirType = cursor.getLong(columnIndex);
|
||||
statement.bindLong(index, SmsTable.Types.translateFromSystemBaseType(theirType));
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isAppropriateTypeForMigration(Cursor cursor, int columnIndex) {
|
||||
long systemType = cursor.getLong(columnIndex);
|
||||
long ourType = SmsTable.Types.translateFromSystemBaseType(systemType);
|
||||
|
||||
return ourType == MmsSmsColumns.Types.BASE_INBOX_TYPE ||
|
||||
ourType == MmsSmsColumns.Types.BASE_SENT_TYPE ||
|
||||
ourType == MmsSmsColumns.Types.BASE_SENT_FAILED_TYPE;
|
||||
}
|
||||
|
||||
private static void getContentValuesForRow(Context context, Cursor cursor, long threadId, SQLiteStatement statement) {
|
||||
String address = cursor.getString(cursor.getColumnIndexOrThrow(SystemColumns.ADDRESS));
|
||||
RecipientId id = Recipient.external(context, address).getId();
|
||||
|
||||
statement.bindString(1, id.serialize());
|
||||
addIntToStatement(statement, cursor, 2, SystemColumns.PERSON);
|
||||
addIntToStatement(statement, cursor, 3, SystemColumns.DATE_RECEIVED);
|
||||
addIntToStatement(statement, cursor, 4, SystemColumns.DATE_RECEIVED);
|
||||
addIntToStatement(statement, cursor, 5, SystemColumns.PROTOCOL);
|
||||
addIntToStatement(statement, cursor, 6, SystemColumns.READ);
|
||||
addIntToStatement(statement, cursor, 7, SystemColumns.STATUS);
|
||||
addTranslatedTypeToStatement(statement, cursor, 8, SystemColumns.TYPE);
|
||||
addIntToStatement(statement, cursor, 9, SystemColumns.REPLY_PATH_PRESENT);
|
||||
addStringToStatement(statement, cursor, 10, SystemColumns.SUBJECT);
|
||||
addStringToStatement(statement, cursor, 11, SystemColumns.BODY);
|
||||
addStringToStatement(statement, cursor, 12, SystemColumns.SERVICE_CENTER);
|
||||
|
||||
statement.bindLong(13, threadId);
|
||||
}
|
||||
|
||||
private static String getTheirCanonicalAddress(Context context, String theirRecipientId) {
|
||||
Uri uri = Uri.parse("content://mms-sms/canonical-address/" + theirRecipientId);
|
||||
Cursor cursor = null;
|
||||
|
||||
try {
|
||||
cursor = context.getContentResolver().query(uri, null, null, null, null);
|
||||
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
return cursor.getString(0);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} catch (IllegalStateException iae) {
|
||||
Log.w(TAG, iae);
|
||||
return null;
|
||||
} finally {
|
||||
if (cursor != null)
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static @Nullable Set<Recipient> getOurRecipients(Context context, String theirRecipients) {
|
||||
StringTokenizer tokenizer = new StringTokenizer(theirRecipients.trim(), " ");
|
||||
Set<Recipient> recipientList = new HashSet<>();
|
||||
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
String theirRecipientId = tokenizer.nextToken();
|
||||
String address = getTheirCanonicalAddress(context, theirRecipientId);
|
||||
|
||||
if (address != null) {
|
||||
recipientList.add(Recipient.external(context, address));
|
||||
}
|
||||
}
|
||||
|
||||
if (recipientList.isEmpty()) return null;
|
||||
else return recipientList;
|
||||
}
|
||||
|
||||
private static void migrateConversation(Context context, SmsMigrationProgressListener listener,
|
||||
ProgressDescription progress,
|
||||
long theirThreadId, long ourThreadId)
|
||||
{
|
||||
MessageTable ourSmsDatabase = SignalDatabase.sms();
|
||||
Cursor cursor = null;
|
||||
SQLiteStatement statement = null;
|
||||
|
||||
try {
|
||||
Uri uri = Uri.parse("content://sms/conversations/" + theirThreadId);
|
||||
|
||||
try {
|
||||
cursor = context.getContentResolver().query(uri, null, null, null, null);
|
||||
} catch (SQLiteException e) {
|
||||
/// Work around for weird sony-specific (?) bug: #4309
|
||||
Log.w(TAG, e);
|
||||
return;
|
||||
}
|
||||
|
||||
SQLiteDatabase transaction = ourSmsDatabase.beginTransaction();
|
||||
statement = ourSmsDatabase.createInsertStatement(transaction);
|
||||
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
int addressColumn = cursor.getColumnIndexOrThrow(SystemColumns.ADDRESS);
|
||||
int typeColumn = cursor.getColumnIndex(SmsTable.TYPE);
|
||||
|
||||
if (!cursor.isNull(addressColumn) && (cursor.isNull(typeColumn) || isAppropriateTypeForMigration(cursor, typeColumn))) {
|
||||
getContentValuesForRow(context, cursor, ourThreadId, statement);
|
||||
statement.execute();
|
||||
}
|
||||
|
||||
listener.progressUpdate(new ProgressDescription(progress, cursor.getCount(), cursor.getPosition()));
|
||||
}
|
||||
|
||||
ourSmsDatabase.endTransaction(transaction);
|
||||
SignalDatabase.threads().update(ourThreadId, true);
|
||||
SignalDatabase.threads().setLastScrolled(ourThreadId, 0);
|
||||
SignalDatabase.threads().notifyConversationListeners(ourThreadId);
|
||||
|
||||
} finally {
|
||||
if (statement != null)
|
||||
statement.close();
|
||||
if (cursor != null)
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static void migrateDatabase(Context context, SmsMigrationProgressListener listener)
|
||||
{
|
||||
// if (context.getSharedPreferences("SecureSMS", Context.MODE_PRIVATE).getBoolean("migrated", false))
|
||||
// return;
|
||||
|
||||
ThreadTable threadTable = SignalDatabase.threads();
|
||||
Cursor cursor = null;
|
||||
|
||||
try {
|
||||
Uri threadListUri = Uri.parse("content://mms-sms/conversations?simple=true");
|
||||
cursor = context.getContentResolver().query(threadListUri, null, null, null, "date ASC");
|
||||
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
long theirThreadId = cursor.getLong(cursor.getColumnIndexOrThrow("_id"));
|
||||
String theirRecipients = cursor.getString(cursor.getColumnIndexOrThrow("recipient_ids"));
|
||||
Set<Recipient> ourRecipients = getOurRecipients(context, theirRecipients);
|
||||
ProgressDescription progress = new ProgressDescription(cursor.getCount(), cursor.getPosition(), 100, 0);
|
||||
|
||||
if (ourRecipients != null) {
|
||||
if (ourRecipients.size() == 1) {
|
||||
long ourThreadId = threadTable.getOrCreateThreadIdFor(ourRecipients.iterator().next());
|
||||
migrateConversation(context, listener, progress, theirThreadId, ourThreadId);
|
||||
} else if (ourRecipients.size() > 1) {
|
||||
ourRecipients.add(Recipient.self());
|
||||
|
||||
List<RecipientId> recipientIds = Stream.of(ourRecipients).map(Recipient::getId).toList();
|
||||
|
||||
GroupId.Mms ourGroupId = SignalDatabase.groups().getOrCreateMmsGroupForMembers(recipientIds);
|
||||
RecipientId ourGroupRecipientId = SignalDatabase.recipients().getOrInsertFromGroupId(ourGroupId);
|
||||
Recipient ourGroupRecipient = Recipient.resolved(ourGroupRecipientId);
|
||||
long ourThreadId = threadTable.getOrCreateThreadIdFor(ourGroupRecipient, ThreadTable.DistributionTypes.CONVERSATION);
|
||||
|
||||
migrateConversation(context, listener, progress, theirThreadId, ourThreadId);
|
||||
}
|
||||
}
|
||||
|
||||
progress.incrementPrimaryComplete();
|
||||
listener.progressUpdate(progress);
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null)
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
context.getSharedPreferences("SecureSMS", Context.MODE_PRIVATE).edit()
|
||||
.putBoolean("migrated", true).apply();
|
||||
}
|
||||
|
||||
public interface SmsMigrationProgressListener {
|
||||
void progressUpdate(ProgressDescription description);
|
||||
}
|
||||
|
||||
public static class ProgressDescription {
|
||||
public final int primaryTotal;
|
||||
public int primaryComplete;
|
||||
public final int secondaryTotal;
|
||||
public final int secondaryComplete;
|
||||
|
||||
ProgressDescription(int primaryTotal, int primaryComplete,
|
||||
int secondaryTotal, int secondaryComplete)
|
||||
{
|
||||
this.primaryTotal = primaryTotal;
|
||||
this.primaryComplete = primaryComplete;
|
||||
this.secondaryTotal = secondaryTotal;
|
||||
this.secondaryComplete = secondaryComplete;
|
||||
}
|
||||
|
||||
ProgressDescription(ProgressDescription that, int secondaryTotal, int secondaryComplete) {
|
||||
this.primaryComplete = that.primaryComplete;
|
||||
this.primaryTotal = that.primaryTotal;
|
||||
this.secondaryComplete = secondaryComplete;
|
||||
this.secondaryTotal = secondaryTotal;
|
||||
}
|
||||
|
||||
void incrementPrimaryComplete() {
|
||||
primaryComplete += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -31,8 +31,6 @@ import com.google.android.mms.pdu_alt.NotificationInd;
|
|||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
|
||||
import net.zetetic.database.sqlcipher.SQLiteStatement;
|
||||
|
||||
import org.signal.core.util.CursorExtensionsKt;
|
||||
import org.signal.core.util.CursorUtil;
|
||||
import org.signal.core.util.SQLiteDatabaseExtensionsKt;
|
||||
|
@ -100,36 +98,23 @@ public class SmsTable extends MessageTable {
|
|||
|
||||
private static final String TAG = Log.tag(SmsTable.class);
|
||||
|
||||
public static final String TABLE_NAME = "sms";
|
||||
public static final String PERSON = "person";
|
||||
static final String DATE_RECEIVED = "date";
|
||||
static final String DATE_SENT = "date_sent";
|
||||
public static final String PROTOCOL = "protocol";
|
||||
public static final String STATUS = "status";
|
||||
public static final String TYPE = "type";
|
||||
public static final String REPLY_PATH_PRESENT = "reply_path_present";
|
||||
public static final String SUBJECT = "subject";
|
||||
public static final String SERVICE_CENTER = "service_center";
|
||||
public static final String TABLE_NAME = "sms";
|
||||
public static final String SMS_STATUS = "status";
|
||||
|
||||
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
|
||||
THREAD_ID + " INTEGER, " +
|
||||
RECIPIENT_ID + " INTEGER, " +
|
||||
ADDRESS_DEVICE_ID + " INTEGER DEFAULT 1, " +
|
||||
PERSON + " INTEGER, " +
|
||||
DATE_RECEIVED + " INTEGER, " +
|
||||
DATE_SENT + " INTEGER, " +
|
||||
DATE_SENT + " INTEGER NOT NULL, " +
|
||||
DATE_RECEIVED + " INTEGER NOT NULL, " +
|
||||
DATE_SERVER + " INTEGER DEFAULT -1, " +
|
||||
PROTOCOL + " INTEGER, " +
|
||||
READ + " INTEGER DEFAULT 0, " +
|
||||
STATUS + " INTEGER DEFAULT -1," +
|
||||
THREAD_ID + " INTEGER NOT NULL REFERENCES " + ThreadTable.TABLE_NAME + " (" + ThreadTable.ID + ") ON DELETE CASCADE, " +
|
||||
RECIPIENT_ID + " INTEGER NOT NULL REFERENCES " + RecipientTable.TABLE_NAME + " (" + RecipientTable.ID + ") ON DELETE CASCADE, " +
|
||||
RECIPIENT_DEVICE_ID + " INTEGER DEFAULT 1, " +
|
||||
TYPE + " INTEGER, " +
|
||||
REPLY_PATH_PRESENT + " INTEGER, " +
|
||||
DELIVERY_RECEIPT_COUNT + " INTEGER DEFAULT 0," +
|
||||
SUBJECT + " TEXT, " +
|
||||
BODY + " TEXT, " +
|
||||
READ + " INTEGER DEFAULT 0, " +
|
||||
SMS_STATUS + " INTEGER DEFAULT -1," +
|
||||
DELIVERY_RECEIPT_COUNT + " INTEGER DEFAULT 0," +
|
||||
MISMATCHED_IDENTITIES + " TEXT DEFAULT NULL, " +
|
||||
SERVICE_CENTER + " TEXT, " +
|
||||
SUBSCRIPTION_ID + " INTEGER DEFAULT -1, " +
|
||||
SMS_SUBSCRIPTION_ID + " INTEGER DEFAULT -1, " +
|
||||
EXPIRES_IN + " INTEGER DEFAULT 0, " +
|
||||
EXPIRE_STARTED + " INTEGER DEFAULT 0, " +
|
||||
NOTIFIED + " DEFAULT 0, " +
|
||||
|
@ -155,15 +140,30 @@ public class SmsTable extends MessageTable {
|
|||
};
|
||||
|
||||
private static final String[] MESSAGE_PROJECTION = new String[] {
|
||||
ID, THREAD_ID, RECIPIENT_ID, ADDRESS_DEVICE_ID, PERSON,
|
||||
DATE_RECEIVED + " AS " + NORMALIZED_DATE_RECEIVED,
|
||||
DATE_SENT + " AS " + NORMALIZED_DATE_SENT,
|
||||
ID,
|
||||
THREAD_ID,
|
||||
RECIPIENT_ID,
|
||||
RECIPIENT_DEVICE_ID,
|
||||
DATE_RECEIVED,
|
||||
DATE_SENT,
|
||||
DATE_SERVER,
|
||||
PROTOCOL, READ, STATUS, TYPE,
|
||||
REPLY_PATH_PRESENT, SUBJECT, BODY, SERVICE_CENTER, DELIVERY_RECEIPT_COUNT,
|
||||
MISMATCHED_IDENTITIES, SUBSCRIPTION_ID, EXPIRES_IN, EXPIRE_STARTED,
|
||||
NOTIFIED, READ_RECEIPT_COUNT, UNIDENTIFIED, REACTIONS_UNREAD, REACTIONS_LAST_SEEN,
|
||||
REMOTE_DELETED, NOTIFIED_TIMESTAMP, RECEIPT_TIMESTAMP
|
||||
READ,
|
||||
SMS_STATUS,
|
||||
TYPE,
|
||||
BODY,
|
||||
DELIVERY_RECEIPT_COUNT,
|
||||
MISMATCHED_IDENTITIES,
|
||||
SMS_SUBSCRIPTION_ID,
|
||||
EXPIRES_IN,
|
||||
EXPIRE_STARTED,
|
||||
NOTIFIED,
|
||||
READ_RECEIPT_COUNT,
|
||||
UNIDENTIFIED,
|
||||
REACTIONS_UNREAD,
|
||||
REACTIONS_LAST_SEEN,
|
||||
REMOTE_DELETED,
|
||||
NOTIFIED_TIMESTAMP,
|
||||
RECEIPT_TIMESTAMP
|
||||
};
|
||||
|
||||
@VisibleForTesting
|
||||
|
@ -489,7 +489,7 @@ public class SmsTable extends MessageTable {
|
|||
public void markSmsStatus(long id, int status) {
|
||||
Log.i(TAG, "Updating ID: " + id + " to status: " + status);
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(STATUS, status);
|
||||
contentValues.put(SMS_STATUS, status);
|
||||
|
||||
SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
|
||||
db.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {id+""});
|
||||
|
@ -731,7 +731,7 @@ public class SmsTable extends MessageTable {
|
|||
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(RECIPIENT_ID, sender.serialize());
|
||||
values.put(ADDRESS_DEVICE_ID, 1);
|
||||
values.put(RECIPIENT_DEVICE_ID, 1);
|
||||
values.put(DATE_RECEIVED, timestamp);
|
||||
values.put(DATE_SENT, timestamp);
|
||||
values.put(READ, markRead ? 1 : 0);
|
||||
|
@ -808,7 +808,7 @@ public class SmsTable extends MessageTable {
|
|||
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(RECIPIENT_ID, sender.serialize());
|
||||
values.put(ADDRESS_DEVICE_ID, 1);
|
||||
values.put(RECIPIENT_DEVICE_ID, 1);
|
||||
values.put(DATE_RECEIVED, timestamp);
|
||||
values.put(DATE_SENT, timestamp);
|
||||
values.put(READ, 0);
|
||||
|
@ -880,7 +880,7 @@ public class SmsTable extends MessageTable {
|
|||
|
||||
ContentValues values = new ContentValues(6);
|
||||
values.put(RECIPIENT_ID, recipientId.serialize());
|
||||
values.put(ADDRESS_DEVICE_ID, 1);
|
||||
values.put(RECIPIENT_DEVICE_ID, 1);
|
||||
values.put(DATE_RECEIVED, System.currentTimeMillis());
|
||||
values.put(DATE_SENT, timestamp);
|
||||
values.put(READ, unread ? 0 : 1);
|
||||
|
@ -1008,7 +1008,7 @@ public class SmsTable extends MessageTable {
|
|||
.forEach(threadId -> {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(RECIPIENT_ID, recipient.getId().serialize());
|
||||
values.put(ADDRESS_DEVICE_ID, 1);
|
||||
values.put(RECIPIENT_DEVICE_ID, 1);
|
||||
values.put(DATE_RECEIVED, System.currentTimeMillis());
|
||||
values.put(DATE_SENT, System.currentTimeMillis());
|
||||
values.put(READ, 1);
|
||||
|
@ -1056,7 +1056,7 @@ public class SmsTable extends MessageTable {
|
|||
{
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(RECIPIENT_ID, recipientId.serialize());
|
||||
values.put(ADDRESS_DEVICE_ID, 1);
|
||||
values.put(RECIPIENT_DEVICE_ID, 1);
|
||||
values.put(DATE_RECEIVED, System.currentTimeMillis());
|
||||
values.put(DATE_SENT, System.currentTimeMillis());
|
||||
values.put(READ, 1);
|
||||
|
@ -1092,7 +1092,7 @@ public class SmsTable extends MessageTable {
|
|||
.forEach(threadId -> {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(RECIPIENT_ID, recipientId.serialize());
|
||||
values.put(ADDRESS_DEVICE_ID, 1);
|
||||
values.put(RECIPIENT_DEVICE_ID, 1);
|
||||
values.put(DATE_RECEIVED, System.currentTimeMillis());
|
||||
values.put(DATE_SENT, System.currentTimeMillis());
|
||||
values.put(READ, 1);
|
||||
|
@ -1121,7 +1121,7 @@ public class SmsTable extends MessageTable {
|
|||
public void insertBoostRequestMessage(@NonNull RecipientId recipientId, long threadId) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(RECIPIENT_ID, recipientId.serialize());
|
||||
values.put(ADDRESS_DEVICE_ID, 1);
|
||||
values.put(RECIPIENT_DEVICE_ID, 1);
|
||||
values.put(DATE_RECEIVED, System.currentTimeMillis());
|
||||
values.put(DATE_SENT, System.currentTimeMillis());
|
||||
values.put(READ, 1);
|
||||
|
@ -1136,7 +1136,7 @@ public class SmsTable extends MessageTable {
|
|||
public void insertThreadMergeEvent(@NonNull RecipientId recipientId, long threadId, @NonNull ThreadMergeEvent event) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(RECIPIENT_ID, recipientId.serialize());
|
||||
values.put(ADDRESS_DEVICE_ID, 1);
|
||||
values.put(RECIPIENT_DEVICE_ID, 1);
|
||||
values.put(DATE_RECEIVED, System.currentTimeMillis());
|
||||
values.put(DATE_SENT, System.currentTimeMillis());
|
||||
values.put(READ, 1);
|
||||
|
@ -1153,7 +1153,7 @@ public class SmsTable extends MessageTable {
|
|||
public void insertSmsExportMessage(@NonNull RecipientId recipientId, long threadId) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(RECIPIENT_ID, recipientId.serialize());
|
||||
values.put(ADDRESS_DEVICE_ID, 1);
|
||||
values.put(RECIPIENT_DEVICE_ID, 1);
|
||||
values.put(DATE_RECEIVED, System.currentTimeMillis());
|
||||
values.put(DATE_SENT, System.currentTimeMillis());
|
||||
values.put(READ, 1);
|
||||
|
@ -1251,21 +1251,14 @@ public class SmsTable extends MessageTable {
|
|||
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(RECIPIENT_ID, message.getSender().serialize());
|
||||
values.put(ADDRESS_DEVICE_ID, message.getSenderDeviceId());
|
||||
values.put(RECIPIENT_DEVICE_ID, message.getSenderDeviceId());
|
||||
values.put(DATE_RECEIVED, message.getReceivedTimestampMillis());
|
||||
values.put(DATE_SENT, message.getSentTimestampMillis());
|
||||
values.put(DATE_SERVER, message.getServerTimestampMillis());
|
||||
values.put(PROTOCOL, message.getProtocol());
|
||||
values.put(READ, unread ? 0 : 1);
|
||||
values.put(SUBSCRIPTION_ID, message.getSubscriptionId());
|
||||
values.put(SMS_SUBSCRIPTION_ID, message.getSubscriptionId());
|
||||
values.put(EXPIRES_IN, message.getExpiresIn());
|
||||
values.put(UNIDENTIFIED, message.isUnidentified());
|
||||
|
||||
if (!TextUtils.isEmpty(message.getPseudoSubject()))
|
||||
values.put(SUBJECT, message.getPseudoSubject());
|
||||
|
||||
values.put(REPLY_PATH_PRESENT, message.isReplyPathPresent());
|
||||
values.put(SERVICE_CENTER, message.getServiceCenterAddress());
|
||||
values.put(BODY, message.getMessageBody());
|
||||
values.put(TYPE, type);
|
||||
values.put(THREAD_ID, threadId);
|
||||
|
@ -1316,7 +1309,7 @@ public class SmsTable extends MessageTable {
|
|||
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(RECIPIENT_ID, recipientId.serialize());
|
||||
values.put(ADDRESS_DEVICE_ID, senderDeviceId);
|
||||
values.put(RECIPIENT_DEVICE_ID, senderDeviceId);
|
||||
values.put(DATE_RECEIVED, System.currentTimeMillis());
|
||||
values.put(DATE_SENT, sentTimestamp);
|
||||
values.put(DATE_SERVER, -1);
|
||||
|
@ -1341,7 +1334,7 @@ public class SmsTable extends MessageTable {
|
|||
public void insertBadDecryptMessage(@NonNull RecipientId recipientId, int senderDevice, long sentTimestamp, long receivedTimestamp, long threadId) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(RECIPIENT_ID, recipientId.serialize());
|
||||
values.put(ADDRESS_DEVICE_ID, senderDevice);
|
||||
values.put(RECIPIENT_DEVICE_ID, senderDevice);
|
||||
values.put(DATE_SENT, sentTimestamp);
|
||||
values.put(DATE_RECEIVED, receivedTimestamp);
|
||||
values.put(DATE_SERVER, -1);
|
||||
|
@ -1387,7 +1380,7 @@ public class SmsTable extends MessageTable {
|
|||
contentValues.put(DATE_SENT, date);
|
||||
contentValues.put(READ, 1);
|
||||
contentValues.put(TYPE, type);
|
||||
contentValues.put(SUBSCRIPTION_ID, message.getSubscriptionId());
|
||||
contentValues.put(SMS_SUBSCRIPTION_ID, message.getSubscriptionId());
|
||||
contentValues.put(EXPIRES_IN, message.getExpiresIn());
|
||||
contentValues.put(DELIVERY_RECEIPT_COUNT, Stream.of(earlyDeliveryReceipts.values()).mapToLong(EarlyReceiptCache.Receipt::getCount).sum());
|
||||
contentValues.put(RECEIPT_TIMESTAMP, Stream.of(earlyDeliveryReceipts.values()).mapToLong(EarlyReceiptCache.Receipt::getTimestamp).max().orElse(-1));
|
||||
|
@ -1732,24 +1725,6 @@ public class SmsTable extends MessageTable {
|
|||
databaseHelper.getSignalWritableDatabase().endTransaction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SQLiteStatement createInsertStatement(SQLiteDatabase database) {
|
||||
return database.compileStatement("INSERT INTO " + TABLE_NAME + " (" + RECIPIENT_ID + ", " +
|
||||
PERSON + ", " +
|
||||
DATE_SENT + ", " +
|
||||
DATE_RECEIVED + ", " +
|
||||
PROTOCOL + ", " +
|
||||
READ + ", " +
|
||||
STATUS + ", " +
|
||||
TYPE + ", " +
|
||||
REPLY_PATH_PRESENT + ", " +
|
||||
SUBJECT + ", " +
|
||||
BODY + ", " +
|
||||
SERVICE_CENTER +
|
||||
", " + THREAD_ID + ") " +
|
||||
" VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ViewOnceExpirationInfo getNearestExpiringViewOnceMessage() {
|
||||
throw new UnsupportedOperationException();
|
||||
|
@ -1948,17 +1923,17 @@ public class SmsTable extends MessageTable {
|
|||
public SmsMessageRecord getCurrent() {
|
||||
long messageId = cursor.getLong(cursor.getColumnIndexOrThrow(SmsTable.ID));
|
||||
long recipientId = cursor.getLong(cursor.getColumnIndexOrThrow(SmsTable.RECIPIENT_ID));
|
||||
int addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(SmsTable.ADDRESS_DEVICE_ID));
|
||||
int addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(SmsTable.RECIPIENT_DEVICE_ID));
|
||||
long type = cursor.getLong(cursor.getColumnIndexOrThrow(SmsTable.TYPE));
|
||||
long dateReceived = cursor.getLong(cursor.getColumnIndexOrThrow(SmsTable.NORMALIZED_DATE_RECEIVED));
|
||||
long dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(SmsTable.NORMALIZED_DATE_SENT));
|
||||
long dateReceived = cursor.getLong(cursor.getColumnIndexOrThrow(SmsTable.DATE_RECEIVED));
|
||||
long dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(SmsTable.DATE_SENT));
|
||||
long dateServer = cursor.getLong(cursor.getColumnIndexOrThrow(SmsTable.DATE_SERVER));
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(SmsTable.THREAD_ID));
|
||||
int status = cursor.getInt(cursor.getColumnIndexOrThrow(SmsTable.STATUS));
|
||||
int status = cursor.getInt(cursor.getColumnIndexOrThrow(SmsTable.SMS_STATUS));
|
||||
int deliveryReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(SmsTable.DELIVERY_RECEIPT_COUNT));
|
||||
int readReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(SmsTable.READ_RECEIPT_COUNT));
|
||||
String mismatchDocument = cursor.getString(cursor.getColumnIndexOrThrow(SmsTable.MISMATCHED_IDENTITIES));
|
||||
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SmsTable.SUBSCRIPTION_ID));
|
||||
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SmsTable.SMS_SUBSCRIPTION_ID));
|
||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(SmsTable.EXPIRES_IN));
|
||||
long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(SmsTable.EXPIRE_STARTED));
|
||||
String body = cursor.getString(cursor.getColumnIndexOrThrow(SmsTable.BODY));
|
||||
|
|
|
@ -326,7 +326,7 @@ class StorySendTable(context: Context, databaseHelper: SignalDatabase) : Databas
|
|||
// language=sql
|
||||
"""
|
||||
SELECT
|
||||
$RECIPIENT_ID,
|
||||
$TABLE_NAME.$RECIPIENT_ID,
|
||||
$ALLOWS_REPLIES,
|
||||
$DISTRIBUTION_ID,
|
||||
${MmsTable.REMOTE_DELETED}
|
||||
|
|
|
@ -76,14 +76,13 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
|||
const val TABLE_NAME = "thread"
|
||||
const val ID = "_id"
|
||||
const val DATE = "date"
|
||||
const val MEANINGFUL_MESSAGES = "message_count"
|
||||
const val RECIPIENT_ID = "thread_recipient_id"
|
||||
const val SNIPPET = "snippet"
|
||||
const val SNIPPET_CHARSET = "snippet_charset"
|
||||
const val MEANINGFUL_MESSAGES = "meaningful_messages"
|
||||
const val RECIPIENT_ID = "recipient_id"
|
||||
const val READ = "read"
|
||||
const val UNREAD_COUNT = "unread_count"
|
||||
const val TYPE = "type"
|
||||
const val ERROR = "error"
|
||||
const val SNIPPET = "snippet"
|
||||
const val SNIPPET_TYPE = "snippet_type"
|
||||
const val SNIPPET_URI = "snippet_uri"
|
||||
const val SNIPPET_CONTENT_TYPE = "snippet_content_type"
|
||||
|
@ -106,11 +105,10 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
|||
$DATE INTEGER DEFAULT 0,
|
||||
$MEANINGFUL_MESSAGES INTEGER DEFAULT 0,
|
||||
$RECIPIENT_ID INTEGER,
|
||||
$SNIPPET TEXT,
|
||||
$SNIPPET_CHARSET INTEGER DEFAULT 0,
|
||||
$READ INTEGER DEFAULT ${ReadStatus.READ.serialize()},
|
||||
$TYPE INTEGER DEFAULT 0,
|
||||
$ERROR INTEGER DEFAULT 0,
|
||||
$SNIPPET TEXT,
|
||||
$SNIPPET_TYPE INTEGER DEFAULT 0,
|
||||
$SNIPPET_URI TEXT DEFAULT NULL,
|
||||
$SNIPPET_CONTENT_TYPE TEXT DEFAULT NULL,
|
||||
|
@ -143,7 +141,6 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
|||
MEANINGFUL_MESSAGES,
|
||||
RECIPIENT_ID,
|
||||
SNIPPET,
|
||||
SNIPPET_CHARSET,
|
||||
READ,
|
||||
UNREAD_COUNT,
|
||||
TYPE,
|
||||
|
@ -343,7 +340,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
|||
mmsSms.getConversation(threadId).use { cursor ->
|
||||
if (cursor.count > length) {
|
||||
cursor.moveToPosition(length - 1)
|
||||
max(trimBeforeDate, cursor.requireLong(MmsSmsColumns.NORMALIZED_DATE_RECEIVED))
|
||||
max(trimBeforeDate, cursor.requireLong(MmsSmsColumns.DATE_RECEIVED))
|
||||
} else {
|
||||
trimBeforeDate
|
||||
}
|
||||
|
@ -702,14 +699,14 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
|||
}
|
||||
|
||||
if (hideSelf) {
|
||||
where += " AND $RECIPIENT_ID != ${Recipient.self().id.toLong()}"
|
||||
where += " AND $TABLE_NAME.$RECIPIENT_ID != ${Recipient.self().id.toLong()}"
|
||||
}
|
||||
|
||||
where += " AND $ARCHIVED = 0"
|
||||
where += " AND ${RecipientTable.TABLE_NAME}.${RecipientTable.BLOCKED} = 0"
|
||||
|
||||
if (SignalStore.releaseChannelValues().releaseChannelRecipientId != null) {
|
||||
where += " AND $RECIPIENT_ID != ${SignalStore.releaseChannelValues().releaseChannelRecipientId!!.toLong()}"
|
||||
where += " AND $TABLE_NAME.$RECIPIENT_ID != ${SignalStore.releaseChannelValues().releaseChannelRecipientId!!.toLong()}"
|
||||
}
|
||||
|
||||
val query = createQuery(
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V162_ThreadUnreadSe
|
|||
import org.thoughtcrime.securesms.database.helpers.migration.V163_RemoteMegaphoneSnoozeSupportMigration
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V164_ThreadDatabaseReadIndexMigration
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V165_MmsMessageBoxPaymentTransactionIndexMigration
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V166_ThreadAndMessageForeignKeys
|
||||
|
||||
/**
|
||||
* Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness.
|
||||
|
@ -29,7 +30,7 @@ object SignalDatabaseMigrations {
|
|||
|
||||
val TAG: String = Log.tag(SignalDatabaseMigrations.javaClass)
|
||||
|
||||
const val DATABASE_VERSION = 165
|
||||
const val DATABASE_VERSION = 166
|
||||
|
||||
@JvmStatic
|
||||
fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
|
@ -100,6 +101,10 @@ object SignalDatabaseMigrations {
|
|||
if (oldVersion < 165) {
|
||||
V165_MmsMessageBoxPaymentTransactionIndexMigration.migrate(context, db, oldVersion, newVersion)
|
||||
}
|
||||
|
||||
if (oldVersion < 166) {
|
||||
V166_ThreadAndMessageForeignKeys.migrate(context, db, oldVersion, newVersion)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
|
|
@ -0,0 +1,424 @@
|
|||
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.delete
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.signal.core.util.readToList
|
||||
import org.signal.core.util.requireLong
|
||||
import org.signal.core.util.update
|
||||
|
||||
/**
|
||||
* This one's a doozy. We want to add additional foreign key constraints between the thread, recipient, and message tables. This will let us know for sure
|
||||
* that there aren't threads with invalid recipients, or messages with invalid threads, or multiple threads for the same recipient.
|
||||
*/
|
||||
object V166_ThreadAndMessageForeignKeys : SignalDatabaseMigration {
|
||||
|
||||
private val TAG = Log.tag(V166_ThreadAndMessageForeignKeys::class.java)
|
||||
|
||||
override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
val stopwatch = Stopwatch("migration")
|
||||
|
||||
removeDuplicateThreadEntries(db)
|
||||
stopwatch.split("thread-dupes")
|
||||
|
||||
updateThreadTableSchema(db)
|
||||
stopwatch.split("thread-schema")
|
||||
|
||||
fixDanglingSmsMessages(db)
|
||||
stopwatch.split("sms-dangling")
|
||||
|
||||
fixDanglingMmsMessages(db)
|
||||
stopwatch.split("mms-dangling")
|
||||
|
||||
updateSmsTableSchema(db)
|
||||
stopwatch.split("sms-schema")
|
||||
|
||||
updateMmsTableSchema(db)
|
||||
stopwatch.split("mms-schema")
|
||||
|
||||
stopwatch.stop(TAG)
|
||||
}
|
||||
|
||||
private fun removeDuplicateThreadEntries(db: SQLiteDatabase) {
|
||||
db.rawQuery(
|
||||
"""
|
||||
SELECT
|
||||
thread_recipient_id,
|
||||
COUNT(*) AS thread_count
|
||||
FROM thread
|
||||
GROUP BY thread_recipient_id HAVING thread_count > 1
|
||||
""".trimMargin()
|
||||
).use { cursor ->
|
||||
while (cursor.moveToNext()) {
|
||||
val recipientId = cursor.requireLong("thread_recipient_id")
|
||||
val count = cursor.requireLong("thread_count")
|
||||
Log.w(TAG, "There were $count threads for RecipientId::$recipientId. Merging.")
|
||||
|
||||
val threads: List<ThreadInfo> = getThreadsByRecipientId(db, cursor.requireLong("thread_recipient_id"))
|
||||
mergeThreads(db, threads)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getThreadsByRecipientId(db: SQLiteDatabase, recipientId: Long): List<ThreadInfo> {
|
||||
return db.rawQuery("SELECT _id, date FROM thread WHERE thread_recipient_id = ?".trimIndent(), recipientId).readToList { cursor ->
|
||||
ThreadInfo(cursor.requireLong("_id"), cursor.requireLong("date"))
|
||||
}
|
||||
}
|
||||
|
||||
private fun mergeThreads(db: SQLiteDatabase, threads: List<ThreadInfo>) {
|
||||
val primaryThread: ThreadInfo = threads.maxByOrNull { it.date }!!
|
||||
val secondaryThreads: List<ThreadInfo> = threads.filterNot { it.id == primaryThread.id }
|
||||
|
||||
secondaryThreads.forEach { secondaryThread ->
|
||||
remapThread(db, primaryThread.id, secondaryThread.id)
|
||||
}
|
||||
}
|
||||
|
||||
private fun remapThread(db: SQLiteDatabase, primaryId: Long, secondaryId: Long) {
|
||||
db.update("drafts")
|
||||
.values("thread_id" to primaryId)
|
||||
.where("thread_id = ?", secondaryId)
|
||||
.run()
|
||||
|
||||
db.update("mention")
|
||||
.values("thread_id" to primaryId)
|
||||
.where("thread_id = ?", secondaryId)
|
||||
.run()
|
||||
|
||||
db.update("mms")
|
||||
.values("thread_id" to primaryId)
|
||||
.where("thread_id = ?", secondaryId)
|
||||
.run()
|
||||
|
||||
db.update("sms")
|
||||
.values("thread_id" to primaryId)
|
||||
.where("thread_id = ?", secondaryId)
|
||||
.run()
|
||||
|
||||
db.update("pending_retry_receipts")
|
||||
.values("thread_id" to primaryId)
|
||||
.where("thread_id = ?", secondaryId)
|
||||
.run()
|
||||
|
||||
db.delete("thread")
|
||||
.where("_id = ?", secondaryId)
|
||||
.run()
|
||||
}
|
||||
|
||||
private fun updateThreadTableSchema(db: SQLiteDatabase) {
|
||||
db.execSQL(
|
||||
"""
|
||||
CREATE TABLE thread_tmp (
|
||||
_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
date INTEGER DEFAULT 0,
|
||||
meaningful_messages INTEGER DEFAULT 0,
|
||||
recipient_id INTEGER NOT NULL UNIQUE REFERENCES recipient (_id) ON DELETE CASCADE,
|
||||
read INTEGER DEFAULT 1,
|
||||
type INTEGER DEFAULT 0,
|
||||
error INTEGER DEFAULT 0,
|
||||
snippet TEXT,
|
||||
snippet_type INTEGER DEFAULT 0,
|
||||
snippet_uri TEXT DEFAULT NULL,
|
||||
snippet_content_type TEXT DEFAULT NULL,
|
||||
snippet_extras TEXT DEFAULT NULL,
|
||||
unread_count INTEGER DEFAULT 0,
|
||||
archived INTEGER DEFAULT 0,
|
||||
status INTEGER DEFAULT 0,
|
||||
delivery_receipt_count INTEGER DEFAULT 0,
|
||||
read_receipt_count INTEGER DEFAULT 0,
|
||||
expires_in INTEGER DEFAULT 0,
|
||||
last_seen INTEGER DEFAULT 0,
|
||||
has_sent INTEGER DEFAULT 0,
|
||||
last_scrolled INTEGER DEFAULT 0,
|
||||
pinned INTEGER DEFAULT 0,
|
||||
unread_self_mention_count INTEGER DEFAULT 0
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
db.execSQL(
|
||||
"""
|
||||
INSERT INTO thread_tmp
|
||||
SELECT
|
||||
_id,
|
||||
date,
|
||||
message_count,
|
||||
thread_recipient_id,
|
||||
read,
|
||||
type,
|
||||
error,
|
||||
snippet,
|
||||
snippet_type,
|
||||
snippet_uri,
|
||||
snippet_content_type,
|
||||
snippet_extras,
|
||||
unread_count,
|
||||
archived,
|
||||
status,
|
||||
delivery_receipt_count,
|
||||
read_receipt_count,
|
||||
expires_in,
|
||||
last_seen,
|
||||
has_sent,
|
||||
last_scrolled,
|
||||
pinned,
|
||||
unread_self_mention_count
|
||||
FROM thread
|
||||
""".trimMargin()
|
||||
)
|
||||
|
||||
db.execSQL("DROP TABLE thread")
|
||||
db.execSQL("ALTER TABLE thread_tmp RENAME TO thread")
|
||||
|
||||
db.execSQL("CREATE INDEX thread_recipient_id_index ON thread (recipient_id)")
|
||||
db.execSQL("CREATE INDEX archived_count_index ON thread (archived, meaningful_messages)")
|
||||
db.execSQL("CREATE INDEX thread_pinned_index ON thread (pinned)")
|
||||
db.execSQL("CREATE INDEX thread_read ON thread (read)")
|
||||
}
|
||||
|
||||
private fun fixDanglingSmsMessages(db: SQLiteDatabase) {
|
||||
db.delete("sms")
|
||||
.where("address NOT IN (SELECT _id FROM recipient)")
|
||||
.run()
|
||||
|
||||
// Can't even attempt to "fix" these because without the threadId we don't know if it's a 1:1 or group message
|
||||
db.delete("sms")
|
||||
.where("thread_id NOT IN (SELECT _id FROM thread)")
|
||||
.run()
|
||||
}
|
||||
|
||||
private fun fixDanglingMmsMessages(db: SQLiteDatabase) {
|
||||
db.delete("mms")
|
||||
.where("address NOT IN (SELECT _id FROM recipient)")
|
||||
.run()
|
||||
|
||||
// Can't even attempt to "fix" these because without the threadId we don't know if it's a 1:1 or group message
|
||||
db.delete("mms")
|
||||
.where("thread_id NOT IN (SELECT _id FROM thread)")
|
||||
.run()
|
||||
}
|
||||
|
||||
private fun updateSmsTableSchema(db: SQLiteDatabase) {
|
||||
db.execSQL(
|
||||
"""
|
||||
CREATE TABLE sms_tmp (
|
||||
_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
date_sent INTEGER NOT NULL,
|
||||
date_received INTEGER NOT NULL,
|
||||
date_server INTEGER DEFAULT -1,
|
||||
thread_id INTEGER NOT NULL REFERENCES thread (_id) ON DELETE CASCADE,
|
||||
recipient_id NOT NULL REFERENCES recipient (_id) ON DELETE CASCADE,
|
||||
recipient_device_id INTEGER DEFAULT 1,
|
||||
type INTEGER,
|
||||
body TEXT,
|
||||
read INTEGER DEFAULT 0,
|
||||
status INTEGER DEFAULT -1,
|
||||
delivery_receipt_count INTEGER DEFAULT 0,
|
||||
mismatched_identities TEXT DEFAULT NULL,
|
||||
subscription_id INTEGER DEFAULT -1,
|
||||
expires_in INTEGER DEFAULT 0,
|
||||
expire_started INTEGER DEFAULT 0,
|
||||
notified INTEGER DEFAULT 0,
|
||||
read_receipt_count INTEGER DEFAULT 0,
|
||||
unidentified INTEGER DEFAULT 0,
|
||||
reactions_unread INTEGER DEFAULT 0,
|
||||
reactions_last_seen INTEGER DEFAULT -1,
|
||||
remote_deleted INTEGER DEFAULT 0,
|
||||
notified_timestamp INTEGER DEFAULT 0,
|
||||
server_guid TEXT DEFAULT NULL,
|
||||
receipt_timestamp INTEGER DEFAULT -1,
|
||||
export_state BLOB DEFAULT NULL,
|
||||
exported INTEGER DEFAULT 0
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
db.execSQL(
|
||||
"""
|
||||
INSERT INTO sms_tmp
|
||||
SELECT
|
||||
_id,
|
||||
date_sent,
|
||||
date,
|
||||
date_server,
|
||||
thread_id,
|
||||
address,
|
||||
address_device_id,
|
||||
type,
|
||||
body,
|
||||
read,
|
||||
status,
|
||||
delivery_receipt_count,
|
||||
mismatched_identities,
|
||||
subscription_id,
|
||||
expires_in,
|
||||
expire_started,
|
||||
notified,
|
||||
read_receipt_count,
|
||||
unidentified,
|
||||
reactions_unread,
|
||||
reactions_last_seen,
|
||||
remote_deleted,
|
||||
notified_timestamp,
|
||||
server_guid,
|
||||
receipt_timestamp,
|
||||
export_state,
|
||||
exported
|
||||
FROM sms
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
db.execSQL("DROP TABLE sms")
|
||||
db.execSQL("ALTER TABLE sms_tmp RENAME TO sms")
|
||||
|
||||
db.execSQL("CREATE INDEX sms_read_and_notified_and_thread_id_index ON sms(read, notified, thread_id)")
|
||||
db.execSQL("CREATE INDEX sms_type_index ON sms (type)")
|
||||
db.execSQL("CREATE INDEX sms_date_sent_index ON sms (date_sent, recipient_id, thread_id)")
|
||||
db.execSQL("CREATE INDEX sms_date_server_index ON sms (date_server)")
|
||||
db.execSQL("CREATE INDEX sms_thread_date_index ON sms (thread_id, date_received)")
|
||||
db.execSQL("CREATE INDEX sms_reactions_unread_index ON sms (reactions_unread)")
|
||||
db.execSQL("CREATE INDEX sms_exported_index ON sms (exported)")
|
||||
|
||||
db.execSQL("CREATE TRIGGER sms_ai AFTER INSERT ON sms BEGIN INSERT INTO sms_fts(rowid, body, thread_id) VALUES (new._id, new.body, new.thread_id); END;")
|
||||
db.execSQL("CREATE TRIGGER sms_ad AFTER DELETE ON sms BEGIN INSERT INTO sms_fts(sms_fts, rowid, body, thread_id) VALUES('delete', old._id, old.body, old.thread_id); END;")
|
||||
db.execSQL("CREATE TRIGGER sms_au AFTER UPDATE ON sms BEGIN INSERT INTO sms_fts(sms_fts, rowid, body, thread_id) VALUES('delete', old._id, old.body, old.thread_id); INSERT INTO sms_fts(rowid, body, thread_id) VALUES(new._id, new.body, new.thread_id); END;")
|
||||
db.execSQL("CREATE TRIGGER msl_sms_delete AFTER DELETE ON sms BEGIN DELETE FROM msl_payload WHERE _id IN (SELECT payload_id FROM msl_message WHERE message_id = old._id AND is_mms = 0); END")
|
||||
}
|
||||
|
||||
private fun updateMmsTableSchema(db: SQLiteDatabase) {
|
||||
db.execSQL(
|
||||
"""
|
||||
CREATE TABLE mms_tmp (
|
||||
_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
date_sent INTEGER NOT NULL,
|
||||
date_received INTEGER NOT NULL,
|
||||
date_server INTEGER DEFAULT -1,
|
||||
thread_id INTEGER NOT NULL REFERENCES thread (_id) ON DELETE CASCADE,
|
||||
recipient_id INTEGER NOT NULL REFERENCES recipient (_id) ON DELETE CASCADE,
|
||||
recipient_device_id INTEGER,
|
||||
type INTEGER NOT NULL,
|
||||
body TEXT,
|
||||
read INTEGER DEFAULT 0,
|
||||
ct_l TEXT,
|
||||
exp INTEGER,
|
||||
m_type INTEGER,
|
||||
m_size INTEGER,
|
||||
st INTEGER,
|
||||
tr_id TEXT,
|
||||
subscription_id INTEGER DEFAULT -1,
|
||||
receipt_timestamp INTEGER DEFAULT -1,
|
||||
delivery_receipt_count INTEGER DEFAULT 0,
|
||||
read_receipt_count INTEGER DEFAULT 0,
|
||||
viewed_receipt_count INTEGER DEFAULT 0,
|
||||
mismatched_identities TEXT DEFAULT NULL,
|
||||
network_failures TEXT DEFAULT NULL,
|
||||
expires_in INTEGER DEFAULT 0,
|
||||
expire_started INTEGER DEFAULT 0,
|
||||
notified INTEGER DEFAULT 0,
|
||||
quote_id INTEGER DEFAULT 0,
|
||||
quote_author INTEGER DEFAULT 0,
|
||||
quote_body TEXT DEFAULT NULL,
|
||||
quote_missing INTEGER DEFAULT 0,
|
||||
quote_mentions BLOB DEFAULT NULL,
|
||||
quote_type INTEGER DEFAULT 0,
|
||||
shared_contacts TEXT DEFAULT NULL,
|
||||
unidentified INTEGER DEFAULT 0,
|
||||
link_previews TEXT DEFAULT NULL,
|
||||
view_once INTEGER DEFAULT 0,
|
||||
reactions_unread INTEGER DEFAULT 0,
|
||||
reactions_last_seen INTEGER DEFAULT -1,
|
||||
remote_deleted INTEGER DEFAULT 0,
|
||||
mentions_self INTEGER DEFAULT 0,
|
||||
notified_timestamp INTEGER DEFAULT 0,
|
||||
server_guid TEXT DEFAULT NULL,
|
||||
message_ranges BLOB DEFAULT NULL,
|
||||
story_type INTEGER DEFAULT 0,
|
||||
parent_story_id INTEGER DEFAULT 0,
|
||||
export_state BLOB DEFAULT NULL,
|
||||
exported INTEGER DEFAULT 0
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
db.execSQL(
|
||||
"""
|
||||
INSERT INTO mms_tmp
|
||||
SELECT
|
||||
_id,
|
||||
date,
|
||||
date_received,
|
||||
date_server,
|
||||
thread_id,
|
||||
address,
|
||||
address_device_id,
|
||||
msg_box,
|
||||
body,
|
||||
read,
|
||||
ct_l,
|
||||
exp,
|
||||
m_type,
|
||||
m_size,
|
||||
st,
|
||||
tr_id,
|
||||
subscription_id,
|
||||
receipt_timestamp,
|
||||
delivery_receipt_count,
|
||||
read_receipt_count,
|
||||
viewed_receipt_count,
|
||||
mismatched_identities,
|
||||
network_failures,
|
||||
expires_in,
|
||||
expire_started,
|
||||
notified,
|
||||
quote_id,
|
||||
quote_author,
|
||||
quote_body,
|
||||
quote_missing,
|
||||
quote_mentions,
|
||||
quote_type,
|
||||
shared_contacts,
|
||||
unidentified,
|
||||
previews,
|
||||
reveal_duration,
|
||||
reactions_unread,
|
||||
reactions_last_seen,
|
||||
remote_deleted,
|
||||
mentions_self,
|
||||
notified_timestamp,
|
||||
server_guid,
|
||||
ranges,
|
||||
is_story,
|
||||
parent_story_id,
|
||||
export_state,
|
||||
exported
|
||||
FROM mms
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
db.execSQL("DROP TABLE mms")
|
||||
db.execSQL("ALTER TABLE mms_tmp RENAME TO mms")
|
||||
|
||||
db.execSQL("CREATE INDEX mms_read_and_notified_and_thread_id_index ON mms(read, notified, thread_id)")
|
||||
db.execSQL("CREATE INDEX mms_type_index ON mms (type)")
|
||||
db.execSQL("CREATE INDEX mms_date_sent_index ON mms (date_sent, recipient_id, thread_id)")
|
||||
db.execSQL("CREATE INDEX mms_date_server_index ON mms (date_server)")
|
||||
db.execSQL("CREATE INDEX mms_thread_date_index ON mms (thread_id, date_received)")
|
||||
db.execSQL("CREATE INDEX mms_reactions_unread_index ON mms (reactions_unread)")
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS mms_story_type_index ON mms (story_type)")
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS mms_parent_story_id_index ON mms (parent_story_id)")
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS mms_thread_story_parent_story_index ON mms (thread_id, date_received, story_type, parent_story_id)")
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS mms_quote_id_quote_author_index ON mms (quote_id, quote_author)")
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS mms_exported_index ON mms (exported)")
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS mms_id_type_payment_transactions_index ON mms (_id, type) WHERE type & ${0x300000000L} != 0")
|
||||
|
||||
db.execSQL("CREATE TRIGGER mms_ai AFTER INSERT ON mms BEGIN INSERT INTO mms_fts(rowid, body, thread_id) VALUES (new._id, new.body, new.thread_id); END")
|
||||
db.execSQL("CREATE TRIGGER mms_ad AFTER DELETE ON mms BEGIN INSERT INTO mms_fts(mms_fts, rowid, body, thread_id) VALUES('delete', old._id, old.body, old.thread_id); END")
|
||||
db.execSQL("CREATE TRIGGER mms_au AFTER UPDATE ON mms BEGIN INSERT INTO mms_fts(mms_fts, rowid, body, thread_id) VALUES('delete', old._id, old.body, old.thread_id); INSERT INTO mms_fts(rowid, body, thread_id) VALUES (new._id, new.body, new.thread_id); END")
|
||||
db.execSQL("CREATE TRIGGER msl_mms_delete AFTER DELETE ON mms BEGIN DELETE FROM msl_payload WHERE _id IN (SELECT payload_id FROM msl_message WHERE message_id = old._id AND is_mms = 1); END")
|
||||
}
|
||||
|
||||
data class ThreadInfo(val id: Long, val date: Long)
|
||||
}
|
|
@ -60,7 +60,6 @@ import java.util.stream.Collectors;
|
|||
public class MediaMmsMessageRecord extends MmsMessageRecord {
|
||||
private final static String TAG = Log.tag(MediaMmsMessageRecord.class);
|
||||
|
||||
private final int partCount;
|
||||
private final boolean mentionsSelf;
|
||||
private final BodyRangeList messageRanges;
|
||||
private final Payment payment;
|
||||
|
@ -76,7 +75,6 @@ public class MediaMmsMessageRecord extends MmsMessageRecord {
|
|||
long threadId,
|
||||
String body,
|
||||
@NonNull SlideDeck slideDeck,
|
||||
int partCount,
|
||||
long mailbox,
|
||||
Set<IdentityKeyMismatch> mismatches,
|
||||
Set<NetworkFailure> failures,
|
||||
|
@ -106,7 +104,6 @@ public class MediaMmsMessageRecord extends MmsMessageRecord {
|
|||
subscriptionId, expiresIn, expireStarted, viewOnce, slideDeck,
|
||||
readReceiptCount, quote, contacts, linkPreviews, unidentified, reactions, remoteDelete, notifiedTimestamp, viewedReceiptCount, receiptTimestamp,
|
||||
storyType, parentStoryId, giftBadge);
|
||||
this.partCount = partCount;
|
||||
this.mentionsSelf = mentionsSelf;
|
||||
this.messageRanges = messageRanges;
|
||||
this.payment = payment;
|
||||
|
@ -140,10 +137,6 @@ public class MediaMmsMessageRecord extends MmsMessageRecord {
|
|||
return super.getDisplayBody(context);
|
||||
}
|
||||
|
||||
public int getPartCount() {
|
||||
return partCount;
|
||||
}
|
||||
|
||||
public @Nullable BodyRangeList getMessageRanges() {
|
||||
return messageRanges;
|
||||
}
|
||||
|
@ -164,14 +157,14 @@ public class MediaMmsMessageRecord extends MmsMessageRecord {
|
|||
|
||||
public @NonNull MediaMmsMessageRecord withReactions(@NonNull List<ReactionRecord> reactions) {
|
||||
return new MediaMmsMessageRecord(getId(), getRecipient(), getIndividualRecipient(), getRecipientDeviceId(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), getSlideDeck(),
|
||||
getPartCount(), getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(),
|
||||
getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(),
|
||||
getReadReceiptCount(), getQuote(), getSharedContacts(), getLinkPreviews(), isUnidentified(), reactions, isRemoteDelete(), mentionsSelf,
|
||||
getNotifiedTimestamp(), getViewedReceiptCount(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment());
|
||||
}
|
||||
|
||||
public @NonNull MediaMmsMessageRecord withoutQuote() {
|
||||
return new MediaMmsMessageRecord(getId(), getRecipient(), getIndividualRecipient(), getRecipientDeviceId(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), getSlideDeck(),
|
||||
getPartCount(), getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(),
|
||||
getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(),
|
||||
getReadReceiptCount(), null, getSharedContacts(), getLinkPreviews(), isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf,
|
||||
getNotifiedTimestamp(), getViewedReceiptCount(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment());
|
||||
}
|
||||
|
@ -192,14 +185,14 @@ public class MediaMmsMessageRecord extends MmsMessageRecord {
|
|||
SlideDeck slideDeck = MmsTable.Reader.buildSlideDeck(context, slideAttachments);
|
||||
|
||||
return new MediaMmsMessageRecord(getId(), getRecipient(), getIndividualRecipient(), getRecipientDeviceId(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), slideDeck,
|
||||
getPartCount(), getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(),
|
||||
getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(),
|
||||
getReadReceiptCount(), quote, contacts, linkPreviews, isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf,
|
||||
getNotifiedTimestamp(), getViewedReceiptCount(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment());
|
||||
}
|
||||
|
||||
public @NonNull MediaMmsMessageRecord withPayment(@NonNull Payment payment) {
|
||||
return new MediaMmsMessageRecord(getId(), getRecipient(), getIndividualRecipient(), getRecipientDeviceId(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), getSlideDeck(),
|
||||
getPartCount(), getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(),
|
||||
getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(),
|
||||
getReadReceiptCount(), getQuote(), getSharedContacts(), getLinkPreviews(), isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf,
|
||||
getNotifiedTimestamp(), getViewedReceiptCount(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), payment);
|
||||
}
|
||||
|
|
|
@ -111,9 +111,10 @@ public class ApplicationMigrations {
|
|||
static final int SYSTEM_NAME_SYNC = 67;
|
||||
static final int STORY_VIEWED_STATE = 68;
|
||||
static final int STORY_READ_STATE = 69;
|
||||
static final int THREAD_MESSAGE_SCHEMA_CHANGE = 70;
|
||||
}
|
||||
|
||||
public static final int CURRENT_VERSION = 69;
|
||||
public static final int CURRENT_VERSION = 70;
|
||||
|
||||
/**
|
||||
* This *must* be called after the {@link JobManager} has been instantiated, but *before* the call
|
||||
|
@ -491,6 +492,10 @@ public class ApplicationMigrations {
|
|||
jobs.put(Version.STORY_READ_STATE, new StoryReadStateMigrationJob());
|
||||
}
|
||||
|
||||
if (lastSeenVersion < Version.THREAD_MESSAGE_SCHEMA_CHANGE) {
|
||||
jobs.put(Version.THREAD_MESSAGE_SCHEMA_CHANGE, new DatabaseMigrationJob());
|
||||
}
|
||||
|
||||
return jobs;
|
||||
}
|
||||
|
||||
|
|
|
@ -451,7 +451,7 @@ public class SearchRepository {
|
|||
Recipient messageRecipient = Recipient.live(messageRecipientId).get();
|
||||
String body = CursorUtil.requireString(cursor, SearchTable.BODY);
|
||||
String bodySnippet = CursorUtil.requireString(cursor, SearchTable.SNIPPET);
|
||||
long receivedMs = CursorUtil.requireLong(cursor, MmsSmsColumns.NORMALIZED_DATE_RECEIVED);
|
||||
long receivedMs = CursorUtil.requireLong(cursor, MmsSmsColumns.DATE_RECEIVED);
|
||||
long threadId = CursorUtil.requireLong(cursor, MmsSmsColumns.THREAD_ID);
|
||||
int messageId = CursorUtil.requireInt(cursor, SearchTable.MESSAGE_ID);
|
||||
boolean isMms = CursorUtil.requireInt(cursor, SearchTable.IS_MMS) == 1;
|
||||
|
|
|
@ -1,226 +0,0 @@
|
|||
package org.thoughtcrime.securesms.service;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.PowerManager;
|
||||
import android.os.PowerManager.WakeLock;
|
||||
|
||||
import androidx.core.app.NotificationCompat;
|
||||
|
||||
import org.signal.core.util.PendingIntentFlags;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.MainActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.database.SmsMigrator;
|
||||
import org.thoughtcrime.securesms.database.SmsMigrator.ProgressDescription;
|
||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||
import org.thoughtcrime.securesms.notifications.NotificationIds;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
// FIXME: This class is nuts.
|
||||
public class ApplicationMigrationService extends Service
|
||||
implements SmsMigrator.SmsMigrationProgressListener
|
||||
{
|
||||
private static final String TAG = Log.tag(ApplicationMigrationService.class);
|
||||
public static final String MIGRATE_DATABASE = "org.thoughtcrime.securesms.ApplicationMigration.MIGRATE_DATABSE";
|
||||
public static final String COMPLETED_ACTION = "org.thoughtcrime.securesms.ApplicationMigrationService.COMPLETED";
|
||||
private static final String PREFERENCES_NAME = "SecureSMS";
|
||||
private static final String DATABASE_MIGRATED = "migrated";
|
||||
|
||||
private final BroadcastReceiver completedReceiver = new CompletedReceiver();
|
||||
private final Binder binder = new ApplicationMigrationBinder();
|
||||
private final Executor executor = Executors.newSingleThreadExecutor();
|
||||
|
||||
private WeakReference<Handler> handler = null;
|
||||
private NotificationCompat.Builder notification = null;
|
||||
private ImportState state = new ImportState(ImportState.STATE_IDLE, null);
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
registerCompletedReceiver();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
if (intent == null) return START_NOT_STICKY;
|
||||
|
||||
if (intent.getAction() != null && intent.getAction().equals(MIGRATE_DATABASE)) {
|
||||
executor.execute(new ImportRunnable());
|
||||
}
|
||||
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
unregisterCompletedReceiver();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return binder;
|
||||
}
|
||||
|
||||
public void setImportStateHandler(Handler handler) {
|
||||
this.handler = new WeakReference<>(handler);
|
||||
}
|
||||
|
||||
private void registerCompletedReceiver() {
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(COMPLETED_ACTION);
|
||||
|
||||
registerReceiver(completedReceiver, filter);
|
||||
}
|
||||
|
||||
private void unregisterCompletedReceiver() {
|
||||
unregisterReceiver(completedReceiver);
|
||||
}
|
||||
|
||||
private void notifyImportComplete() {
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(COMPLETED_ACTION);
|
||||
|
||||
sendOrderedBroadcast(intent, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void progressUpdate(ProgressDescription progress) {
|
||||
setState(new ImportState(ImportState.STATE_MIGRATING_IN_PROGRESS, progress));
|
||||
}
|
||||
|
||||
public ImportState getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
private void setState(ImportState state) {
|
||||
this.state = state;
|
||||
|
||||
if (this.handler != null) {
|
||||
Handler handler = this.handler.get();
|
||||
|
||||
if (handler != null) {
|
||||
handler.obtainMessage(state.state, state.progress).sendToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
if (state.progress != null && state.progress.secondaryComplete == 0) {
|
||||
updateBackgroundNotification(state.progress.primaryTotal, state.progress.primaryComplete);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateBackgroundNotification(int total, int complete) {
|
||||
notification.setProgress(total, complete, false);
|
||||
|
||||
((NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE))
|
||||
.notify(NotificationIds.APPLICATION_MIGRATION, notification.build());
|
||||
}
|
||||
|
||||
private NotificationCompat.Builder initializeBackgroundNotification() {
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NotificationChannels.OTHER);
|
||||
|
||||
builder.setSmallIcon(R.drawable.ic_notification);
|
||||
builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_notification));
|
||||
builder.setContentTitle(getString(R.string.ApplicationMigrationService_importing_text_messages));
|
||||
builder.setContentText(getString(R.string.ApplicationMigrationService_import_in_progress));
|
||||
builder.setOngoing(true);
|
||||
builder.setProgress(100, 0, false);
|
||||
// TODO [greyson] Navigation
|
||||
builder.setContentIntent(PendingIntent.getActivity(this, 0, MainActivity.clearTop(this), PendingIntentFlags.mutable()));
|
||||
|
||||
stopForeground(true);
|
||||
startForeground(NotificationIds.APPLICATION_MIGRATION, builder.build());
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
private class ImportRunnable implements Runnable {
|
||||
|
||||
ImportRunnable() {}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
notification = initializeBackgroundNotification();
|
||||
PowerManager powerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
|
||||
WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "signal:migration");
|
||||
|
||||
try {
|
||||
wakeLock.acquire();
|
||||
|
||||
setState(new ImportState(ImportState.STATE_MIGRATING_BEGIN, null));
|
||||
|
||||
SmsMigrator.migrateDatabase(ApplicationMigrationService.this,
|
||||
ApplicationMigrationService.this);
|
||||
|
||||
setState(new ImportState(ImportState.STATE_MIGRATING_COMPLETE, null));
|
||||
|
||||
setDatabaseImported(ApplicationMigrationService.this);
|
||||
stopForeground(true);
|
||||
notifyImportComplete();
|
||||
stopSelf();
|
||||
} finally {
|
||||
wakeLock.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ApplicationMigrationBinder extends Binder {
|
||||
public ApplicationMigrationService getService() {
|
||||
return ApplicationMigrationService.this;
|
||||
}
|
||||
}
|
||||
|
||||
private static class CompletedReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, NotificationChannels.OTHER);
|
||||
builder.setSmallIcon(R.drawable.ic_notification);
|
||||
builder.setContentTitle(context.getString(R.string.ApplicationMigrationService_import_complete));
|
||||
builder.setContentText(context.getString(R.string.ApplicationMigrationService_system_database_import_is_complete));
|
||||
// TODO [greyson] Navigation
|
||||
builder.setContentIntent(PendingIntent.getActivity(context, 0, MainActivity.clearTop(context), PendingIntentFlags.mutable()));
|
||||
builder.setWhen(System.currentTimeMillis());
|
||||
builder.setDefaults(Notification.DEFAULT_VIBRATE);
|
||||
builder.setAutoCancel(true);
|
||||
|
||||
Notification notification = builder.build();
|
||||
((NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE)).notify(NotificationIds.SMS_IMPORT_COMPLETE, notification);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ImportState {
|
||||
public static final int STATE_IDLE = 0;
|
||||
public static final int STATE_MIGRATING_BEGIN = 1;
|
||||
public static final int STATE_MIGRATING_IN_PROGRESS = 2;
|
||||
public static final int STATE_MIGRATING_COMPLETE = 3;
|
||||
|
||||
public int state;
|
||||
public ProgressDescription progress;
|
||||
|
||||
public ImportState(int state, ProgressDescription progress) {
|
||||
this.state = state;
|
||||
this.progress = progress;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isDatabaseImported(Context context) {
|
||||
return context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE)
|
||||
.getBoolean(DATABASE_MIGRATED, false);
|
||||
}
|
||||
|
||||
public static void setDatabaseImported(Context context) {
|
||||
context.getSharedPreferences(PREFERENCES_NAME, 0).edit().putBoolean(DATABASE_MIGRATED, true).apply();
|
||||
}
|
||||
}
|
|
@ -31,10 +31,6 @@ public class MmsListener extends BroadcastReceiver {
|
|||
private static final String TAG = Log.tag(MmsListener.class);
|
||||
|
||||
private boolean isRelevant(Context context, Intent intent) {
|
||||
if (!ApplicationMigrationService.isDatabaseImported(context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Telephony.Sms.Intents.WAP_PUSH_RECEIVED_ACTION.equals(intent.getAction()) && Util.isDefaultSmsProvider(context)) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -86,9 +86,6 @@ public class SmsListener extends BroadcastReceiver {
|
|||
if (isExemption(message, messageBody))
|
||||
return false;
|
||||
|
||||
if (!ApplicationMigrationService.isDatabaseImported(context))
|
||||
return false;
|
||||
|
||||
if (SMS_RECEIVED_ACTION.equals(intent.getAction()) && Util.isDefaultSmsProvider(context)) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -39,8 +39,7 @@ object GV2UpdateTransformer : ColumnTransformer {
|
|||
|
||||
private fun Cursor.getMessageType(): Long {
|
||||
return when {
|
||||
getColumnIndex(SmsTable.TYPE) != -1 -> requireLong(SmsTable.TYPE)
|
||||
getColumnIndex(MmsTable.MESSAGE_BOX) != -1 -> requireLong(MmsTable.MESSAGE_BOX)
|
||||
getColumnIndex(MmsSmsColumns.TYPE) != -1 -> requireLong(MmsSmsColumns.TYPE)
|
||||
else -> -1
|
||||
}
|
||||
}
|
||||
|
|
|
@ -151,7 +151,6 @@ object FakeMessageRecords {
|
|||
threadId,
|
||||
body,
|
||||
slideDeck,
|
||||
partCount,
|
||||
mailbox,
|
||||
mismatches,
|
||||
failures,
|
||||
|
|
|
@ -77,13 +77,13 @@ object TestMms {
|
|||
): Long {
|
||||
val contentValues = ContentValues().apply {
|
||||
put(MmsTable.DATE_SENT, message.sentTimeMillis)
|
||||
put(MmsTable.MESSAGE_TYPE, PduHeaders.MESSAGE_TYPE_SEND_REQ)
|
||||
put(MmsTable.MMS_MESSAGE_TYPE, PduHeaders.MESSAGE_TYPE_SEND_REQ)
|
||||
|
||||
put(MmsTable.MESSAGE_BOX, type)
|
||||
put(MmsTable.TYPE, type)
|
||||
put(MmsSmsColumns.THREAD_ID, threadId)
|
||||
put(MmsSmsColumns.READ, if (unread) 0 else 1)
|
||||
put(MmsTable.DATE_RECEIVED, receivedTimestampMillis)
|
||||
put(MmsSmsColumns.SUBSCRIPTION_ID, message.subscriptionId)
|
||||
put(MmsSmsColumns.SMS_SUBSCRIPTION_ID, message.subscriptionId)
|
||||
put(MmsSmsColumns.EXPIRES_IN, message.expiresIn)
|
||||
put(MmsTable.VIEW_ONCE, message.isViewOnce)
|
||||
put(MmsSmsColumns.RECIPIENT_ID, recipientId.serialize())
|
||||
|
@ -93,7 +93,6 @@ object TestMms {
|
|||
put(MmsTable.STORY_TYPE, message.storyType.code)
|
||||
|
||||
put(MmsSmsColumns.BODY, body)
|
||||
put(MmsTable.PART_COUNT, 0)
|
||||
put(MmsTable.MENTIONS_SELF, 0)
|
||||
}
|
||||
|
||||
|
@ -106,7 +105,6 @@ object TestMms {
|
|||
values.putNull(MmsSmsColumns.BODY)
|
||||
values.putNull(MmsTable.QUOTE_BODY)
|
||||
values.putNull(MmsTable.QUOTE_AUTHOR)
|
||||
values.putNull(MmsTable.QUOTE_ATTACHMENT)
|
||||
values.put(MmsTable.QUOTE_TYPE, -1)
|
||||
values.putNull(MmsTable.QUOTE_ID)
|
||||
values.putNull(MmsTable.LINK_PREVIEWS)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package org.thoughtcrime.securesms.database
|
||||
|
||||
import android.content.ContentValues
|
||||
import android.text.TextUtils
|
||||
import org.thoughtcrime.securesms.groups.GroupId
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.sms.IncomingTextMessage
|
||||
|
@ -61,22 +60,14 @@ object TestSms {
|
|||
): Long {
|
||||
val values = ContentValues().apply {
|
||||
put(MmsSmsColumns.RECIPIENT_ID, message.sender.serialize())
|
||||
put(MmsSmsColumns.ADDRESS_DEVICE_ID, message.senderDeviceId)
|
||||
put(MmsSmsColumns.RECIPIENT_DEVICE_ID, message.senderDeviceId)
|
||||
put(SmsTable.DATE_RECEIVED, message.receivedTimestampMillis)
|
||||
put(SmsTable.DATE_SENT, message.sentTimestampMillis)
|
||||
put(MmsSmsColumns.DATE_SERVER, message.serverTimestampMillis)
|
||||
put(SmsTable.PROTOCOL, message.protocol)
|
||||
put(MmsSmsColumns.READ, if (unread) 0 else 1)
|
||||
put(MmsSmsColumns.SUBSCRIPTION_ID, message.subscriptionId)
|
||||
put(MmsSmsColumns.SMS_SUBSCRIPTION_ID, message.subscriptionId)
|
||||
put(MmsSmsColumns.EXPIRES_IN, message.expiresIn)
|
||||
put(MmsSmsColumns.UNIDENTIFIED, message.isUnidentified)
|
||||
|
||||
if (!TextUtils.isEmpty(message.pseudoSubject)) {
|
||||
put(SmsTable.SUBJECT, message.pseudoSubject)
|
||||
}
|
||||
|
||||
put(SmsTable.REPLY_PATH_PRESENT, message.isReplyPathPresent)
|
||||
put(SmsTable.SERVICE_CENTER, message.serviceCenterAddress)
|
||||
put(MmsSmsColumns.BODY, message.messageBody)
|
||||
put(SmsTable.TYPE, type)
|
||||
put(MmsSmsColumns.THREAD_ID, threadId)
|
||||
|
|
|
@ -6,6 +6,7 @@ import android.database.sqlite.SQLiteDatabase
|
|||
import androidx.core.content.contentValuesOf
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import androidx.sqlite.db.SupportSQLiteQueryBuilder
|
||||
import org.intellij.lang.annotations.Language
|
||||
|
||||
/**
|
||||
* Begins a transaction on the `this` database, runs the provided [block] providing the `this` value as it's argument
|
||||
|
@ -85,7 +86,7 @@ class SelectBuilderPart2(
|
|||
private val columns: Array<String>,
|
||||
private val tableName: String
|
||||
) {
|
||||
fun where(where: String, vararg whereArgs: Any): SelectBuilderPart3 {
|
||||
fun where(@Language("sql") where: String, vararg whereArgs: Any): SelectBuilderPart3 {
|
||||
return SelectBuilderPart3(db, columns, tableName, where, SqlUtil.buildArgs(*whereArgs))
|
||||
}
|
||||
|
||||
|
@ -213,7 +214,7 @@ class UpdateBuilderPart2(
|
|||
private val tableName: String,
|
||||
private val values: ContentValues
|
||||
) {
|
||||
fun where(where: String, vararg whereArgs: Any): UpdateBuilderPart3 {
|
||||
fun where(@Language("sql") where: String, vararg whereArgs: Any): UpdateBuilderPart3 {
|
||||
return UpdateBuilderPart3(db, tableName, values, where, SqlUtil.buildArgs(*whereArgs))
|
||||
}
|
||||
|
||||
|
@ -239,7 +240,7 @@ class DeleteBuilderPart1(
|
|||
private val db: SupportSQLiteDatabase,
|
||||
private val tableName: String
|
||||
) {
|
||||
fun where(where: String, vararg whereArgs: Any): DeleteBuilderPart2 {
|
||||
fun where(@Language("sql") where: String, vararg whereArgs: Any): DeleteBuilderPart2 {
|
||||
return DeleteBuilderPart2(db, tableName, where, SqlUtil.buildArgs(*whereArgs))
|
||||
}
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue