Store the server timestamp for a message.
This commit is contained in:
parent
00b6a222bd
commit
f12a9b9ac7
23 changed files with 315 additions and 214 deletions
|
@ -52,6 +52,7 @@ public class MediaDatabase extends Database {
|
|||
+ MmsDatabase.TABLE_NAME + "." + MmsDatabase.MESSAGE_BOX + ", "
|
||||
+ MmsDatabase.TABLE_NAME + "." + MmsDatabase.DATE_SENT + ", "
|
||||
+ MmsDatabase.TABLE_NAME + "." + MmsDatabase.DATE_RECEIVED + ", "
|
||||
+ MmsDatabase.TABLE_NAME + "." + MmsDatabase.DATE_SERVER + ", "
|
||||
+ MmsDatabase.TABLE_NAME + "." + MmsDatabase.THREAD_ID + ", "
|
||||
+ MmsDatabase.TABLE_NAME + "." + MmsDatabase.RECIPIENT_ID + ", "
|
||||
+ ThreadDatabase.TABLE_NAME + "." + ThreadDatabase.RECIPIENT_ID + " as " + THREAD_RECIPIENT_ID + " "
|
||||
|
|
|
@ -118,6 +118,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
THREAD_ID + " INTEGER, " +
|
||||
DATE_SENT + " INTEGER, " +
|
||||
DATE_RECEIVED + " INTEGER, " +
|
||||
DATE_SERVER + " INTEGER DEFAULT -1, " +
|
||||
MESSAGE_BOX + " INTEGER, " +
|
||||
READ + " INTEGER DEFAULT 0, " +
|
||||
"m_id" + " TEXT, " +
|
||||
|
@ -175,6 +176,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
"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_date_sent_index ON " + TABLE_NAME + " (" + DATE_SENT + ");",
|
||||
"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 + ");"
|
||||
};
|
||||
|
@ -183,6 +185,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
MmsDatabase.TABLE_NAME + "." + ID + " AS " + ID,
|
||||
THREAD_ID, DATE_SENT + " AS " + NORMALIZED_DATE_SENT,
|
||||
DATE_RECEIVED + " AS " + NORMALIZED_DATE_RECEIVED,
|
||||
DATE_SERVER,
|
||||
MESSAGE_BOX, READ,
|
||||
CONTENT_LOCATION, EXPIRY, MESSAGE_TYPE,
|
||||
MESSAGE_SIZE, STATUS, TRANSACTION_ID,
|
||||
|
@ -902,6 +905,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
ContentValues contentValues = new ContentValues();
|
||||
|
||||
contentValues.put(DATE_SENT, retrieved.getSentTimeMillis());
|
||||
contentValues.put(DATE_SERVER, retrieved.getServerTimeMillis());
|
||||
contentValues.put(RECIPIENT_ID, retrieved.getFrom().serialize());
|
||||
|
||||
contentValues.put(MESSAGE_BOX, mailbox);
|
||||
|
@ -991,7 +995,6 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
|
||||
Log.i(TAG, "Message received type: " + notification.getMessageType());
|
||||
|
||||
|
||||
contentBuilder.add(CONTENT_LOCATION, notification.getContentLocation());
|
||||
contentBuilder.add(DATE_SENT, System.currentTimeMillis());
|
||||
contentBuilder.add(EXPIRY, notification.getExpiry());
|
||||
|
@ -1474,13 +1477,20 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
public MessageRecord getCurrent() {
|
||||
SlideDeck slideDeck = new SlideDeck(context, message.getAttachments());
|
||||
|
||||
return new MediaMmsMessageRecord(id, message.getRecipient(), message.getRecipient(),
|
||||
1, System.currentTimeMillis(), System.currentTimeMillis(),
|
||||
0, threadId, message.getBody(),
|
||||
slideDeck, slideDeck.getSlides().size(),
|
||||
return new MediaMmsMessageRecord(id,
|
||||
message.getRecipient(),
|
||||
message.getRecipient(),
|
||||
1,
|
||||
System.currentTimeMillis(),
|
||||
System.currentTimeMillis(),
|
||||
-1,
|
||||
0,
|
||||
threadId, message.getBody(),
|
||||
slideDeck,
|
||||
slideDeck.getSlides().size(),
|
||||
message.isSecure() ? MmsSmsColumns.Types.getOutgoingEncryptedMessageType() : MmsSmsColumns.Types.getOutgoingSmsMessageType(),
|
||||
new LinkedList<IdentityKeyMismatch>(),
|
||||
new LinkedList<NetworkFailure>(),
|
||||
new LinkedList<>(),
|
||||
new LinkedList<>(),
|
||||
message.getSubscriptionId(),
|
||||
message.getExpiresIn(),
|
||||
System.currentTimeMillis(),
|
||||
|
@ -1493,7 +1503,10 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
message.getOutgoingQuote().isOriginalMissing(),
|
||||
new SlideDeck(context, message.getOutgoingQuote().getAttachments())) :
|
||||
null,
|
||||
message.getSharedContacts(), message.getLinkPreviews(), false, Collections.emptyList());
|
||||
message.getSharedContacts(),
|
||||
message.getLinkPreviews(),
|
||||
false,
|
||||
Collections.emptyList());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1565,22 +1578,23 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
}
|
||||
|
||||
private MediaMmsMessageRecord getMediaMmsMessageRecord(Cursor cursor) {
|
||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.ID ));
|
||||
long dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.NORMALIZED_DATE_SENT ));
|
||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.ID));
|
||||
long dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.NORMALIZED_DATE_SENT));
|
||||
long dateReceived = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.NORMALIZED_DATE_RECEIVED));
|
||||
long box = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.MESSAGE_BOX ));
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.THREAD_ID ));
|
||||
long recipientId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.RECIPIENT_ID ));
|
||||
int addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.ADDRESS_DEVICE_ID ));
|
||||
long dateServer = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.DATE_SERVER));
|
||||
long box = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.MESSAGE_BOX));
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.THREAD_ID));
|
||||
long recipientId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.RECIPIENT_ID));
|
||||
int addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.ADDRESS_DEVICE_ID));
|
||||
int deliveryReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.DELIVERY_RECEIPT_COUNT));
|
||||
int readReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.READ_RECEIPT_COUNT ));
|
||||
String body = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.BODY ));
|
||||
int partCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.PART_COUNT ));
|
||||
int readReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.READ_RECEIPT_COUNT));
|
||||
String body = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.BODY));
|
||||
int partCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.PART_COUNT));
|
||||
String mismatchDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.MISMATCHED_IDENTITIES));
|
||||
String networkDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.NETWORK_FAILURE ));
|
||||
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.SUBSCRIPTION_ID ));
|
||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.EXPIRES_IN ));
|
||||
long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.EXPIRE_STARTED ));
|
||||
String networkDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.NETWORK_FAILURE));
|
||||
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.SUBSCRIPTION_ID));
|
||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.EXPIRES_IN));
|
||||
long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.EXPIRE_STARTED));
|
||||
boolean unidentified = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.UNIDENTIFIED)) == 1;
|
||||
boolean isViewOnce = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.VIEW_ONCE)) == 1;
|
||||
List<ReactionRecord> reactions = parseReactions(cursor);
|
||||
|
@ -1601,7 +1615,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
Quote quote = getQuote(cursor);
|
||||
|
||||
return new MediaMmsMessageRecord(id, recipient, recipient,
|
||||
addressDeviceId, dateSent, dateReceived, deliveryReceiptCount,
|
||||
addressDeviceId, dateSent, dateReceived, dateServer, deliveryReceiptCount,
|
||||
threadId, body, slideDeck, partCount, box, mismatches,
|
||||
networkFailures, subscriptionId, expiresIn, expireStarted,
|
||||
isViewOnce, readReceiptCount, quote, contacts, previews, unidentified, reactions);
|
||||
|
|
|
@ -6,6 +6,7 @@ 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 DATE_SERVER = "date_server";
|
||||
public static final String THREAD_ID = "thread_id";
|
||||
public static final String READ = "read";
|
||||
public static final String BODY = "body";
|
||||
|
|
|
@ -44,19 +44,27 @@ public class MmsSmsDatabase extends Database {
|
|||
public static final String MMS_TRANSPORT = "mms";
|
||||
public static final String SMS_TRANSPORT = "sms";
|
||||
|
||||
private static final String[] PROJECTION = {MmsSmsColumns.ID, MmsSmsColumns.UNIQUE_ROW_ID,
|
||||
SmsDatabase.BODY, SmsDatabase.TYPE,
|
||||
private static final String[] PROJECTION = {MmsSmsColumns.ID,
|
||||
MmsSmsColumns.UNIQUE_ROW_ID,
|
||||
SmsDatabase.BODY,
|
||||
SmsDatabase.TYPE,
|
||||
MmsSmsColumns.THREAD_ID,
|
||||
SmsDatabase.RECIPIENT_ID, SmsDatabase.ADDRESS_DEVICE_ID, SmsDatabase.SUBJECT,
|
||||
SmsDatabase.RECIPIENT_ID,
|
||||
SmsDatabase.ADDRESS_DEVICE_ID,
|
||||
SmsDatabase.SUBJECT,
|
||||
MmsSmsColumns.NORMALIZED_DATE_SENT,
|
||||
MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
|
||||
MmsDatabase.MESSAGE_TYPE, MmsDatabase.MESSAGE_BOX,
|
||||
MmsSmsColumns.DATE_SERVER,
|
||||
MmsDatabase.MESSAGE_TYPE,
|
||||
MmsDatabase.MESSAGE_BOX,
|
||||
SmsDatabase.STATUS,
|
||||
MmsSmsColumns.UNIDENTIFIED,
|
||||
MmsSmsColumns.REACTIONS,
|
||||
MmsDatabase.PART_COUNT,
|
||||
MmsDatabase.CONTENT_LOCATION, MmsDatabase.TRANSACTION_ID,
|
||||
MmsDatabase.MESSAGE_SIZE, MmsDatabase.EXPIRY,
|
||||
MmsDatabase.CONTENT_LOCATION,
|
||||
MmsDatabase.TRANSACTION_ID,
|
||||
MmsDatabase.MESSAGE_SIZE,
|
||||
MmsDatabase.EXPIRY,
|
||||
MmsDatabase.STATUS,
|
||||
MmsSmsColumns.DELIVERY_RECEIPT_COUNT,
|
||||
MmsSmsColumns.READ_RECEIPT_COUNT,
|
||||
|
@ -386,7 +394,8 @@ public class MmsSmsDatabase extends Database {
|
|||
MmsDatabase.VIEW_ONCE,
|
||||
MmsDatabase.REACTIONS,
|
||||
MmsSmsColumns.REACTIONS_UNREAD,
|
||||
MmsSmsColumns.REACTIONS_LAST_SEEN};
|
||||
MmsSmsColumns.REACTIONS_LAST_SEEN,
|
||||
MmsSmsColumns.DATE_SERVER };
|
||||
|
||||
String[] smsProjection = {SmsDatabase.DATE_SENT + " AS " + MmsSmsColumns.NORMALIZED_DATE_SENT,
|
||||
SmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
|
||||
|
@ -416,7 +425,8 @@ public class MmsSmsDatabase extends Database {
|
|||
MmsDatabase.VIEW_ONCE,
|
||||
MmsDatabase.REACTIONS,
|
||||
MmsSmsColumns.REACTIONS_UNREAD,
|
||||
MmsSmsColumns.REACTIONS_LAST_SEEN};
|
||||
MmsSmsColumns.REACTIONS_LAST_SEEN,
|
||||
MmsSmsColumns.DATE_SERVER };
|
||||
|
||||
SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder();
|
||||
SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder();
|
||||
|
@ -447,6 +457,7 @@ public class MmsSmsDatabase extends Database {
|
|||
mmsColumnsPresent.add(MmsDatabase.MESSAGE_BOX);
|
||||
mmsColumnsPresent.add(MmsDatabase.DATE_SENT);
|
||||
mmsColumnsPresent.add(MmsDatabase.DATE_RECEIVED);
|
||||
mmsColumnsPresent.add(MmsDatabase.DATE_SERVER);
|
||||
mmsColumnsPresent.add(MmsDatabase.PART_COUNT);
|
||||
mmsColumnsPresent.add(MmsDatabase.CONTENT_LOCATION);
|
||||
mmsColumnsPresent.add(MmsDatabase.TRANSACTION_ID);
|
||||
|
@ -486,6 +497,7 @@ public class MmsSmsDatabase extends Database {
|
|||
smsColumnsPresent.add(SmsDatabase.SUBJECT);
|
||||
smsColumnsPresent.add(SmsDatabase.DATE_SENT);
|
||||
smsColumnsPresent.add(SmsDatabase.DATE_RECEIVED);
|
||||
smsColumnsPresent.add(SmsDatabase.DATE_SERVER);
|
||||
smsColumnsPresent.add(SmsDatabase.STATUS);
|
||||
smsColumnsPresent.add(SmsDatabase.UNIDENTIFIED);
|
||||
smsColumnsPresent.add(SmsDatabase.REACTIONS);
|
||||
|
|
|
@ -84,6 +84,7 @@ public class SmsDatabase extends MessagingDatabase {
|
|||
PERSON + " INTEGER, " +
|
||||
DATE_RECEIVED + " INTEGER, " +
|
||||
DATE_SENT + " INTEGER, " +
|
||||
DATE_SERVER + " INTEGER DEFAULT -1, " +
|
||||
PROTOCOL + " INTEGER, " +
|
||||
READ + " INTEGER DEFAULT 0, " +
|
||||
STATUS + " INTEGER DEFAULT -1," +
|
||||
|
@ -110,6 +111,7 @@ public class SmsDatabase extends MessagingDatabase {
|
|||
"CREATE INDEX IF NOT EXISTS sms_read_and_notified_and_thread_id_index ON " + TABLE_NAME + "(" + READ + "," + NOTIFIED + "," + THREAD_ID + ");",
|
||||
"CREATE INDEX IF NOT EXISTS sms_type_index ON " + TABLE_NAME + " (" + TYPE + ");",
|
||||
"CREATE INDEX IF NOT EXISTS sms_date_sent_index ON " + TABLE_NAME + " (" + DATE_SENT + ");",
|
||||
"CREATE INDEX IF NOT EXISTS sms_date_server_index ON " + TABLE_NAME + " (" + DATE_SERVER + ");",
|
||||
"CREATE INDEX IF NOT EXISTS sms_thread_date_index ON " + TABLE_NAME + " (" + THREAD_ID + ", " + DATE_RECEIVED + ");",
|
||||
"CREATE INDEX IF NOT EXISTS sms_reactions_unread_index ON " + TABLE_NAME + " (" + REACTIONS_UNREAD + ");"
|
||||
};
|
||||
|
@ -118,6 +120,7 @@ public class SmsDatabase extends MessagingDatabase {
|
|||
ID, THREAD_ID, RECIPIENT_ID, ADDRESS_DEVICE_ID, PERSON,
|
||||
DATE_RECEIVED + " AS " + NORMALIZED_DATE_RECEIVED,
|
||||
DATE_SENT + " AS " + NORMALIZED_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,
|
||||
|
@ -534,36 +537,6 @@ public class SmsDatabase extends MessagingDatabase {
|
|||
return new Pair<>(messageId, threadId);
|
||||
}
|
||||
|
||||
public Pair<Long, Long> copyMessageInbox(long messageId) {
|
||||
try {
|
||||
SmsMessageRecord record = getMessage(messageId);
|
||||
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(TYPE, (record.getType() & ~Types.BASE_TYPE_MASK) | Types.BASE_INBOX_TYPE);
|
||||
contentValues.put(RECIPIENT_ID, record.getIndividualRecipient().getId().serialize());
|
||||
contentValues.put(ADDRESS_DEVICE_ID, record.getRecipientDeviceId());
|
||||
contentValues.put(DATE_RECEIVED, System.currentTimeMillis());
|
||||
contentValues.put(DATE_SENT, record.getDateSent());
|
||||
contentValues.put(PROTOCOL, 31337);
|
||||
contentValues.put(READ, 0);
|
||||
contentValues.put(BODY, record.getBody());
|
||||
contentValues.put(THREAD_ID, record.getThreadId());
|
||||
contentValues.put(EXPIRES_IN, record.getExpiresIn());
|
||||
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
long newMessageId = db.insert(TABLE_NAME, null, contentValues);
|
||||
|
||||
DatabaseFactory.getThreadDatabase(context).update(record.getThreadId(), true);
|
||||
notifyConversationListeners(record.getThreadId());
|
||||
|
||||
ApplicationDependencies.getJobManager().add(new TrimThreadJob(record.getThreadId()));
|
||||
|
||||
return new Pair<>(newMessageId, record.getThreadId());
|
||||
} catch (NoSuchMessageException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasReceivedAnyCallsSince(long threadId, long timestamp) {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
String[] projection = new String[]{SmsDatabase.TYPE};
|
||||
|
@ -665,6 +638,7 @@ public class SmsDatabase extends MessagingDatabase {
|
|||
values.put(ADDRESS_DEVICE_ID, message.getSenderDeviceId());
|
||||
values.put(DATE_RECEIVED, System.currentTimeMillis());
|
||||
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());
|
||||
|
@ -908,7 +882,7 @@ public class SmsDatabase extends MessagingDatabase {
|
|||
return new OutgoingMessageReader(message, threadId);
|
||||
}
|
||||
|
||||
public class OutgoingMessageReader {
|
||||
public static class OutgoingMessageReader {
|
||||
|
||||
private final OutgoingTextMessage message;
|
||||
private final long id;
|
||||
|
@ -921,13 +895,25 @@ public class SmsDatabase extends MessagingDatabase {
|
|||
}
|
||||
|
||||
public MessageRecord getCurrent() {
|
||||
return new SmsMessageRecord(id, message.getMessageBody(),
|
||||
message.getRecipient(), message.getRecipient(),
|
||||
1, System.currentTimeMillis(), System.currentTimeMillis(),
|
||||
0, message.isSecureMessage() ? MmsSmsColumns.Types.getOutgoingEncryptedMessageType() : MmsSmsColumns.Types.getOutgoingSmsMessageType(),
|
||||
threadId, 0, new LinkedList<IdentityKeyMismatch>(),
|
||||
message.getSubscriptionId(), message.getExpiresIn(),
|
||||
System.currentTimeMillis(), 0, false, Collections.emptyList());
|
||||
return new SmsMessageRecord(id,
|
||||
message.getMessageBody(),
|
||||
message.getRecipient(),
|
||||
message.getRecipient(),
|
||||
1,
|
||||
System.currentTimeMillis(),
|
||||
System.currentTimeMillis(),
|
||||
-1,
|
||||
0,
|
||||
message.isSecureMessage() ? MmsSmsColumns.Types.getOutgoingEncryptedMessageType() : MmsSmsColumns.Types.getOutgoingSmsMessageType(),
|
||||
threadId,
|
||||
0,
|
||||
new LinkedList<>(),
|
||||
message.getSubscriptionId(),
|
||||
message.getExpiresIn(),
|
||||
System.currentTimeMillis(),
|
||||
0,
|
||||
false,
|
||||
Collections.emptyList());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -952,21 +938,22 @@ public class SmsDatabase extends MessagingDatabase {
|
|||
}
|
||||
|
||||
public SmsMessageRecord getCurrent() {
|
||||
long messageId = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.ID ));
|
||||
long recipientId = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.RECIPIENT_ID ));
|
||||
int addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.ADDRESS_DEVICE_ID ));
|
||||
long type = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.TYPE ));
|
||||
long messageId = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.ID));
|
||||
long recipientId = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.RECIPIENT_ID));
|
||||
int addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.ADDRESS_DEVICE_ID));
|
||||
long type = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.TYPE));
|
||||
long dateReceived = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.NORMALIZED_DATE_RECEIVED));
|
||||
long dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.NORMALIZED_DATE_SENT ));
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.THREAD_ID ));
|
||||
int status = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.STATUS ));
|
||||
long dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.NORMALIZED_DATE_SENT));
|
||||
long dateServer = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.DATE_SERVER));
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.THREAD_ID));
|
||||
int status = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.STATUS));
|
||||
int deliveryReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.DELIVERY_RECEIPT_COUNT));
|
||||
int readReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.READ_RECEIPT_COUNT ));
|
||||
int readReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.READ_RECEIPT_COUNT));
|
||||
String mismatchDocument = cursor.getString(cursor.getColumnIndexOrThrow(SmsDatabase.MISMATCHED_IDENTITIES));
|
||||
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.SUBSCRIPTION_ID ));
|
||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.EXPIRES_IN ));
|
||||
long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.EXPIRE_STARTED ));
|
||||
String body = cursor.getString(cursor.getColumnIndexOrThrow(SmsDatabase.BODY ));
|
||||
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.SUBSCRIPTION_ID));
|
||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.EXPIRES_IN));
|
||||
long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.EXPIRE_STARTED));
|
||||
String body = cursor.getString(cursor.getColumnIndexOrThrow(SmsDatabase.BODY));
|
||||
boolean unidentified = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.UNIDENTIFIED)) == 1;
|
||||
List<ReactionRecord> reactions = parseReactions(cursor);
|
||||
|
||||
|
@ -980,7 +967,7 @@ public class SmsDatabase extends MessagingDatabase {
|
|||
return new SmsMessageRecord(messageId, body, recipient,
|
||||
recipient,
|
||||
addressDeviceId,
|
||||
dateSent, dateReceived, deliveryReceiptCount, type,
|
||||
dateSent, dateReceived, dateServer, deliveryReceiptCount, type,
|
||||
threadId, status, mismatches, subscriptionId,
|
||||
expiresIn, expireStarted,
|
||||
readReceiptCount, unidentified, reactions);
|
||||
|
|
|
@ -128,8 +128,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||
private static final int ATTACHMENT_UPLOAD_TIMESTAMP = 56;
|
||||
private static final int ATTACHMENT_CDN_NUMBER = 57;
|
||||
private static final int JOB_INPUT_DATA = 58;
|
||||
private static final int SERVER_TIMESTAMP = 59;
|
||||
|
||||
private static final int DATABASE_VERSION = 58;
|
||||
private static final int DATABASE_VERSION = 59;
|
||||
private static final String DATABASE_NAME = "signal.db";
|
||||
|
||||
private final Context context;
|
||||
|
@ -873,6 +874,14 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||
db.execSQL("ALTER TABLE job_spec ADD COLUMN serialized_input_data TEXT DEFAULT NULL");
|
||||
}
|
||||
|
||||
if (oldVersion < SERVER_TIMESTAMP) {
|
||||
db.execSQL("ALTER TABLE sms ADD COLUMN date_server INTEGER DEFAULT -1");
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS sms_date_server_index ON sms (date_server)");
|
||||
|
||||
db.execSQL("ALTER TABLE mms ADD COLUMN date_server INTEGER DEFAULT -1");
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS mms_date_server_index ON mms (date_server)");
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
|
|
|
@ -46,22 +46,34 @@ public class MediaMmsMessageRecord extends MmsMessageRecord {
|
|||
|
||||
private final int partCount;
|
||||
|
||||
public MediaMmsMessageRecord(long id, Recipient conversationRecipient,
|
||||
Recipient individualRecipient, int recipientDeviceId,
|
||||
long dateSent, long dateReceived, int deliveryReceiptCount,
|
||||
long threadId, String body,
|
||||
public MediaMmsMessageRecord(long id,
|
||||
Recipient conversationRecipient,
|
||||
Recipient individualRecipient,
|
||||
int recipientDeviceId,
|
||||
long dateSent,
|
||||
long dateReceived,
|
||||
long dateServer,
|
||||
int deliveryReceiptCount,
|
||||
long threadId,
|
||||
String body,
|
||||
@NonNull SlideDeck slideDeck,
|
||||
int partCount, long mailbox,
|
||||
int partCount,
|
||||
long mailbox,
|
||||
List<IdentityKeyMismatch> mismatches,
|
||||
List<NetworkFailure> failures, int subscriptionId,
|
||||
long expiresIn, long expireStarted,
|
||||
boolean viewOnce, int readReceiptCount,
|
||||
@Nullable Quote quote, @NonNull List<Contact> contacts,
|
||||
@NonNull List<LinkPreview> linkPreviews, boolean unidentified,
|
||||
List<NetworkFailure> failures,
|
||||
int subscriptionId,
|
||||
long expiresIn,
|
||||
long expireStarted,
|
||||
boolean viewOnce,
|
||||
int readReceiptCount,
|
||||
@Nullable Quote quote,
|
||||
@NonNull List<Contact> contacts,
|
||||
@NonNull List<LinkPreview> linkPreviews,
|
||||
boolean unidentified,
|
||||
@NonNull List<ReactionRecord> reactions)
|
||||
{
|
||||
super(id, body, conversationRecipient, individualRecipient, recipientDeviceId, dateSent,
|
||||
dateReceived, threadId, Status.STATUS_NONE, deliveryReceiptCount, mailbox, mismatches, failures,
|
||||
dateReceived, dateServer, threadId, Status.STATUS_NONE, deliveryReceiptCount, mailbox, mismatches, failures,
|
||||
subscriptionId, expiresIn, expireStarted, viewOnce, slideDeck,
|
||||
readReceiptCount, quote, contacts, linkPreviews, unidentified, reactions);
|
||||
this.partCount = partCount;
|
||||
|
|
|
@ -54,10 +54,11 @@ public abstract class MessageRecord extends DisplayRecord {
|
|||
private final long expireStarted;
|
||||
private final boolean unidentified;
|
||||
private final List<ReactionRecord> reactions;
|
||||
private final long serverTimestamp;
|
||||
|
||||
MessageRecord(long id, String body, Recipient conversationRecipient,
|
||||
Recipient individualRecipient, int recipientDeviceId,
|
||||
long dateSent, long dateReceived, long threadId,
|
||||
long dateSent, long dateReceived, long dateServer, long threadId,
|
||||
int deliveryStatus, int deliveryReceiptCount, long type,
|
||||
List<IdentityKeyMismatch> mismatches,
|
||||
List<NetworkFailure> networkFailures,
|
||||
|
@ -77,6 +78,7 @@ public abstract class MessageRecord extends DisplayRecord {
|
|||
this.expireStarted = expireStarted;
|
||||
this.unidentified = unidentified;
|
||||
this.reactions = reactions;
|
||||
this.serverTimestamp = dateServer;
|
||||
}
|
||||
|
||||
public abstract boolean isMms();
|
||||
|
@ -145,6 +147,10 @@ public abstract class MessageRecord extends DisplayRecord {
|
|||
return getDateReceived();
|
||||
}
|
||||
|
||||
public long getServerTimestamp() {
|
||||
return serverTimestamp;
|
||||
}
|
||||
|
||||
public boolean isForcedSms() {
|
||||
return SmsDatabase.Types.isForcedSms(type);
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ public abstract class MmsMessageRecord extends MessageRecord {
|
|||
|
||||
MmsMessageRecord(long id, String body, Recipient conversationRecipient,
|
||||
Recipient individualRecipient, int recipientDeviceId, long dateSent,
|
||||
long dateReceived, long threadId, int deliveryStatus, int deliveryReceiptCount,
|
||||
long dateReceived, long dateServer, long threadId, int deliveryStatus, int deliveryReceiptCount,
|
||||
long type, List<IdentityKeyMismatch> mismatches,
|
||||
List<NetworkFailure> networkFailures, int subscriptionId, long expiresIn,
|
||||
long expireStarted, boolean viewOnce,
|
||||
|
@ -35,7 +35,7 @@ public abstract class MmsMessageRecord extends MessageRecord {
|
|||
@NonNull List<LinkPreview> linkPreviews, boolean unidentified,
|
||||
@NonNull List<ReactionRecord> reactions)
|
||||
{
|
||||
super(id, body, conversationRecipient, individualRecipient, recipientDeviceId, dateSent, dateReceived, threadId, deliveryStatus, deliveryReceiptCount, type, mismatches, networkFailures, subscriptionId, expiresIn, expireStarted, readReceiptCount, unidentified, reactions);
|
||||
super(id, body, conversationRecipient, individualRecipient, recipientDeviceId, dateSent, dateReceived, dateServer, threadId, deliveryStatus, deliveryReceiptCount, type, mismatches, networkFailures, subscriptionId, expiresIn, expireStarted, readReceiptCount, unidentified, reactions);
|
||||
|
||||
this.slideDeck = slideDeck;
|
||||
this.quote = quote;
|
||||
|
|
|
@ -55,8 +55,8 @@ public class NotificationMmsMessageRecord extends MmsMessageRecord {
|
|||
int subscriptionId, SlideDeck slideDeck, int readReceiptCount)
|
||||
{
|
||||
super(id, "", conversationRecipient, individualRecipient, recipientDeviceId,
|
||||
dateSent, dateReceived, threadId, Status.STATUS_NONE, deliveryReceiptCount, mailbox,
|
||||
new LinkedList<IdentityKeyMismatch>(), new LinkedList<NetworkFailure>(), subscriptionId,
|
||||
dateSent, dateReceived, -1, threadId, Status.STATUS_NONE, deliveryReceiptCount, mailbox,
|
||||
new LinkedList<>(), new LinkedList<>(), subscriptionId,
|
||||
0, 0, false, slideDeck, readReceiptCount, null, Collections.emptyList(), Collections.emptyList(), false,
|
||||
Collections.emptyList());
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ public class SmsMessageRecord extends MessageRecord {
|
|||
String body, Recipient recipient,
|
||||
Recipient individualRecipient,
|
||||
int recipientDeviceId,
|
||||
long dateSent, long dateReceived,
|
||||
long dateSent, long dateReceived, long dateServer,
|
||||
int deliveryReceiptCount,
|
||||
long type, long threadId,
|
||||
int status, List<IdentityKeyMismatch> mismatches,
|
||||
|
@ -52,7 +52,7 @@ public class SmsMessageRecord extends MessageRecord {
|
|||
@NonNull List<ReactionRecord> reactions)
|
||||
{
|
||||
super(id, body, recipient, individualRecipient, recipientDeviceId,
|
||||
dateSent, dateReceived, threadId, status, deliveryReceiptCount, type,
|
||||
dateSent, dateReceived, dateServer, threadId, status, deliveryReceiptCount, type,
|
||||
mismatches, new LinkedList<>(), subscriptionId,
|
||||
expiresIn, expireStarted, readReceiptCount, unidentified, reactions);
|
||||
}
|
||||
|
|
|
@ -246,7 +246,7 @@ public final class GroupV1MessageProcessor {
|
|||
} else {
|
||||
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
|
||||
String body = Base64.encodeBytes(storage.toByteArray());
|
||||
IncomingTextMessage incoming = new IncomingTextMessage(Recipient.externalPush(context, content.getSender()).getId(), content.getSenderDevice(), content.getTimestamp(), body, Optional.of(GroupId.v1(group.getGroupId())), 0, content.isNeedsReceipt());
|
||||
IncomingTextMessage incoming = new IncomingTextMessage(Recipient.externalPush(context, content.getSender()).getId(), content.getSenderDevice(), content.getTimestamp(), content.getServerTimestamp(), body, Optional.of(GroupId.v1(group.getGroupId())), 0, content.isNeedsReceipt());
|
||||
IncomingGroupMessage groupMessage = new IncomingGroupMessage(incoming, storage, body);
|
||||
|
||||
Optional<InsertResult> insertResult = smsDatabase.insertMessageInbox(groupMessage);
|
||||
|
|
|
@ -235,7 +235,7 @@ public class MmsDownloadJob extends BaseJob {
|
|||
group = Optional.of(DatabaseFactory.getGroupDatabase(context).getOrCreateMmsGroupForMembers(recipients));
|
||||
}
|
||||
|
||||
IncomingMediaMessage message = new IncomingMediaMessage(from, group, body, retrieved.getDate() * 1000L, attachments, subscriptionId, 0, false, false, false);
|
||||
IncomingMediaMessage message = new IncomingMediaMessage(from, group, body, retrieved.getDate() * 1000L, -1, attachments, subscriptionId, 0, false, false, false);
|
||||
Optional<InsertResult> insertResult = database.insertMessageInbox(message, contentLocation, threadId);
|
||||
|
||||
if (insertResult.isPresent()) {
|
||||
|
|
|
@ -482,6 +482,7 @@ public final class PushProcessMessageJob extends BaseJob {
|
|||
IncomingTextMessage incomingTextMessage = new IncomingTextMessage(Recipient.externalPush(context, content.getSender()).getId(),
|
||||
content.getSenderDevice(),
|
||||
content.getTimestamp(),
|
||||
content.getServerTimestamp(),
|
||||
"", Optional.absent(), 0,
|
||||
content.isNeedsReceipt());
|
||||
|
||||
|
@ -572,8 +573,11 @@ public final class PushProcessMessageJob extends BaseJob {
|
|||
Recipient sender = Recipient.externalPush(context, content.getSender());
|
||||
Recipient recipient = getMessageDestination(content, message);
|
||||
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(sender.getId(),
|
||||
message.getTimestamp(), -1,
|
||||
message.getExpiresInSeconds() * 1000L, true,
|
||||
message.getTimestamp(),
|
||||
content.getServerTimestamp(),
|
||||
-1,
|
||||
message.getExpiresInSeconds() * 1000L,
|
||||
true,
|
||||
false,
|
||||
content.isNeedsReceipt(),
|
||||
Optional.absent(),
|
||||
|
@ -859,8 +863,11 @@ public final class PushProcessMessageJob extends BaseJob {
|
|||
Optional<List<LinkPreview>> linkPreviews = getLinkPreviews(message.getPreviews(), message.getBody().or(""));
|
||||
Optional<Attachment> sticker = getStickerAttachment(message.getSticker());
|
||||
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(Recipient.externalPush(context, content.getSender()).getId(),
|
||||
message.getTimestamp(), -1,
|
||||
message.getExpiresInSeconds() * 1000L, false,
|
||||
message.getTimestamp(),
|
||||
content.getServerTimestamp(),
|
||||
-1,
|
||||
message.getExpiresInSeconds() * 1000L,
|
||||
false,
|
||||
message.isViewOnce(),
|
||||
content.isNeedsReceipt(),
|
||||
message.getBody(),
|
||||
|
@ -1071,7 +1078,9 @@ public final class PushProcessMessageJob extends BaseJob {
|
|||
|
||||
IncomingTextMessage textMessage = new IncomingTextMessage(Recipient.externalPush(context, content.getSender()).getId(),
|
||||
content.getSenderDevice(),
|
||||
message.getTimestamp(), body,
|
||||
message.getTimestamp(),
|
||||
content.getServerTimestamp(),
|
||||
body,
|
||||
groupId,
|
||||
message.getExpiresInSeconds() * 1000L,
|
||||
content.isNeedsReceipt());
|
||||
|
@ -1498,7 +1507,7 @@ public final class PushProcessMessageJob extends BaseJob {
|
|||
private Optional<InsertResult> insertPlaceholder(@NonNull String sender, int senderDevice, long timestamp, Optional<GroupId> groupId) {
|
||||
SmsDatabase database = DatabaseFactory.getSmsDatabase(context);
|
||||
IncomingTextMessage textMessage = new IncomingTextMessage(Recipient.external(context, sender).getId(),
|
||||
senderDevice, timestamp, "",
|
||||
senderDevice, timestamp, -1, "",
|
||||
groupId, 0, false);
|
||||
|
||||
textMessage = new IncomingEncryptedMessage(textMessage, "");
|
||||
|
|
|
@ -24,6 +24,7 @@ public class IncomingMediaMessage {
|
|||
private final String body;
|
||||
private final boolean push;
|
||||
private final long sentTimeMillis;
|
||||
private final long serverTimeMillis;
|
||||
private final int subscriptionId;
|
||||
private final long expiresIn;
|
||||
private final boolean expirationUpdate;
|
||||
|
@ -39,6 +40,7 @@ public class IncomingMediaMessage {
|
|||
Optional<GroupId> groupId,
|
||||
String body,
|
||||
long sentTimeMillis,
|
||||
long serverTimeMillis,
|
||||
List<Attachment> attachments,
|
||||
int subscriptionId,
|
||||
long expiresIn,
|
||||
|
@ -49,6 +51,7 @@ public class IncomingMediaMessage {
|
|||
this.from = from;
|
||||
this.groupId = groupId.orNull();
|
||||
this.sentTimeMillis = sentTimeMillis;
|
||||
this.serverTimeMillis = serverTimeMillis;
|
||||
this.body = body;
|
||||
this.push = false;
|
||||
this.subscriptionId = subscriptionId;
|
||||
|
@ -63,6 +66,7 @@ public class IncomingMediaMessage {
|
|||
|
||||
public IncomingMediaMessage(@NonNull RecipientId from,
|
||||
long sentTimeMillis,
|
||||
long serverTimeMillis,
|
||||
int subscriptionId,
|
||||
long expiresIn,
|
||||
boolean expirationUpdate,
|
||||
|
@ -79,6 +83,7 @@ public class IncomingMediaMessage {
|
|||
this.push = true;
|
||||
this.from = from;
|
||||
this.sentTimeMillis = sentTimeMillis;
|
||||
this.serverTimeMillis = serverTimeMillis;
|
||||
this.body = body.orNull();
|
||||
this.subscriptionId = subscriptionId;
|
||||
this.expiresIn = expiresIn;
|
||||
|
@ -131,6 +136,10 @@ public class IncomingMediaMessage {
|
|||
return sentTimeMillis;
|
||||
}
|
||||
|
||||
public long getServerTimeMillis() {
|
||||
return serverTimeMillis;
|
||||
}
|
||||
|
||||
public long getExpiresIn() {
|
||||
return expiresIn;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import org.whispersystems.libsignal.util.guava.Optional;
|
|||
public class IncomingJoinedMessage extends IncomingTextMessage {
|
||||
|
||||
public IncomingJoinedMessage(RecipientId sender) {
|
||||
super(sender, 1, System.currentTimeMillis(), null, Optional.absent(), 0, false);
|
||||
super(sender, 1, System.currentTimeMillis(), -1, null, Optional.absent(), 0, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -37,6 +37,7 @@ public class IncomingTextMessage implements Parcelable {
|
|||
private final boolean replyPathPresent;
|
||||
private final String pseudoSubject;
|
||||
private final long sentTimestampMillis;
|
||||
private final long serverTimestampMillis;
|
||||
@Nullable private final GroupId groupId;
|
||||
private final boolean push;
|
||||
private final int subscriptionId;
|
||||
|
@ -44,70 +45,79 @@ public class IncomingTextMessage implements Parcelable {
|
|||
private final boolean unidentified;
|
||||
|
||||
public IncomingTextMessage(@NonNull RecipientId sender, @NonNull SmsMessage message, int subscriptionId) {
|
||||
this.message = message.getDisplayMessageBody();
|
||||
this.sender = sender;
|
||||
this.senderDeviceId = SignalServiceAddress.DEFAULT_DEVICE_ID;
|
||||
this.protocol = message.getProtocolIdentifier();
|
||||
this.serviceCenterAddress = message.getServiceCenterAddress();
|
||||
this.replyPathPresent = message.isReplyPathPresent();
|
||||
this.pseudoSubject = message.getPseudoSubject();
|
||||
this.sentTimestampMillis = message.getTimestampMillis();
|
||||
this.subscriptionId = subscriptionId;
|
||||
this.expiresInMillis = 0;
|
||||
this.groupId = null;
|
||||
this.push = false;
|
||||
this.unidentified = false;
|
||||
this.message = message.getDisplayMessageBody();
|
||||
this.sender = sender;
|
||||
this.senderDeviceId = SignalServiceAddress.DEFAULT_DEVICE_ID;
|
||||
this.protocol = message.getProtocolIdentifier();
|
||||
this.serviceCenterAddress = message.getServiceCenterAddress();
|
||||
this.replyPathPresent = message.isReplyPathPresent();
|
||||
this.pseudoSubject = message.getPseudoSubject();
|
||||
this.sentTimestampMillis = message.getTimestampMillis();
|
||||
this.serverTimestampMillis = -1;
|
||||
this.subscriptionId = subscriptionId;
|
||||
this.expiresInMillis = 0;
|
||||
this.groupId = null;
|
||||
this.push = false;
|
||||
this.unidentified = false;
|
||||
}
|
||||
|
||||
public IncomingTextMessage(@NonNull RecipientId sender, int senderDeviceId, long sentTimestampMillis,
|
||||
String encodedBody, Optional<GroupId> groupId,
|
||||
long expiresInMillis, boolean unidentified)
|
||||
public IncomingTextMessage(@NonNull RecipientId sender,
|
||||
int senderDeviceId,
|
||||
long sentTimestampMillis,
|
||||
long serverTimestampMillis,
|
||||
String encodedBody,
|
||||
Optional<GroupId> groupId,
|
||||
long expiresInMillis,
|
||||
boolean unidentified)
|
||||
{
|
||||
this.message = encodedBody;
|
||||
this.sender = sender;
|
||||
this.senderDeviceId = senderDeviceId;
|
||||
this.protocol = 31337;
|
||||
this.serviceCenterAddress = "GCM";
|
||||
this.replyPathPresent = true;
|
||||
this.pseudoSubject = "";
|
||||
this.sentTimestampMillis = sentTimestampMillis;
|
||||
this.push = true;
|
||||
this.subscriptionId = -1;
|
||||
this.expiresInMillis = expiresInMillis;
|
||||
this.unidentified = unidentified;
|
||||
this.groupId = groupId.orNull();
|
||||
this.message = encodedBody;
|
||||
this.sender = sender;
|
||||
this.senderDeviceId = senderDeviceId;
|
||||
this.protocol = 31337;
|
||||
this.serviceCenterAddress = "GCM";
|
||||
this.replyPathPresent = true;
|
||||
this.pseudoSubject = "";
|
||||
this.sentTimestampMillis = sentTimestampMillis;
|
||||
this.serverTimestampMillis = serverTimestampMillis;
|
||||
this.push = true;
|
||||
this.subscriptionId = -1;
|
||||
this.expiresInMillis = expiresInMillis;
|
||||
this.unidentified = unidentified;
|
||||
this.groupId = groupId.orNull();
|
||||
}
|
||||
|
||||
public IncomingTextMessage(Parcel in) {
|
||||
this.message = in.readString();
|
||||
this.sender = in.readParcelable(IncomingTextMessage.class.getClassLoader());
|
||||
this.senderDeviceId = in.readInt();
|
||||
this.protocol = in.readInt();
|
||||
this.serviceCenterAddress = in.readString();
|
||||
this.replyPathPresent = (in.readInt() == 1);
|
||||
this.pseudoSubject = in.readString();
|
||||
this.sentTimestampMillis = in.readLong();
|
||||
this.groupId = GroupId.parseNullable(in.readString());
|
||||
this.push = (in.readInt() == 1);
|
||||
this.subscriptionId = in.readInt();
|
||||
this.expiresInMillis = in.readLong();
|
||||
this.unidentified = in.readInt() == 1;
|
||||
this.message = in.readString();
|
||||
this.sender = in.readParcelable(IncomingTextMessage.class.getClassLoader());
|
||||
this.senderDeviceId = in.readInt();
|
||||
this.protocol = in.readInt();
|
||||
this.serviceCenterAddress = in.readString();
|
||||
this.replyPathPresent = (in.readInt() == 1);
|
||||
this.pseudoSubject = in.readString();
|
||||
this.sentTimestampMillis = in.readLong();
|
||||
this.serverTimestampMillis = in.readLong();
|
||||
this.groupId = GroupId.parseNullable(in.readString());
|
||||
this.push = (in.readInt() == 1);
|
||||
this.subscriptionId = in.readInt();
|
||||
this.expiresInMillis = in.readLong();
|
||||
this.unidentified = in.readInt() == 1;
|
||||
}
|
||||
|
||||
public IncomingTextMessage(IncomingTextMessage base, String newBody) {
|
||||
this.message = newBody;
|
||||
this.sender = base.getSender();
|
||||
this.senderDeviceId = base.getSenderDeviceId();
|
||||
this.protocol = base.getProtocol();
|
||||
this.serviceCenterAddress = base.getServiceCenterAddress();
|
||||
this.replyPathPresent = base.isReplyPathPresent();
|
||||
this.pseudoSubject = base.getPseudoSubject();
|
||||
this.sentTimestampMillis = base.getSentTimestampMillis();
|
||||
this.groupId = base.getGroupId();
|
||||
this.push = base.isPush();
|
||||
this.subscriptionId = base.getSubscriptionId();
|
||||
this.expiresInMillis = base.getExpiresIn();
|
||||
this.unidentified = base.isUnidentified();
|
||||
this.message = newBody;
|
||||
this.sender = base.getSender();
|
||||
this.senderDeviceId = base.getSenderDeviceId();
|
||||
this.protocol = base.getProtocol();
|
||||
this.serviceCenterAddress = base.getServiceCenterAddress();
|
||||
this.replyPathPresent = base.isReplyPathPresent();
|
||||
this.pseudoSubject = base.getPseudoSubject();
|
||||
this.sentTimestampMillis = base.getSentTimestampMillis();
|
||||
this.serverTimestampMillis = base.getServerTimestampMillis();
|
||||
this.groupId = base.getGroupId();
|
||||
this.push = base.isPush();
|
||||
this.subscriptionId = base.getSubscriptionId();
|
||||
this.expiresInMillis = base.getExpiresIn();
|
||||
this.unidentified = base.isUnidentified();
|
||||
}
|
||||
|
||||
public IncomingTextMessage(List<IncomingTextMessage> fragments) {
|
||||
|
@ -117,36 +127,38 @@ public class IncomingTextMessage implements Parcelable {
|
|||
body.append(message.getMessageBody());
|
||||
}
|
||||
|
||||
this.message = body.toString();
|
||||
this.sender = fragments.get(0).getSender();
|
||||
this.senderDeviceId = fragments.get(0).getSenderDeviceId();
|
||||
this.protocol = fragments.get(0).getProtocol();
|
||||
this.serviceCenterAddress = fragments.get(0).getServiceCenterAddress();
|
||||
this.replyPathPresent = fragments.get(0).isReplyPathPresent();
|
||||
this.pseudoSubject = fragments.get(0).getPseudoSubject();
|
||||
this.sentTimestampMillis = fragments.get(0).getSentTimestampMillis();
|
||||
this.groupId = fragments.get(0).getGroupId();
|
||||
this.push = fragments.get(0).isPush();
|
||||
this.subscriptionId = fragments.get(0).getSubscriptionId();
|
||||
this.expiresInMillis = fragments.get(0).getExpiresIn();
|
||||
this.unidentified = fragments.get(0).isUnidentified();
|
||||
this.message = body.toString();
|
||||
this.sender = fragments.get(0).getSender();
|
||||
this.senderDeviceId = fragments.get(0).getSenderDeviceId();
|
||||
this.protocol = fragments.get(0).getProtocol();
|
||||
this.serviceCenterAddress = fragments.get(0).getServiceCenterAddress();
|
||||
this.replyPathPresent = fragments.get(0).isReplyPathPresent();
|
||||
this.pseudoSubject = fragments.get(0).getPseudoSubject();
|
||||
this.sentTimestampMillis = fragments.get(0).getSentTimestampMillis();
|
||||
this.serverTimestampMillis = fragments.get(0).getServerTimestampMillis();
|
||||
this.groupId = fragments.get(0).getGroupId();
|
||||
this.push = fragments.get(0).isPush();
|
||||
this.subscriptionId = fragments.get(0).getSubscriptionId();
|
||||
this.expiresInMillis = fragments.get(0).getExpiresIn();
|
||||
this.unidentified = fragments.get(0).isUnidentified();
|
||||
}
|
||||
|
||||
protected IncomingTextMessage(@NonNull RecipientId sender, @Nullable GroupId groupId)
|
||||
{
|
||||
this.message = "";
|
||||
this.sender = sender;
|
||||
this.senderDeviceId = SignalServiceAddress.DEFAULT_DEVICE_ID;
|
||||
this.protocol = 31338;
|
||||
this.serviceCenterAddress = "Outgoing";
|
||||
this.replyPathPresent = true;
|
||||
this.pseudoSubject = "";
|
||||
this.sentTimestampMillis = System.currentTimeMillis();
|
||||
this.groupId = groupId;
|
||||
this.push = true;
|
||||
this.subscriptionId = -1;
|
||||
this.expiresInMillis = 0;
|
||||
this.unidentified = false;
|
||||
this.message = "";
|
||||
this.sender = sender;
|
||||
this.senderDeviceId = SignalServiceAddress.DEFAULT_DEVICE_ID;
|
||||
this.protocol = 31338;
|
||||
this.serviceCenterAddress = "Outgoing";
|
||||
this.replyPathPresent = true;
|
||||
this.pseudoSubject = "";
|
||||
this.sentTimestampMillis = System.currentTimeMillis();
|
||||
this.serverTimestampMillis = sentTimestampMillis;
|
||||
this.groupId = groupId;
|
||||
this.push = true;
|
||||
this.subscriptionId = -1;
|
||||
this.expiresInMillis = 0;
|
||||
this.unidentified = false;
|
||||
}
|
||||
|
||||
public int getSubscriptionId() {
|
||||
|
@ -161,6 +173,10 @@ public class IncomingTextMessage implements Parcelable {
|
|||
return sentTimestampMillis;
|
||||
}
|
||||
|
||||
public long getServerTimestampMillis() {
|
||||
return serverTimestampMillis;
|
||||
}
|
||||
|
||||
public String getPseudoSubject() {
|
||||
return pseudoSubject;
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ public class IdentityUtil {
|
|||
if (groupRecord.getMembers().contains(recipient.getId()) && groupRecord.isActive() && !groupRecord.isMms()) {
|
||||
|
||||
if (remote) {
|
||||
IncomingTextMessage incoming = new IncomingTextMessage(recipient.getId(), 1, time, null, Optional.of(groupRecord.getId()), 0, false);
|
||||
IncomingTextMessage incoming = new IncomingTextMessage(recipient.getId(), 1, time, -1, null, Optional.of(groupRecord.getId()), 0, false);
|
||||
|
||||
if (verified) incoming = new IncomingIdentityVerifiedMessage(incoming);
|
||||
else incoming = new IncomingIdentityDefaultMessage(incoming);
|
||||
|
@ -100,7 +100,7 @@ public class IdentityUtil {
|
|||
}
|
||||
|
||||
if (remote) {
|
||||
IncomingTextMessage incoming = new IncomingTextMessage(recipient.getId(), 1, time, null, Optional.absent(), 0, false);
|
||||
IncomingTextMessage incoming = new IncomingTextMessage(recipient.getId(), 1, time, -1, null, Optional.absent(), 0, false);
|
||||
|
||||
if (verified) incoming = new IncomingIdentityVerifiedMessage(incoming);
|
||||
else incoming = new IncomingIdentityDefaultMessage(incoming);
|
||||
|
@ -129,14 +129,14 @@ public class IdentityUtil {
|
|||
|
||||
while ((groupRecord = reader.getNext()) != null) {
|
||||
if (groupRecord.getMembers().contains(recipient.getId()) && groupRecord.isActive()) {
|
||||
IncomingTextMessage incoming = new IncomingTextMessage(recipient.getId(), 1, time, null, Optional.of(groupRecord.getId()), 0, false);
|
||||
IncomingTextMessage incoming = new IncomingTextMessage(recipient.getId(), 1, time, time, null, Optional.of(groupRecord.getId()), 0, false);
|
||||
IncomingIdentityUpdateMessage groupUpdate = new IncomingIdentityUpdateMessage(incoming);
|
||||
|
||||
smsDatabase.insertMessageInbox(groupUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
IncomingTextMessage incoming = new IncomingTextMessage(recipient.getId(), 1, time, null, Optional.absent(), 0, false);
|
||||
IncomingTextMessage incoming = new IncomingTextMessage(recipient.getId(), 1, time, -1, null, Optional.absent(), 0, false);
|
||||
IncomingIdentityUpdateMessage individualUpdate = new IncomingIdentityUpdateMessage(incoming);
|
||||
Optional<InsertResult> insertResult = smsDatabase.insertMessageInbox(individualUpdate);
|
||||
|
||||
|
|
|
@ -176,14 +176,14 @@ public class SignalServiceCipher {
|
|||
SessionCipher sessionCipher = new SessionCipher(signalProtocolStore, sourceAddress);
|
||||
|
||||
paddedMessage = sessionCipher.decrypt(new PreKeySignalMessage(ciphertext));
|
||||
metadata = new SignalServiceMetadata(envelope.getSourceAddress(), envelope.getSourceDevice(), envelope.getTimestamp(), false);
|
||||
metadata = new SignalServiceMetadata(envelope.getSourceAddress(), envelope.getSourceDevice(), envelope.getTimestamp(), envelope.getServerTimestamp(), false);
|
||||
sessionVersion = sessionCipher.getSessionVersion();
|
||||
} else if (envelope.isSignalMessage()) {
|
||||
SignalProtocolAddress sourceAddress = getPreferredProtocolAddress(signalProtocolStore, envelope.getSourceAddress(), envelope.getSourceDevice());
|
||||
SessionCipher sessionCipher = new SessionCipher(signalProtocolStore, sourceAddress);
|
||||
|
||||
paddedMessage = sessionCipher.decrypt(new SignalMessage(ciphertext));
|
||||
metadata = new SignalServiceMetadata(envelope.getSourceAddress(), envelope.getSourceDevice(), envelope.getTimestamp(), false);
|
||||
metadata = new SignalServiceMetadata(envelope.getSourceAddress(), envelope.getSourceDevice(), envelope.getTimestamp(), envelope.getServerTimestamp(), false);
|
||||
sessionVersion = sessionCipher.getSessionVersion();
|
||||
} else if (envelope.isUnidentifiedSender()) {
|
||||
SealedSessionCipher sealedSessionCipher = new SealedSessionCipher(signalProtocolStore, localAddress.getUuid().orNull(), localAddress.getNumber().orNull(), 1);
|
||||
|
@ -192,7 +192,7 @@ public class SignalServiceCipher {
|
|||
SignalProtocolAddress protocolAddress = getPreferredProtocolAddress(signalProtocolStore, resultAddress, result.getDeviceId());
|
||||
|
||||
paddedMessage = result.getPaddedMessage();
|
||||
metadata = new SignalServiceMetadata(resultAddress, result.getDeviceId(), envelope.getTimestamp(), true);
|
||||
metadata = new SignalServiceMetadata(resultAddress, result.getDeviceId(), envelope.getTimestamp(), envelope.getServerTimestamp(), true);
|
||||
sessionVersion = sealedSessionCipher.getSessionVersion(protocolAddress);
|
||||
} else {
|
||||
throw new InvalidMetadataMessageException("Unknown type: " + envelope.getType());
|
||||
|
|
|
@ -58,6 +58,7 @@ public final class SignalServiceContent {
|
|||
private final SignalServiceAddress sender;
|
||||
private final int senderDevice;
|
||||
private final long timestamp;
|
||||
private final long serverTimestamp;
|
||||
private final boolean needsReceipt;
|
||||
private final SignalServiceContentProto serializedState;
|
||||
|
||||
|
@ -67,10 +68,11 @@ public final class SignalServiceContent {
|
|||
private final Optional<SignalServiceReceiptMessage> readMessage;
|
||||
private final Optional<SignalServiceTypingMessage> typingMessage;
|
||||
|
||||
private SignalServiceContent(SignalServiceDataMessage message, SignalServiceAddress sender, int senderDevice, long timestamp, boolean needsReceipt, SignalServiceContentProto serializedState) {
|
||||
private SignalServiceContent(SignalServiceDataMessage message, SignalServiceAddress sender, int senderDevice, long timestamp, long serverTimestamp, boolean needsReceipt, SignalServiceContentProto serializedState) {
|
||||
this.sender = sender;
|
||||
this.senderDevice = senderDevice;
|
||||
this.timestamp = timestamp;
|
||||
this.serverTimestamp = serverTimestamp;
|
||||
this.needsReceipt = needsReceipt;
|
||||
this.serializedState = serializedState;
|
||||
|
||||
|
@ -81,10 +83,11 @@ public final class SignalServiceContent {
|
|||
this.typingMessage = Optional.absent();
|
||||
}
|
||||
|
||||
private SignalServiceContent(SignalServiceSyncMessage synchronizeMessage, SignalServiceAddress sender, int senderDevice, long timestamp, boolean needsReceipt, SignalServiceContentProto serializedState) {
|
||||
private SignalServiceContent(SignalServiceSyncMessage synchronizeMessage, SignalServiceAddress sender, int senderDevice, long timestamp, long serverTimestamp, boolean needsReceipt, SignalServiceContentProto serializedState) {
|
||||
this.sender = sender;
|
||||
this.senderDevice = senderDevice;
|
||||
this.timestamp = timestamp;
|
||||
this.serverTimestamp = serverTimestamp;
|
||||
this.needsReceipt = needsReceipt;
|
||||
this.serializedState = serializedState;
|
||||
|
||||
|
@ -95,10 +98,11 @@ public final class SignalServiceContent {
|
|||
this.typingMessage = Optional.absent();
|
||||
}
|
||||
|
||||
private SignalServiceContent(SignalServiceCallMessage callMessage, SignalServiceAddress sender, int senderDevice, long timestamp, boolean needsReceipt, SignalServiceContentProto serializedState) {
|
||||
private SignalServiceContent(SignalServiceCallMessage callMessage, SignalServiceAddress sender, int senderDevice, long timestamp, long serverTimestamp, boolean needsReceipt, SignalServiceContentProto serializedState) {
|
||||
this.sender = sender;
|
||||
this.senderDevice = senderDevice;
|
||||
this.timestamp = timestamp;
|
||||
this.serverTimestamp = serverTimestamp;
|
||||
this.needsReceipt = needsReceipt;
|
||||
this.serializedState = serializedState;
|
||||
|
||||
|
@ -109,10 +113,11 @@ public final class SignalServiceContent {
|
|||
this.typingMessage = Optional.absent();
|
||||
}
|
||||
|
||||
private SignalServiceContent(SignalServiceReceiptMessage receiptMessage, SignalServiceAddress sender, int senderDevice, long timestamp, boolean needsReceipt, SignalServiceContentProto serializedState) {
|
||||
private SignalServiceContent(SignalServiceReceiptMessage receiptMessage, SignalServiceAddress sender, int senderDevice, long timestamp, long serverTimestamp, boolean needsReceipt, SignalServiceContentProto serializedState) {
|
||||
this.sender = sender;
|
||||
this.senderDevice = senderDevice;
|
||||
this.timestamp = timestamp;
|
||||
this.serverTimestamp = serverTimestamp;
|
||||
this.needsReceipt = needsReceipt;
|
||||
this.serializedState = serializedState;
|
||||
|
||||
|
@ -123,10 +128,11 @@ public final class SignalServiceContent {
|
|||
this.typingMessage = Optional.absent();
|
||||
}
|
||||
|
||||
private SignalServiceContent(SignalServiceTypingMessage typingMessage, SignalServiceAddress sender, int senderDevice, long timestamp, boolean needsReceipt, SignalServiceContentProto serializedState) {
|
||||
private SignalServiceContent(SignalServiceTypingMessage typingMessage, SignalServiceAddress sender, int senderDevice, long timestamp, long serverTimestamp, boolean needsReceipt, SignalServiceContentProto serializedState) {
|
||||
this.sender = sender;
|
||||
this.senderDevice = senderDevice;
|
||||
this.timestamp = timestamp;
|
||||
this.serverTimestamp = serverTimestamp;
|
||||
this.needsReceipt = needsReceipt;
|
||||
this.serializedState = serializedState;
|
||||
|
||||
|
@ -169,6 +175,10 @@ public final class SignalServiceContent {
|
|||
return timestamp;
|
||||
}
|
||||
|
||||
public long getServerTimestamp() {
|
||||
return serverTimestamp;
|
||||
}
|
||||
|
||||
public boolean isNeedsReceipt() {
|
||||
return needsReceipt;
|
||||
}
|
||||
|
@ -206,6 +216,7 @@ public final class SignalServiceContent {
|
|||
metadata.getSender(),
|
||||
metadata.getSenderDevice(),
|
||||
metadata.getTimestamp(),
|
||||
metadata.getServerTimestamp(),
|
||||
metadata.isNeedsReceipt(),
|
||||
serviceContentProto);
|
||||
} else if (serviceContentProto.getDataCase() == SignalServiceContentProto.DataCase.CONTENT) {
|
||||
|
@ -216,6 +227,7 @@ public final class SignalServiceContent {
|
|||
metadata.getSender(),
|
||||
metadata.getSenderDevice(),
|
||||
metadata.getTimestamp(),
|
||||
metadata.getServerTimestamp(),
|
||||
metadata.isNeedsReceipt(),
|
||||
serviceContentProto);
|
||||
} else if (message.hasSyncMessage() && localAddress.matches(metadata.getSender())) {
|
||||
|
@ -223,6 +235,7 @@ public final class SignalServiceContent {
|
|||
metadata.getSender(),
|
||||
metadata.getSenderDevice(),
|
||||
metadata.getTimestamp(),
|
||||
metadata.getServerTimestamp(),
|
||||
metadata.isNeedsReceipt(),
|
||||
serviceContentProto);
|
||||
} else if (message.hasCallMessage()) {
|
||||
|
@ -230,6 +243,7 @@ public final class SignalServiceContent {
|
|||
metadata.getSender(),
|
||||
metadata.getSenderDevice(),
|
||||
metadata.getTimestamp(),
|
||||
metadata.getServerTimestamp(),
|
||||
metadata.isNeedsReceipt(),
|
||||
serviceContentProto);
|
||||
} else if (message.hasReceiptMessage()) {
|
||||
|
@ -237,6 +251,7 @@ public final class SignalServiceContent {
|
|||
metadata.getSender(),
|
||||
metadata.getSenderDevice(),
|
||||
metadata.getTimestamp(),
|
||||
metadata.getServerTimestamp(),
|
||||
metadata.isNeedsReceipt(),
|
||||
serviceContentProto);
|
||||
} else if (message.hasTypingMessage()) {
|
||||
|
@ -244,6 +259,7 @@ public final class SignalServiceContent {
|
|||
metadata.getSender(),
|
||||
metadata.getSenderDevice(),
|
||||
metadata.getTimestamp(),
|
||||
metadata.getServerTimestamp(),
|
||||
false,
|
||||
serviceContentProto);
|
||||
}
|
||||
|
|
|
@ -6,13 +6,15 @@ public final class SignalServiceMetadata {
|
|||
private final SignalServiceAddress sender;
|
||||
private final int senderDevice;
|
||||
private final long timestamp;
|
||||
private final long serverTimestamp;
|
||||
private final boolean needsReceipt;
|
||||
|
||||
public SignalServiceMetadata(SignalServiceAddress sender, int senderDevice, long timestamp, boolean needsReceipt) {
|
||||
this.sender = sender;
|
||||
this.senderDevice = senderDevice;
|
||||
this.timestamp = timestamp;
|
||||
this.needsReceipt = needsReceipt;
|
||||
public SignalServiceMetadata(SignalServiceAddress sender, int senderDevice, long timestamp, long serverTimestamp, boolean needsReceipt) {
|
||||
this.sender = sender;
|
||||
this.senderDevice = senderDevice;
|
||||
this.timestamp = timestamp;
|
||||
this.serverTimestamp = serverTimestamp;
|
||||
this.needsReceipt = needsReceipt;
|
||||
}
|
||||
|
||||
public SignalServiceAddress getSender() {
|
||||
|
@ -27,6 +29,10 @@ public final class SignalServiceMetadata {
|
|||
return timestamp;
|
||||
}
|
||||
|
||||
public long getServerTimestamp() {
|
||||
return serverTimestamp;
|
||||
}
|
||||
|
||||
public boolean isNeedsReceipt() {
|
||||
return needsReceipt;
|
||||
}
|
||||
|
|
|
@ -14,13 +14,15 @@ public final class SignalServiceMetadataProtobufSerializer {
|
|||
.setSenderDevice(metadata.getSenderDevice())
|
||||
.setNeedsReceipt(metadata.isNeedsReceipt())
|
||||
.setTimestamp(metadata.getTimestamp())
|
||||
.setServerTimestamp(metadata.getServerTimestamp())
|
||||
.build();
|
||||
}
|
||||
|
||||
public static SignalServiceMetadata fromProtobuf(MetadataProto metadata) {
|
||||
return new SignalServiceMetadata(SignalServiceAddressProtobufSerializer.fromProtobuf(metadata.getAddress()),
|
||||
metadata.getSenderDevice(),
|
||||
metadata.getTimestamp(),
|
||||
metadata.getNeedsReceipt());
|
||||
metadata.getSenderDevice(),
|
||||
metadata.getTimestamp(),
|
||||
metadata.getServerTimestamp(),
|
||||
metadata.getNeedsReceipt());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,10 +22,11 @@ message SignalServiceContentProto {
|
|||
}
|
||||
|
||||
message MetadataProto {
|
||||
optional AddressProto address = 1;
|
||||
optional int32 senderDevice = 2;
|
||||
optional int64 timestamp = 3;
|
||||
optional bool needsReceipt = 4;
|
||||
optional AddressProto address = 1;
|
||||
optional int32 senderDevice = 2;
|
||||
optional int64 timestamp = 3;
|
||||
optional int64 serverTimestamp = 5;
|
||||
optional bool needsReceipt = 4;
|
||||
}
|
||||
|
||||
message AddressProto {
|
||||
|
|
Loading…
Add table
Reference in a new issue