2013-09-09 01:19:05 +00:00
|
|
|
package org.thoughtcrime.securesms.database;
|
|
|
|
|
|
|
|
import android.content.ContentValues;
|
|
|
|
import android.content.Context;
|
2013-09-09 23:46:03 +00:00
|
|
|
import android.database.Cursor;
|
2015-04-21 20:04:00 +00:00
|
|
|
import android.support.annotation.NonNull;
|
2014-11-03 23:16:04 +00:00
|
|
|
import android.util.Log;
|
2013-09-09 01:19:05 +00:00
|
|
|
|
2018-01-25 03:17:44 +00:00
|
|
|
import net.sqlcipher.database.SQLiteDatabase;
|
|
|
|
|
|
|
|
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
2014-11-12 19:15:05 +00:00
|
|
|
import org.thoughtcrime.securesms.util.Base64;
|
2016-03-23 17:34:41 +00:00
|
|
|
import org.whispersystems.libsignal.util.guava.Optional;
|
|
|
|
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
|
|
|
|
import org.whispersystems.signalservice.internal.util.Util;
|
2013-09-09 01:19:05 +00:00
|
|
|
|
2013-09-09 23:46:03 +00:00
|
|
|
import java.io.IOException;
|
|
|
|
|
2013-09-09 01:19:05 +00:00
|
|
|
public class PushDatabase extends Database {
|
|
|
|
|
2014-11-04 23:01:32 +00:00
|
|
|
private static final String TAG = PushDatabase.class.getSimpleName();
|
|
|
|
|
2013-09-09 01:19:05 +00:00
|
|
|
private static final String TABLE_NAME = "push";
|
|
|
|
public static final String ID = "_id";
|
|
|
|
public static final String TYPE = "type";
|
|
|
|
public static final String SOURCE = "source";
|
2014-02-03 03:38:06 +00:00
|
|
|
public static final String DEVICE_ID = "device_id";
|
2015-05-29 23:23:47 +00:00
|
|
|
public static final String LEGACY_MSG = "body";
|
|
|
|
public static final String CONTENT = "content";
|
2013-09-09 01:19:05 +00:00
|
|
|
public static final String TIMESTAMP = "timestamp";
|
|
|
|
|
|
|
|
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ID + " INTEGER PRIMARY KEY, " +
|
2015-05-29 23:23:47 +00:00
|
|
|
TYPE + " INTEGER, " + SOURCE + " TEXT, " + DEVICE_ID + " INTEGER, " + LEGACY_MSG + " TEXT, " + CONTENT + " TEXT, " + TIMESTAMP + " INTEGER);";
|
2013-09-09 01:19:05 +00:00
|
|
|
|
2018-01-25 03:17:44 +00:00
|
|
|
public PushDatabase(Context context, SQLCipherOpenHelper databaseHelper) {
|
2013-09-09 01:19:05 +00:00
|
|
|
super(context, databaseHelper);
|
|
|
|
}
|
|
|
|
|
2016-03-23 17:34:41 +00:00
|
|
|
public long insert(@NonNull SignalServiceEnvelope envelope) {
|
2015-04-21 20:04:00 +00:00
|
|
|
Optional<Long> messageId = find(envelope);
|
2013-09-09 01:19:05 +00:00
|
|
|
|
2015-04-21 20:04:00 +00:00
|
|
|
if (messageId.isPresent()) {
|
|
|
|
return messageId.get();
|
|
|
|
} else {
|
|
|
|
ContentValues values = new ContentValues();
|
|
|
|
values.put(TYPE, envelope.getType());
|
|
|
|
values.put(SOURCE, envelope.getSource());
|
|
|
|
values.put(DEVICE_ID, envelope.getSourceDevice());
|
2015-05-29 23:23:47 +00:00
|
|
|
values.put(LEGACY_MSG, envelope.hasLegacyMessage() ? Base64.encodeBytes(envelope.getLegacyMessage()) : "");
|
|
|
|
values.put(CONTENT, envelope.hasContent() ? Base64.encodeBytes(envelope.getContent()) : "");
|
2015-04-21 20:04:00 +00:00
|
|
|
values.put(TIMESTAMP, envelope.getTimestamp());
|
|
|
|
|
|
|
|
return databaseHelper.getWritableDatabase().insert(TABLE_NAME, null, values);
|
|
|
|
}
|
2013-09-09 01:19:05 +00:00
|
|
|
}
|
|
|
|
|
2016-03-23 17:34:41 +00:00
|
|
|
public SignalServiceEnvelope get(long id) throws NoSuchMessageException {
|
2014-11-03 23:16:04 +00:00
|
|
|
Cursor cursor = null;
|
|
|
|
|
|
|
|
try {
|
|
|
|
cursor = databaseHelper.getReadableDatabase().query(TABLE_NAME, null, ID_WHERE,
|
|
|
|
new String[] {String.valueOf(id)},
|
|
|
|
null, null, null);
|
|
|
|
|
|
|
|
if (cursor != null && cursor.moveToNext()) {
|
2015-05-29 23:23:47 +00:00
|
|
|
String legacyMessage = cursor.getString(cursor.getColumnIndexOrThrow(LEGACY_MSG));
|
|
|
|
String content = cursor.getString(cursor.getColumnIndexOrThrow(CONTENT));
|
|
|
|
|
2016-03-23 17:34:41 +00:00
|
|
|
return new SignalServiceEnvelope(cursor.getInt(cursor.getColumnIndexOrThrow(TYPE)),
|
|
|
|
cursor.getString(cursor.getColumnIndexOrThrow(SOURCE)),
|
|
|
|
cursor.getInt(cursor.getColumnIndexOrThrow(DEVICE_ID)),
|
|
|
|
"",
|
|
|
|
cursor.getLong(cursor.getColumnIndexOrThrow(TIMESTAMP)),
|
|
|
|
Util.isEmpty(legacyMessage) ? null : Base64.decode(legacyMessage),
|
|
|
|
Util.isEmpty(content) ? null : Base64.decode(content));
|
2014-11-03 23:16:04 +00:00
|
|
|
}
|
|
|
|
} catch (IOException e) {
|
2014-11-04 23:01:32 +00:00
|
|
|
Log.w(TAG, e);
|
2014-11-03 23:16:04 +00:00
|
|
|
throw new NoSuchMessageException(e);
|
|
|
|
} finally {
|
|
|
|
if (cursor != null)
|
|
|
|
cursor.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
throw new NoSuchMessageException("Not found");
|
|
|
|
}
|
|
|
|
|
2013-09-09 23:46:03 +00:00
|
|
|
public Cursor getPending() {
|
|
|
|
return databaseHelper.getReadableDatabase().query(TABLE_NAME, null, null, null, null, null, null);
|
|
|
|
}
|
|
|
|
|
2013-09-09 01:19:05 +00:00
|
|
|
public void delete(long id) {
|
|
|
|
databaseHelper.getWritableDatabase().delete(TABLE_NAME, ID_WHERE, new String[] {id+""});
|
|
|
|
}
|
2013-09-09 23:46:03 +00:00
|
|
|
|
|
|
|
public Reader readerFor(Cursor cursor) {
|
|
|
|
return new Reader(cursor);
|
|
|
|
}
|
|
|
|
|
2016-03-23 17:34:41 +00:00
|
|
|
private Optional<Long> find(SignalServiceEnvelope envelope) {
|
2015-04-21 20:04:00 +00:00
|
|
|
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
|
|
|
Cursor cursor = null;
|
|
|
|
|
|
|
|
try {
|
|
|
|
cursor = database.query(TABLE_NAME, null, TYPE + " = ? AND " + SOURCE + " = ? AND " +
|
2015-05-29 23:23:47 +00:00
|
|
|
DEVICE_ID + " = ? AND " + LEGACY_MSG + " = ? AND " +
|
|
|
|
CONTENT + " = ? AND " + TIMESTAMP + " = ?" ,
|
2015-04-21 20:04:00 +00:00
|
|
|
new String[] {String.valueOf(envelope.getType()),
|
|
|
|
envelope.getSource(),
|
|
|
|
String.valueOf(envelope.getSourceDevice()),
|
2015-05-29 23:23:47 +00:00
|
|
|
envelope.hasLegacyMessage() ? Base64.encodeBytes(envelope.getLegacyMessage()) : "",
|
|
|
|
envelope.hasContent() ? Base64.encodeBytes(envelope.getContent()) : "",
|
2015-04-21 20:04:00 +00:00
|
|
|
String.valueOf(envelope.getTimestamp())},
|
|
|
|
null, null, null);
|
|
|
|
|
|
|
|
if (cursor != null && cursor.moveToFirst()) {
|
|
|
|
return Optional.of(cursor.getLong(cursor.getColumnIndexOrThrow(ID)));
|
|
|
|
} else {
|
|
|
|
return Optional.absent();
|
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
if (cursor != null) cursor.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-09 23:46:03 +00:00
|
|
|
public static class Reader {
|
|
|
|
private final Cursor cursor;
|
|
|
|
|
|
|
|
public Reader(Cursor cursor) {
|
|
|
|
this.cursor = cursor;
|
|
|
|
}
|
|
|
|
|
2016-03-23 17:34:41 +00:00
|
|
|
public SignalServiceEnvelope getNext() {
|
2013-09-09 23:46:03 +00:00
|
|
|
try {
|
|
|
|
if (cursor == null || !cursor.moveToNext())
|
|
|
|
return null;
|
|
|
|
|
2015-05-29 23:23:47 +00:00
|
|
|
int type = cursor.getInt(cursor.getColumnIndexOrThrow(TYPE));
|
|
|
|
String source = cursor.getString(cursor.getColumnIndexOrThrow(SOURCE));
|
|
|
|
int deviceId = cursor.getInt(cursor.getColumnIndexOrThrow(DEVICE_ID));
|
|
|
|
String legacyMessage = cursor.getString(cursor.getColumnIndexOrThrow(LEGACY_MSG));
|
|
|
|
String content = cursor.getString(cursor.getColumnIndexOrThrow(CONTENT));
|
|
|
|
long timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(TIMESTAMP));
|
2013-09-09 23:46:03 +00:00
|
|
|
|
2016-03-23 17:34:41 +00:00
|
|
|
return new SignalServiceEnvelope(type, source, deviceId, "", timestamp,
|
|
|
|
legacyMessage != null ? Base64.decode(legacyMessage) : null,
|
|
|
|
content != null ? Base64.decode(content) : null);
|
2013-09-09 23:46:03 +00:00
|
|
|
} catch (IOException e) {
|
|
|
|
throw new AssertionError(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void close() {
|
|
|
|
this.cursor.close();
|
|
|
|
}
|
|
|
|
}
|
2013-09-09 01:19:05 +00:00
|
|
|
}
|