mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-27 12:05:22 +00:00
feat: add self sending syncTarget messages
This commit is contained in:
parent
e4a1de24f5
commit
57d532f4b8
@ -686,6 +686,15 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
return insertMessageInbox(message, Types.BASE_INBOX_TYPE, serverTimestamp);
|
return insertMessageInbox(message, Types.BASE_INBOX_TYPE, serverTimestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Optional<InsertResult> insertMessageOutbox(long threadId, OutgoingTextMessage message, long serverTimestamp) {
|
||||||
|
long messageId = insertMessageOutbox(threadId, message, false, serverTimestamp, null);
|
||||||
|
if (messageId == -1) {
|
||||||
|
return Optional.absent();
|
||||||
|
}
|
||||||
|
markAsSent(messageId, true);
|
||||||
|
return Optional.fromNullable(new InsertResult(messageId, threadId));
|
||||||
|
}
|
||||||
|
|
||||||
public long insertMessageOutbox(long threadId, OutgoingTextMessage message,
|
public long insertMessageOutbox(long threadId, OutgoingTextMessage message,
|
||||||
boolean forceSms, long date, InsertListener insertListener)
|
boolean forceSms, long date, InsertListener insertListener)
|
||||||
{
|
{
|
||||||
@ -716,9 +725,17 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
contentValues.put(DELIVERY_RECEIPT_COUNT, Stream.of(earlyDeliveryReceipts.values()).mapToLong(Long::longValue).sum());
|
contentValues.put(DELIVERY_RECEIPT_COUNT, Stream.of(earlyDeliveryReceipts.values()).mapToLong(Long::longValue).sum());
|
||||||
contentValues.put(READ_RECEIPT_COUNT, Stream.of(earlyReadReceipts.values()).mapToLong(Long::longValue).sum());
|
contentValues.put(READ_RECEIPT_COUNT, Stream.of(earlyReadReceipts.values()).mapToLong(Long::longValue).sum());
|
||||||
|
|
||||||
|
SQLiteDatabase readDb = databaseHelper.getReadableDatabase();
|
||||||
|
Cursor existingRecord = readDb.query(TABLE_NAME, null, String.format("%s = ? AND %s = ? AND %s = ?",ADDRESS, THREAD_ID, DATE_SENT),
|
||||||
|
new String[] { address.serialize(), Long.toString(threadId), Long.toString(date) }, null, null, null);
|
||||||
|
int existingRecordCount = existingRecord.getCount();
|
||||||
|
if (existingRecordCount > 0) {
|
||||||
|
// return -1 because record exists from Address to ThreadID with the same date sent (probably sent from us)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||||
long messageId = db.insert(TABLE_NAME, ADDRESS, contentValues);
|
long messageId = db.insert(TABLE_NAME, ADDRESS, contentValues);
|
||||||
|
|
||||||
if (insertListener != null) {
|
if (insertListener != null) {
|
||||||
insertListener.onComplete();
|
insertListener.onComplete();
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ import org.session.libsignal.metadata.ProtocolNoSessionException;
|
|||||||
import org.session.libsignal.metadata.ProtocolUntrustedIdentityException;
|
import org.session.libsignal.metadata.ProtocolUntrustedIdentityException;
|
||||||
import org.session.libsignal.metadata.SelfSendException;
|
import org.session.libsignal.metadata.SelfSendException;
|
||||||
import org.session.libsignal.service.loki.api.crypto.SessionProtocol;
|
import org.session.libsignal.service.loki.api.crypto.SessionProtocol;
|
||||||
|
import org.session.libsignal.service.loki.utilities.HexEncodingKt;
|
||||||
import org.session.libsignal.utilities.PromiseUtilities;
|
import org.session.libsignal.utilities.PromiseUtilities;
|
||||||
import org.thoughtcrime.securesms.ApplicationContext;
|
import org.thoughtcrime.securesms.ApplicationContext;
|
||||||
|
|
||||||
@ -568,6 +569,8 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
|||||||
{
|
{
|
||||||
Recipient originalRecipient = getMessageDestination(content, message);
|
Recipient originalRecipient = getMessageDestination(content, message);
|
||||||
Recipient masterRecipient = getMessageMasterDestination(content.getSender());
|
Recipient masterRecipient = getMessageMasterDestination(content.getSender());
|
||||||
|
String syncTarget = message.getSyncTarget().orNull();
|
||||||
|
|
||||||
|
|
||||||
notifyTypingStoppedFromIncomingMessage(masterRecipient, content.getSender(), content.getSenderDevice());
|
notifyTypingStoppedFromIncomingMessage(masterRecipient, content.getSender(), content.getSenderDevice());
|
||||||
|
|
||||||
@ -582,75 +585,79 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
|||||||
masterAddress = getMessageMasterDestination(content.getSender()).getAddress();
|
masterAddress = getMessageMasterDestination(content.getSender()).getAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(masterAddress, message.getTimestamp(), -1,
|
if (syncTarget != null && !syncTarget.isEmpty()) {
|
||||||
message.getExpiresInSeconds() * 1000L, false, content.isNeedsReceipt(), message.getBody(), message.getGroupInfo(), message.getAttachments(),
|
// OutgoingMediaMessage mediaMessage = new OutgoingMediaMessage(masterAddress, message.getTimestamp(), -1,
|
||||||
quote, sharedContacts, linkPreviews, sticker);
|
// message.getExpiresInSeconds() * 1000L, false, )
|
||||||
|
} else {
|
||||||
|
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(masterAddress, message.getTimestamp(), -1,
|
||||||
|
message.getExpiresInSeconds() * 1000L, false, content.isNeedsReceipt(), message.getBody(), message.getGroupInfo(), message.getAttachments(),
|
||||||
|
quote, sharedContacts, linkPreviews, sticker);
|
||||||
|
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||||
|
database.beginTransaction();
|
||||||
|
|
||||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
// Ignore message if it has no body and no attachments
|
||||||
database.beginTransaction();
|
if (mediaMessage.getBody().isEmpty() && mediaMessage.getAttachments().isEmpty() && mediaMessage.getLinkPreviews().isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Ignore message if it has no body and no attachments
|
Optional<InsertResult> insertResult;
|
||||||
if (mediaMessage.getBody().isEmpty() && mediaMessage.getAttachments().isEmpty() && mediaMessage.getLinkPreviews().isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Optional<InsertResult> insertResult;
|
try {
|
||||||
|
if (message.isGroupMessage()) {
|
||||||
|
insertResult = database.insertSecureDecryptedMessageInbox(mediaMessage, -1, content.getTimestamp());
|
||||||
|
} else {
|
||||||
|
insertResult = database.insertSecureDecryptedMessageInbox(mediaMessage, -1);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
if (insertResult.isPresent()) {
|
||||||
if (message.isGroupMessage()) {
|
List<DatabaseAttachment> allAttachments = DatabaseFactory.getAttachmentDatabase(context).getAttachmentsForMessage(insertResult.get().getMessageId());
|
||||||
insertResult = database.insertSecureDecryptedMessageInbox(mediaMessage, -1, content.getTimestamp());
|
List<DatabaseAttachment> stickerAttachments = Stream.of(allAttachments).filter(Attachment::isSticker).toList();
|
||||||
} else {
|
List<DatabaseAttachment> attachments = Stream.of(allAttachments).filterNot(Attachment::isSticker).toList();
|
||||||
insertResult = database.insertSecureDecryptedMessageInbox(mediaMessage, -1);
|
|
||||||
|
forceStickerDownloadIfNecessary(stickerAttachments);
|
||||||
|
|
||||||
|
for (DatabaseAttachment attachment : attachments) {
|
||||||
|
ApplicationContext.getInstance(context).getJobManager().add(new AttachmentDownloadJob(insertResult.get().getMessageId(), attachment.getAttachmentId(), false));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (smsMessageId.isPresent()) {
|
||||||
|
DatabaseFactory.getSmsDatabase(context).deleteMessage(smsMessageId.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
database.setTransactionSuccessful();
|
||||||
|
}
|
||||||
|
} catch (MmsException e) {
|
||||||
|
throw new StorageFailedException(e, content.getSender(), content.getSenderDevice());
|
||||||
|
} finally {
|
||||||
|
database.endTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (insertResult.isPresent()) {
|
if (insertResult.isPresent()) {
|
||||||
List<DatabaseAttachment> allAttachments = DatabaseFactory.getAttachmentDatabase(context).getAttachmentsForMessage(insertResult.get().getMessageId());
|
messageNotifier.updateNotification(context, insertResult.get().getThreadId());
|
||||||
List<DatabaseAttachment> stickerAttachments = Stream.of(allAttachments).filter(Attachment::isSticker).toList();
|
|
||||||
List<DatabaseAttachment> attachments = Stream.of(allAttachments).filterNot(Attachment::isSticker).toList();
|
|
||||||
|
|
||||||
forceStickerDownloadIfNecessary(stickerAttachments);
|
|
||||||
|
|
||||||
for (DatabaseAttachment attachment : attachments) {
|
|
||||||
ApplicationContext.getInstance(context).getJobManager().add(new AttachmentDownloadJob(insertResult.get().getMessageId(), attachment.getAttachmentId(), false));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (smsMessageId.isPresent()) {
|
|
||||||
DatabaseFactory.getSmsDatabase(context).deleteMessage(smsMessageId.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
database.setTransactionSuccessful();
|
|
||||||
}
|
|
||||||
} catch (MmsException e) {
|
|
||||||
throw new StorageFailedException(e, content.getSender(), content.getSenderDevice());
|
|
||||||
} finally {
|
|
||||||
database.endTransaction();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (insertResult.isPresent()) {
|
|
||||||
messageNotifier.updateNotification(context, insertResult.get().getThreadId());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (insertResult.isPresent()) {
|
|
||||||
InsertResult result = insertResult.get();
|
|
||||||
|
|
||||||
// Loki - Cache the user hex encoded public key (for mentions)
|
|
||||||
MentionManagerUtilities.INSTANCE.populateUserPublicKeyCacheIfNeeded(result.getThreadId(), context);
|
|
||||||
MentionsManager.shared.cache(content.getSender(), result.getThreadId());
|
|
||||||
|
|
||||||
// Loki - Store message open group server ID if needed
|
|
||||||
if (messageServerIDOrNull.isPresent()) {
|
|
||||||
long messageID = result.getMessageId();
|
|
||||||
long messageServerID = messageServerIDOrNull.get();
|
|
||||||
LokiMessageDatabase lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context);
|
|
||||||
lokiMessageDatabase.setServerID(messageID, messageServerID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loki - Update mapping of message ID to original thread ID
|
if (insertResult.isPresent()) {
|
||||||
if (result.getMessageId() > -1) {
|
InsertResult result = insertResult.get();
|
||||||
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);
|
|
||||||
LokiMessageDatabase lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context);
|
// Loki - Cache the user hex encoded public key (for mentions)
|
||||||
long originalThreadId = threadDatabase.getOrCreateThreadIdFor(originalRecipient);
|
MentionManagerUtilities.INSTANCE.populateUserPublicKeyCacheIfNeeded(result.getThreadId(), context);
|
||||||
lokiMessageDatabase.setOriginalThreadID(result.getMessageId(), originalThreadId);
|
MentionsManager.shared.cache(content.getSender(), result.getThreadId());
|
||||||
|
|
||||||
|
// Loki - Store message open group server ID if needed
|
||||||
|
if (messageServerIDOrNull.isPresent()) {
|
||||||
|
long messageID = result.getMessageId();
|
||||||
|
long messageServerID = messageServerIDOrNull.get();
|
||||||
|
LokiMessageDatabase lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context);
|
||||||
|
lokiMessageDatabase.setServerID(messageID, messageServerID);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loki - Update mapping of message ID to original thread ID
|
||||||
|
if (result.getMessageId() > -1) {
|
||||||
|
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);
|
||||||
|
LokiMessageDatabase lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context);
|
||||||
|
long originalThreadId = threadDatabase.getOrCreateThreadIdFor(originalRecipient);
|
||||||
|
lokiMessageDatabase.setOriginalThreadID(result.getMessageId(), originalThreadId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -769,6 +776,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
|||||||
String body = message.getBody().isPresent() ? message.getBody().get() : "";
|
String body = message.getBody().isPresent() ? message.getBody().get() : "";
|
||||||
Recipient originalRecipient = getMessageDestination(content, message);
|
Recipient originalRecipient = getMessageDestination(content, message);
|
||||||
Recipient masterRecipient = getMessageMasterDestination(content.getSender());
|
Recipient masterRecipient = getMessageMasterDestination(content.getSender());
|
||||||
|
String syncTarget = message.getSyncTarget().orNull();
|
||||||
|
|
||||||
if (message.getExpiresInSeconds() != originalRecipient.getExpireMessages()) {
|
if (message.getExpiresInSeconds() != originalRecipient.getExpireMessages()) {
|
||||||
handleExpirationUpdate(content, message, Optional.absent());
|
handleExpirationUpdate(content, message, Optional.absent());
|
||||||
@ -778,15 +786,46 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
|||||||
|
|
||||||
if (smsMessageId.isPresent() && !message.getGroupInfo().isPresent()) {
|
if (smsMessageId.isPresent() && !message.getGroupInfo().isPresent()) {
|
||||||
threadId = database.updateBundleMessageBody(smsMessageId.get(), body).second;
|
threadId = database.updateBundleMessageBody(smsMessageId.get(), body).second;
|
||||||
|
} else if (syncTarget != null && !syncTarget.isEmpty()) {
|
||||||
|
Address targetAddress = Address.fromSerialized(syncTarget);
|
||||||
|
|
||||||
|
OutgoingTextMessage tm = new OutgoingTextMessage(Recipient.from(context, targetAddress, false),
|
||||||
|
body, message.getExpiresInSeconds(), -1);
|
||||||
|
|
||||||
|
// Ignore the message if it has no body
|
||||||
|
if (tm.getMessageBody().length() == 0) { return; }
|
||||||
|
|
||||||
|
// Check if we have the thread already
|
||||||
|
long threadID = DatabaseFactory.getLokiThreadDatabase(context).getThreadID(syncTarget);
|
||||||
|
|
||||||
|
|
||||||
|
// Insert the message into the database
|
||||||
|
Optional<InsertResult> insertResult;
|
||||||
|
insertResult = database.insertMessageOutbox(threadID, tm, content.getTimestamp());
|
||||||
|
|
||||||
|
if (insertResult.isPresent()) {
|
||||||
|
threadId = insertResult.get().getThreadId();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (smsMessageId.isPresent()) database.deleteMessage(smsMessageId.get());
|
||||||
|
|
||||||
|
if (threadId != null) {
|
||||||
|
messageNotifier.updateNotification(context, threadId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (insertResult.isPresent()) {
|
||||||
|
InsertResult result = insertResult.get();
|
||||||
|
|
||||||
|
// Loki - Cache the user hex encoded public key (for mentions)
|
||||||
|
MentionManagerUtilities.INSTANCE.populateUserPublicKeyCacheIfNeeded(result.getThreadId(), context);
|
||||||
|
MentionsManager.shared.cache(content.getSender(), result.getThreadId());
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
notifyTypingStoppedFromIncomingMessage(masterRecipient, content.getSender(), content.getSenderDevice());
|
notifyTypingStoppedFromIncomingMessage(masterRecipient, content.getSender(), content.getSenderDevice());
|
||||||
|
|
||||||
Address masterAddress = masterRecipient.getAddress();
|
Address masterAddress = masterRecipient.getAddress();
|
||||||
|
|
||||||
if (message.isGroupMessage()) {
|
|
||||||
masterAddress = getMessageMasterDestination(content.getSender()).getAddress();
|
|
||||||
}
|
|
||||||
|
|
||||||
IncomingTextMessage tm = new IncomingTextMessage(masterAddress,
|
IncomingTextMessage tm = new IncomingTextMessage(masterAddress,
|
||||||
content.getSenderDevice(),
|
content.getSenderDevice(),
|
||||||
message.getTimestamp(), body,
|
message.getTimestamp(), body,
|
||||||
|
@ -15,6 +15,7 @@ import org.session.libsession.messaging.threads.recipients.Recipient;
|
|||||||
import org.session.libsession.messaging.threads.Address;
|
import org.session.libsession.messaging.threads.Address;
|
||||||
import org.session.libsession.utilities.GroupUtil;
|
import org.session.libsession.utilities.GroupUtil;
|
||||||
|
|
||||||
|
import org.session.libsession.utilities.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.ApplicationContext;
|
import org.thoughtcrime.securesms.ApplicationContext;
|
||||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
@ -143,6 +144,9 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
|||||||
List<NetworkFailure> existingNetworkFailures = message.getNetworkFailures();
|
List<NetworkFailure> existingNetworkFailures = message.getNetworkFailures();
|
||||||
List<IdentityKeyMismatch> existingIdentityMismatches = message.getIdentityKeyMismatches();
|
List<IdentityKeyMismatch> existingIdentityMismatches = message.getIdentityKeyMismatches();
|
||||||
|
|
||||||
|
String userPublicKey = TextSecurePreferences.getLocalNumber(context);
|
||||||
|
SignalServiceAddress localAddress = new SignalServiceAddress(userPublicKey);
|
||||||
|
|
||||||
if (database.isSent(messageId)) {
|
if (database.isSent(messageId)) {
|
||||||
log(TAG, "Message " + messageId + " was already sent. Ignoring.");
|
log(TAG, "Message " + messageId + " was already sent. Ignoring.");
|
||||||
return;
|
return;
|
||||||
@ -190,6 +194,22 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (existingNetworkFailures.isEmpty() && networkFailures.isEmpty() && identityMismatches.isEmpty() && existingIdentityMismatches.isEmpty()) {
|
if (existingNetworkFailures.isEmpty() && networkFailures.isEmpty() && identityMismatches.isEmpty() && existingIdentityMismatches.isEmpty()) {
|
||||||
|
Address address = message.getRecipient().getAddress();
|
||||||
|
if (!address.isOpenGroup()) {
|
||||||
|
try {
|
||||||
|
SignalServiceDataMessage selfSend = getDataMessage(address, message)
|
||||||
|
.withSyncTarget(address.toGroupString())
|
||||||
|
.build();
|
||||||
|
// send to ourselves to sync multi-device
|
||||||
|
Optional<UnidentifiedAccessPair> syncAccess = UnidentifiedAccessUtil.getAccessForSync(context);
|
||||||
|
SendMessageResult selfSendResult = messageSender.sendMessage(messageId, localAddress, syncAccess, selfSend);
|
||||||
|
if (selfSendResult.getLokiAPIError() != null) {
|
||||||
|
throw selfSendResult.getLokiAPIError();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("Loki", "Error sending message to ourselves", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
database.markAsSent(messageId, true);
|
database.markAsSent(messageId, true);
|
||||||
|
|
||||||
markAttachmentsUploaded(messageId, message.getAttachments());
|
markAttachmentsUploaded(messageId, message.getAttachments());
|
||||||
@ -238,25 +258,18 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
|||||||
// return results;
|
// return results;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
String groupId = address.toGroupString();
|
|
||||||
Optional<byte[]> profileKey = getProfileKey(message.getRecipient());
|
|
||||||
Optional<Quote> quote = getQuoteFor(message);
|
|
||||||
Optional<SignalServiceDataMessage.Sticker> sticker = getStickerFor(message);
|
|
||||||
List<SharedContact> sharedContacts = getSharedContactsFor(message);
|
|
||||||
List<Preview> previews = getPreviewsFor(message);
|
|
||||||
List<SignalServiceAddress> addresses = Stream.of(destinations).map(this::getPushAddress).toList();
|
List<SignalServiceAddress> addresses = Stream.of(destinations).map(this::getPushAddress).toList();
|
||||||
List<Attachment> attachments = Stream.of(message.getAttachments()).filterNot(Attachment::isSticker).toList();
|
|
||||||
List<SignalServiceAttachment> attachmentPointers = getAttachmentPointersFor(attachments);
|
|
||||||
|
|
||||||
List<Optional<UnidentifiedAccessPair>> unidentifiedAccess = Stream.of(addresses)
|
List<Optional<UnidentifiedAccessPair>> unidentifiedAccess = Stream.of(addresses)
|
||||||
.map(a -> Address.Companion.fromSerialized(a.getNumber()))
|
.map(a -> Address.Companion.fromSerialized(a.getNumber()))
|
||||||
.map(a -> Recipient.from(context, a, false))
|
.map(a -> Recipient.from(context, a, false))
|
||||||
.map(recipient -> UnidentifiedAccessUtil.getAccessFor(context, recipient))
|
.map(recipient -> UnidentifiedAccessUtil.getAccessFor(context, recipient))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
SignalServiceGroup.GroupType groupType = address.isOpenGroup() ? SignalServiceGroup.GroupType.PUBLIC_CHAT : SignalServiceGroup.GroupType.SIGNAL;
|
|
||||||
|
|
||||||
if (message.isGroup() && address.isClosedGroup()) {
|
if (message.isGroup() && address.isClosedGroup()) {
|
||||||
|
SignalServiceGroup.GroupType groupType = address.isOpenGroup() ? SignalServiceGroup.GroupType.PUBLIC_CHAT : SignalServiceGroup.GroupType.SIGNAL;
|
||||||
|
String groupId = address.toGroupString();
|
||||||
|
List<Attachment> attachments = Stream.of(message.getAttachments()).filterNot(Attachment::isSticker).toList();
|
||||||
|
List<SignalServiceAttachment> attachmentPointers = getAttachmentPointersFor(attachments);
|
||||||
// Loki - Only send GroupUpdate or GroupQuit messages to closed groups
|
// Loki - Only send GroupUpdate or GroupQuit messages to closed groups
|
||||||
OutgoingGroupMediaMessage groupMessage = (OutgoingGroupMediaMessage) message;
|
OutgoingGroupMediaMessage groupMessage = (OutgoingGroupMediaMessage) message;
|
||||||
GroupContext groupContext = groupMessage.getGroupContext();
|
GroupContext groupContext = groupMessage.getGroupContext();
|
||||||
@ -271,25 +284,40 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
|||||||
|
|
||||||
return messageSender.sendMessage(messageId, addresses, unidentifiedAccess, groupDataMessage);
|
return messageSender.sendMessage(messageId, addresses, unidentifiedAccess, groupDataMessage);
|
||||||
} else {
|
} else {
|
||||||
SignalServiceGroup group = new SignalServiceGroup(GroupUtil.getDecodedGroupIDAsData(groupId), groupType);
|
SignalServiceDataMessage groupMessage = getDataMessage(address, message).build();
|
||||||
SignalServiceDataMessage groupMessage = SignalServiceDataMessage.newBuilder()
|
|
||||||
.withTimestamp(message.getSentTimeMillis())
|
|
||||||
.asGroupMessage(group)
|
|
||||||
.withAttachments(attachmentPointers)
|
|
||||||
.withBody(message.getBody())
|
|
||||||
.withExpiration((int)(message.getExpiresIn() / 1000))
|
|
||||||
.asExpirationUpdate(message.isExpirationUpdate())
|
|
||||||
.withProfileKey(profileKey.orNull())
|
|
||||||
.withQuote(quote.orNull())
|
|
||||||
.withSticker(sticker.orNull())
|
|
||||||
.withSharedContacts(sharedContacts)
|
|
||||||
.withPreviews(previews)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
return messageSender.sendMessage(messageId, addresses, unidentifiedAccess, groupMessage);
|
return messageSender.sendMessage(messageId, addresses, unidentifiedAccess, groupMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SignalServiceDataMessage.Builder getDataMessage(Address address, OutgoingMediaMessage message) {
|
||||||
|
|
||||||
|
SignalServiceGroup.GroupType groupType = address.isOpenGroup() ? SignalServiceGroup.GroupType.PUBLIC_CHAT : SignalServiceGroup.GroupType.SIGNAL;
|
||||||
|
|
||||||
|
String groupId = address.toGroupString();
|
||||||
|
Optional<byte[]> profileKey = getProfileKey(message.getRecipient());
|
||||||
|
Optional<Quote> quote = getQuoteFor(message);
|
||||||
|
Optional<SignalServiceDataMessage.Sticker> sticker = getStickerFor(message);
|
||||||
|
List<SharedContact> sharedContacts = getSharedContactsFor(message);
|
||||||
|
List<Preview> previews = getPreviewsFor(message);
|
||||||
|
List<Attachment> attachments = Stream.of(message.getAttachments()).filterNot(Attachment::isSticker).toList();
|
||||||
|
List<SignalServiceAttachment> attachmentPointers = getAttachmentPointersFor(attachments);
|
||||||
|
|
||||||
|
SignalServiceGroup group = new SignalServiceGroup(GroupUtil.getDecodedGroupIDAsData(groupId), groupType);
|
||||||
|
return SignalServiceDataMessage.newBuilder()
|
||||||
|
.withTimestamp(message.getSentTimeMillis())
|
||||||
|
.asGroupMessage(group)
|
||||||
|
.withAttachments(attachmentPointers)
|
||||||
|
.withBody(message.getBody())
|
||||||
|
.withExpiration((int)(message.getExpiresIn() / 1000))
|
||||||
|
.asExpirationUpdate(message.isExpirationUpdate())
|
||||||
|
.withProfileKey(profileKey.orNull())
|
||||||
|
.withQuote(quote.orNull())
|
||||||
|
.withSticker(sticker.orNull())
|
||||||
|
.withSharedContacts(sharedContacts)
|
||||||
|
.withPreviews(previews);
|
||||||
|
}
|
||||||
|
|
||||||
public static class Factory implements Job.Factory<PushGroupSendJob> {
|
public static class Factory implements Job.Factory<PushGroupSendJob> {
|
||||||
@Override
|
@Override
|
||||||
public @NonNull PushGroupSendJob create(@NonNull Parameters parameters, @NonNull Data data) {
|
public @NonNull PushGroupSendJob create(@NonNull Parameters parameters, @NonNull Data data) {
|
||||||
|
@ -245,7 +245,9 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
Recipient recipient = Recipient.from(context, destination, false);
|
Recipient recipient = Recipient.from(context, destination, false);
|
||||||
|
String userPublicKey = TextSecurePreferences.getLocalNumber(context);
|
||||||
SignalServiceAddress address = getPushAddress(recipient.getAddress());
|
SignalServiceAddress address = getPushAddress(recipient.getAddress());
|
||||||
|
SignalServiceAddress localAddress = new SignalServiceAddress(userPublicKey);
|
||||||
List<Attachment> attachments = Stream.of(message.getAttachments()).filterNot(Attachment::isSticker).toList();
|
List<Attachment> attachments = Stream.of(message.getAttachments()).filterNot(Attachment::isSticker).toList();
|
||||||
List<SignalServiceAttachment> serviceAttachments = getAttachmentPointersFor(attachments);
|
List<SignalServiceAttachment> serviceAttachments = getAttachmentPointersFor(attachments);
|
||||||
Optional<byte[]> profileKey = getProfileKey(message.getRecipient());
|
Optional<byte[]> profileKey = getProfileKey(message.getRecipient());
|
||||||
@ -254,6 +256,8 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
|||||||
List<SharedContact> sharedContacts = getSharedContactsFor(message);
|
List<SharedContact> sharedContacts = getSharedContactsFor(message);
|
||||||
List<Preview> previews = getPreviewsFor(message);
|
List<Preview> previews = getPreviewsFor(message);
|
||||||
|
|
||||||
|
Optional<UnidentifiedAccessPair> unidentifiedAccessPair = UnidentifiedAccessUtil.getAccessFor(context, recipient);
|
||||||
|
|
||||||
SignalServiceDataMessage mediaMessage = SignalServiceDataMessage.newBuilder()
|
SignalServiceDataMessage mediaMessage = SignalServiceDataMessage.newBuilder()
|
||||||
.withBody(message.getBody())
|
.withBody(message.getBody())
|
||||||
.withAttachments(serviceAttachments)
|
.withAttachments(serviceAttachments)
|
||||||
@ -267,6 +271,20 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
|||||||
.asExpirationUpdate(message.isExpirationUpdate())
|
.asExpirationUpdate(message.isExpirationUpdate())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
SignalServiceDataMessage mediaSelfSendMessage = SignalServiceDataMessage.newBuilder()
|
||||||
|
.withBody(message.getBody())
|
||||||
|
.withAttachments(serviceAttachments)
|
||||||
|
.withTimestamp(message.getSentTimeMillis())
|
||||||
|
.withSyncTarget(destination.serialize())
|
||||||
|
.withExpiration((int)(message.getExpiresIn() / 1000))
|
||||||
|
.withProfileKey(profileKey.orNull())
|
||||||
|
.withQuote(quote.orNull())
|
||||||
|
.withSticker(sticker.orNull())
|
||||||
|
.withSharedContacts(sharedContacts)
|
||||||
|
.withPreviews(previews)
|
||||||
|
.asExpirationUpdate(message.isExpirationUpdate())
|
||||||
|
.build();
|
||||||
|
|
||||||
if (SessionMetaProtocol.shared.isNoteToSelf(address.getNumber())) {
|
if (SessionMetaProtocol.shared.isNoteToSelf(address.getNumber())) {
|
||||||
// Loki - Device link messages don't go through here
|
// Loki - Device link messages don't go through here
|
||||||
Optional<UnidentifiedAccessPair> syncAccess = UnidentifiedAccessUtil.getAccessForSync(context);
|
Optional<UnidentifiedAccessPair> syncAccess = UnidentifiedAccessUtil.getAccessForSync(context);
|
||||||
@ -275,11 +293,24 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
|||||||
messageSender.sendMessage(syncMessage, syncAccess);
|
messageSender.sendMessage(syncMessage, syncAccess);
|
||||||
return syncAccess.isPresent();
|
return syncAccess.isPresent();
|
||||||
} else {
|
} else {
|
||||||
SendMessageResult result = messageSender.sendMessage(messageId, address, UnidentifiedAccessUtil.getAccessFor(context, recipient), mediaMessage);
|
SendMessageResult result = messageSender.sendMessage(messageId, address, unidentifiedAccessPair, mediaMessage);
|
||||||
if (result.getLokiAPIError() != null) {
|
if (result.getLokiAPIError() != null) {
|
||||||
throw result.getLokiAPIError();
|
throw result.getLokiAPIError();
|
||||||
} else {
|
} else {
|
||||||
return result.getSuccess().isUnidentified();
|
boolean isUnidentified = result.getSuccess().isUnidentified();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// send to ourselves to sync multi-device
|
||||||
|
Optional<UnidentifiedAccessPair> syncAccess = UnidentifiedAccessUtil.getAccessForSync(context);
|
||||||
|
SendMessageResult selfSendResult = messageSender.sendMessage(messageId, localAddress, syncAccess, mediaSelfSendMessage);
|
||||||
|
if (selfSendResult.getLokiAPIError() != null) {
|
||||||
|
throw selfSendResult.getLokiAPIError();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("Loki", "Error sending message to ourselves", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return isUnidentified;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (UnregisteredUserException e) {
|
} catch (UnregisteredUserException e) {
|
||||||
|
@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.jobs;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import org.session.libsession.messaging.jobs.Data;
|
import org.session.libsession.messaging.jobs.Data;
|
||||||
|
import org.session.libsignal.service.api.crypto.UnidentifiedAccess;
|
||||||
import org.session.libsignal.utilities.logging.Log;
|
import org.session.libsignal.utilities.logging.Log;
|
||||||
|
|
||||||
import org.session.libsession.messaging.threads.Address;
|
import org.session.libsession.messaging.threads.Address;
|
||||||
@ -192,8 +193,10 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
|
|||||||
throws UntrustedIdentityException, InsecureFallbackApprovalException, RetryLaterException, SnodeAPI.Error
|
throws UntrustedIdentityException, InsecureFallbackApprovalException, RetryLaterException, SnodeAPI.Error
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
String userPublicKey = TextSecurePreferences.getLocalNumber(context);
|
||||||
Recipient recipient = Recipient.from(context, destination, false);
|
Recipient recipient = Recipient.from(context, destination, false);
|
||||||
SignalServiceAddress address = getPushAddress(recipient.getAddress());
|
SignalServiceAddress address = getPushAddress(recipient.getAddress());
|
||||||
|
SignalServiceAddress localAddress = new SignalServiceAddress(userPublicKey);
|
||||||
Optional<byte[]> profileKey = getProfileKey(recipient);
|
Optional<byte[]> profileKey = getProfileKey(recipient);
|
||||||
Optional<UnidentifiedAccessPair> unidentifiedAccess = UnidentifiedAccessUtil.getAccessFor(context, recipient);
|
Optional<UnidentifiedAccessPair> unidentifiedAccess = UnidentifiedAccessUtil.getAccessFor(context, recipient);
|
||||||
|
|
||||||
@ -205,13 +208,21 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
SignalServiceDataMessage textSecureMessage = SignalServiceDataMessage.newBuilder()
|
SignalServiceDataMessage textSecureMessage = SignalServiceDataMessage.newBuilder()
|
||||||
.withTimestamp(message.getDateSent())
|
.withTimestamp(message.getDateSent())
|
||||||
.withBody(message.getBody())
|
.withBody(message.getBody())
|
||||||
.withExpiration((int)(message.getExpiresIn() / 1000))
|
.withExpiration((int)(message.getExpiresIn() / 1000))
|
||||||
.withProfileKey(profileKey.orNull())
|
.withProfileKey(profileKey.orNull())
|
||||||
// .withPreKeyBundle(preKeyBundle)
|
.asEndSessionMessage(message.isEndSession())
|
||||||
.asEndSessionMessage(message.isEndSession())
|
.build();
|
||||||
.build();
|
|
||||||
|
SignalServiceDataMessage textSecureSelfSendMessage = SignalServiceDataMessage.newBuilder()
|
||||||
|
.withTimestamp(message.getDateSent())
|
||||||
|
.withBody(message.getBody())
|
||||||
|
.withSyncTarget(destination.serialize())
|
||||||
|
.withExpiration((int)(message.getExpiresIn() / 1000))
|
||||||
|
.withProfileKey(profileKey.orNull())
|
||||||
|
.asEndSessionMessage(message.isEndSession())
|
||||||
|
.build();
|
||||||
|
|
||||||
if (SessionMetaProtocol.shared.isNoteToSelf(address.getNumber())) {
|
if (SessionMetaProtocol.shared.isNoteToSelf(address.getNumber())) {
|
||||||
// Loki - Device link messages don't go through here
|
// Loki - Device link messages don't go through here
|
||||||
@ -225,7 +236,19 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
|
|||||||
if (result.getLokiAPIError() != null) {
|
if (result.getLokiAPIError() != null) {
|
||||||
throw result.getLokiAPIError();
|
throw result.getLokiAPIError();
|
||||||
} else {
|
} else {
|
||||||
return result.getSuccess().isUnidentified();
|
boolean isUnidentified = result.getSuccess().isUnidentified();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// send to ourselves to sync multi-device
|
||||||
|
Optional<UnidentifiedAccessPair> syncAccess = UnidentifiedAccessUtil.getAccessForSync(context);
|
||||||
|
SendMessageResult selfSendResult = messageSender.sendMessage(messageId, localAddress, syncAccess, textSecureSelfSendMessage);
|
||||||
|
if (selfSendResult.getLokiAPIError() != null) {
|
||||||
|
throw selfSendResult.getLokiAPIError();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("Loki", "Error sending message to ourselves", e);
|
||||||
|
}
|
||||||
|
return isUnidentified;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (UnregisteredUserException e) {
|
} catch (UnregisteredUserException e) {
|
||||||
|
@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.loki.protocol
|
|||||||
|
|
||||||
import com.google.protobuf.ByteString
|
import com.google.protobuf.ByteString
|
||||||
import org.session.libsession.messaging.jobs.Data
|
import org.session.libsession.messaging.jobs.Data
|
||||||
|
import org.session.libsignal.libsignal.util.guava.Optional
|
||||||
import org.thoughtcrime.securesms.ApplicationContext
|
import org.thoughtcrime.securesms.ApplicationContext
|
||||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil
|
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil
|
||||||
import org.thoughtcrime.securesms.jobmanager.Job
|
import org.thoughtcrime.securesms.jobmanager.Job
|
||||||
@ -128,7 +129,7 @@ class ClosedGroupUpdateMessageSendJob private constructor(parameters: Parameters
|
|||||||
// isClosedGroup can always be false as it's only used in the context of legacy closed groups
|
// isClosedGroup can always be false as it's only used in the context of legacy closed groups
|
||||||
messageSender.sendMessage(0, address, udAccess.get().targetUnidentifiedAccess,
|
messageSender.sendMessage(0, address, udAccess.get().targetUnidentifiedAccess,
|
||||||
Date().time, serializedContentMessage, false, ttl, false,
|
Date().time, serializedContentMessage, false, ttl, false,
|
||||||
useFallbackEncryption, false, false, false)
|
useFallbackEncryption, false, false, Optional.absent())
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.d("Loki", "Failed to send closed group update message to: $destination due to error: $e.")
|
Log.d("Loki", "Failed to send closed group update message to: $destination due to error: $e.")
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import org.session.libsession.messaging.jobs.Data
|
|||||||
import org.session.libsignal.libsignal.ecc.DjbECPrivateKey
|
import org.session.libsignal.libsignal.ecc.DjbECPrivateKey
|
||||||
import org.session.libsignal.libsignal.ecc.DjbECPublicKey
|
import org.session.libsignal.libsignal.ecc.DjbECPublicKey
|
||||||
import org.session.libsignal.libsignal.ecc.ECKeyPair
|
import org.session.libsignal.libsignal.ecc.ECKeyPair
|
||||||
|
import org.session.libsignal.libsignal.util.guava.Optional
|
||||||
import org.session.libsignal.service.api.push.SignalServiceAddress
|
import org.session.libsignal.service.api.push.SignalServiceAddress
|
||||||
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
||||||
import org.session.libsignal.service.loki.protocol.meta.TTLUtilities
|
import org.session.libsignal.service.loki.protocol.meta.TTLUtilities
|
||||||
@ -221,7 +222,7 @@ class ClosedGroupUpdateMessageSendJobV2 private constructor(parameters: Paramete
|
|||||||
// isClosedGroup can always be false as it's only used in the context of legacy closed groups
|
// isClosedGroup can always be false as it's only used in the context of legacy closed groups
|
||||||
messageSender.sendMessage(0, address, udAccess.get().targetUnidentifiedAccess,
|
messageSender.sendMessage(0, address, udAccess.get().targetUnidentifiedAccess,
|
||||||
Date().time, serializedContentMessage, false, ttl, false,
|
Date().time, serializedContentMessage, false, ttl, false,
|
||||||
true, false, false, false)
|
true, false, false, Optional.absent())
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.d("Loki", "Failed to send closed group update message to: $destination due to error: $e.")
|
Log.d("Loki", "Failed to send closed group update message to: $destination due to error: $e.")
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint
|
|||||||
import org.thoughtcrime.securesms.jobs.BaseJob
|
import org.thoughtcrime.securesms.jobs.BaseJob
|
||||||
import org.session.libsignal.utilities.logging.Log
|
import org.session.libsignal.utilities.logging.Log
|
||||||
import org.session.libsession.messaging.threads.recipients.Recipient
|
import org.session.libsession.messaging.threads.recipients.Recipient
|
||||||
|
import org.session.libsignal.libsignal.util.guava.Optional
|
||||||
import org.session.libsignal.service.api.push.SignalServiceAddress
|
import org.session.libsignal.service.api.push.SignalServiceAddress
|
||||||
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
||||||
import org.session.libsignal.service.loki.protocol.meta.TTLUtilities
|
import org.session.libsignal.service.loki.protocol.meta.TTLUtilities
|
||||||
@ -56,7 +57,7 @@ class NullMessageSendJob private constructor(parameters: Parameters, private val
|
|||||||
try {
|
try {
|
||||||
messageSender.sendMessage(0, address, udAccess.get().targetUnidentifiedAccess,
|
messageSender.sendMessage(0, address, udAccess.get().targetUnidentifiedAccess,
|
||||||
Date().time, serializedContentMessage, false, ttl, false,
|
Date().time, serializedContentMessage, false, ttl, false,
|
||||||
false, false, false, false)
|
false, false, false, Optional.absent())
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.d("Loki", "Failed to send null message to: $publicKey due to error: $e.")
|
Log.d("Loki", "Failed to send null message to: $publicKey due to error: $e.")
|
||||||
throw e
|
throw e
|
||||||
|
@ -6,12 +6,7 @@ public class IncomingEncryptedMessage extends IncomingTextMessage {
|
|||||||
super(base, newBody);
|
super(base, newBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IncomingTextMessage withMessageBody(String body) {
|
|
||||||
return new IncomingEncryptedMessage(this, body);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSecureMessage() {
|
public boolean isSecureMessage() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -10,12 +10,7 @@ public class IncomingEndSessionMessage extends IncomingTextMessage {
|
|||||||
super(base, newBody);
|
super(base, newBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IncomingEndSessionMessage withMessageBody(String messageBody) {
|
|
||||||
return new IncomingEndSessionMessage(this, messageBody);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEndSession() {
|
public boolean isEndSession() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -11,12 +11,7 @@ public class IncomingGroupMessage extends IncomingTextMessage {
|
|||||||
this.groupContext = groupContext;
|
this.groupContext = groupContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IncomingGroupMessage withMessageBody(String body) {
|
|
||||||
return new IncomingGroupMessage(this, groupContext, body);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isGroup() {
|
public boolean isGroup() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -9,12 +9,7 @@ public class IncomingPreKeyBundleMessage extends IncomingTextMessage {
|
|||||||
this.legacy = legacy;
|
this.legacy = legacy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IncomingPreKeyBundleMessage withMessageBody(String messageBody) {
|
|
||||||
return new IncomingPreKeyBundleMessage(this, messageBody, legacy);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isLegacyPreKeyBundle() {
|
public boolean isLegacyPreKeyBundle() {
|
||||||
return legacy;
|
return legacy;
|
||||||
}
|
}
|
||||||
|
@ -175,10 +175,6 @@ public class IncomingTextMessage implements Parcelable {
|
|||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IncomingTextMessage withMessageBody(String message) {
|
|
||||||
return new IncomingTextMessage(this, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Address getSender() {
|
public Address getSender() {
|
||||||
return sender;
|
return sender;
|
||||||
}
|
}
|
||||||
@ -250,7 +246,6 @@ public class IncomingTextMessage implements Parcelable {
|
|||||||
public boolean isUnidentified() {
|
public boolean isUnidentified() {
|
||||||
return unidentified;
|
return unidentified;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int describeContents() {
|
public int describeContents() {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -152,6 +152,7 @@ class Address private constructor(address: String) : Parcelable, Comparable<Addr
|
|||||||
val UNKNOWN = Address("Unknown")
|
val UNKNOWN = Address("Unknown")
|
||||||
private val TAG = Address::class.java.simpleName
|
private val TAG = Address::class.java.simpleName
|
||||||
private val cachedFormatter = AtomicReference<Pair<String, ExternalAddressFormatter>>()
|
private val cachedFormatter = AtomicReference<Pair<String, ExternalAddressFormatter>>()
|
||||||
|
@JvmStatic
|
||||||
fun fromSerialized(serialized: String): Address {
|
fun fromSerialized(serialized: String): Address {
|
||||||
return Address(serialized)
|
return Address(serialized)
|
||||||
}
|
}
|
||||||
|
@ -26,10 +26,6 @@ import org.session.libsignal.service.api.messages.SignalServiceDataMessage;
|
|||||||
import org.session.libsignal.service.api.messages.SignalServiceGroup;
|
import org.session.libsignal.service.api.messages.SignalServiceGroup;
|
||||||
import org.session.libsignal.service.api.messages.SignalServiceReceiptMessage;
|
import org.session.libsignal.service.api.messages.SignalServiceReceiptMessage;
|
||||||
import org.session.libsignal.service.api.messages.SignalServiceTypingMessage;
|
import org.session.libsignal.service.api.messages.SignalServiceTypingMessage;
|
||||||
import org.session.libsignal.service.api.messages.calls.AnswerMessage;
|
|
||||||
import org.session.libsignal.service.api.messages.calls.IceUpdateMessage;
|
|
||||||
import org.session.libsignal.service.api.messages.calls.OfferMessage;
|
|
||||||
import org.session.libsignal.service.api.messages.calls.SignalServiceCallMessage;
|
|
||||||
import org.session.libsignal.service.api.messages.multidevice.BlockedListMessage;
|
import org.session.libsignal.service.api.messages.multidevice.BlockedListMessage;
|
||||||
import org.session.libsignal.service.api.messages.multidevice.ConfigurationMessage;
|
import org.session.libsignal.service.api.messages.multidevice.ConfigurationMessage;
|
||||||
import org.session.libsignal.service.api.messages.multidevice.ReadMessage;
|
import org.session.libsignal.service.api.messages.multidevice.ReadMessage;
|
||||||
@ -51,7 +47,6 @@ import org.session.libsignal.service.internal.push.PushServiceSocket;
|
|||||||
import org.session.libsignal.service.internal.push.PushTransportDetails;
|
import org.session.libsignal.service.internal.push.PushTransportDetails;
|
||||||
import org.session.libsignal.service.internal.push.SignalServiceProtos;
|
import org.session.libsignal.service.internal.push.SignalServiceProtos;
|
||||||
import org.session.libsignal.service.internal.push.SignalServiceProtos.AttachmentPointer;
|
import org.session.libsignal.service.internal.push.SignalServiceProtos.AttachmentPointer;
|
||||||
import org.session.libsignal.service.internal.push.SignalServiceProtos.CallMessage;
|
|
||||||
import org.session.libsignal.service.internal.push.SignalServiceProtos.Content;
|
import org.session.libsignal.service.internal.push.SignalServiceProtos.Content;
|
||||||
import org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage;
|
import org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage;
|
||||||
import org.session.libsignal.service.internal.push.SignalServiceProtos.GroupContext;
|
import org.session.libsignal.service.internal.push.SignalServiceProtos.GroupContext;
|
||||||
@ -217,34 +212,14 @@ public class SignalServiceMessageSender {
|
|||||||
* @param recipient The sender of the received message you're acknowledging.
|
* @param recipient The sender of the received message you're acknowledging.
|
||||||
* @param message The read receipt to deliver.
|
* @param message The read receipt to deliver.
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
* @throws UntrustedIdentityException
|
|
||||||
*/
|
*/
|
||||||
public void sendReceipt(SignalServiceAddress recipient,
|
public void sendReceipt(SignalServiceAddress recipient,
|
||||||
Optional<UnidentifiedAccessPair> unidentifiedAccess,
|
Optional<UnidentifiedAccessPair> unidentifiedAccess,
|
||||||
SignalServiceReceiptMessage message)
|
SignalServiceReceiptMessage message)
|
||||||
throws IOException, UntrustedIdentityException
|
throws IOException {
|
||||||
{
|
|
||||||
byte[] content = createReceiptContent(message);
|
byte[] content = createReceiptContent(message);
|
||||||
boolean useFallbackEncryption = SessionManagementProtocol.shared.shouldMessageUseFallbackEncryption(message, recipient.getNumber(), store);
|
boolean useFallbackEncryption = SessionManagementProtocol.shared.shouldMessageUseFallbackEncryption(message, recipient.getNumber(), store);
|
||||||
sendMessage(recipient, getTargetUnidentifiedAccess(unidentifiedAccess), message.getWhen(), content, false, message.getTTL(), useFallbackEncryption, false);
|
sendMessage(recipient, getTargetUnidentifiedAccess(unidentifiedAccess), message.getWhen(), content, false, message.getTTL(), useFallbackEncryption);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a typing indicator.
|
|
||||||
*
|
|
||||||
* @param recipient The destination
|
|
||||||
* @param message The typing indicator to deliver
|
|
||||||
* @throws IOException
|
|
||||||
* @throws UntrustedIdentityException
|
|
||||||
*/
|
|
||||||
public void sendTyping(SignalServiceAddress recipient,
|
|
||||||
Optional<UnidentifiedAccessPair> unidentifiedAccess,
|
|
||||||
SignalServiceTypingMessage message)
|
|
||||||
throws IOException, UntrustedIdentityException
|
|
||||||
{
|
|
||||||
byte[] content = createTypingContent(message);
|
|
||||||
boolean useFallbackEncryption = SessionManagementProtocol.shared.shouldMessageUseFallbackEncryption(message, recipient.getNumber(), store);
|
|
||||||
sendMessage(recipient, getTargetUnidentifiedAccess(unidentifiedAccess), message.getTimestamp(), content, true, message.getTTL(), useFallbackEncryption, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendTyping(List<SignalServiceAddress> recipients,
|
public void sendTyping(List<SignalServiceAddress> recipients,
|
||||||
@ -256,42 +231,24 @@ public class SignalServiceMessageSender {
|
|||||||
sendMessage(0, recipients, getTargetUnidentifiedAccess(unidentifiedAccess), message.getTimestamp(), content, true, message.getTTL(), false, false);
|
sendMessage(0, recipients, getTargetUnidentifiedAccess(unidentifiedAccess), message.getTimestamp(), content, true, message.getTTL(), false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a call setup message to a single recipient.
|
|
||||||
*
|
|
||||||
* @param recipient The message's destination.
|
|
||||||
* @param message The call message.
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public void sendCallMessage(SignalServiceAddress recipient,
|
|
||||||
Optional<UnidentifiedAccessPair> unidentifiedAccess,
|
|
||||||
SignalServiceCallMessage message)
|
|
||||||
throws IOException, UntrustedIdentityException
|
|
||||||
{
|
|
||||||
byte[] content = createCallContent(message);
|
|
||||||
boolean useFallbackEncryption = SessionManagementProtocol.shared.shouldMessageUseFallbackEncryption(message, recipient.getNumber(), store);
|
|
||||||
sendMessage(recipient, getTargetUnidentifiedAccess(unidentifiedAccess), System.currentTimeMillis(), content, false, message.getTTL(), useFallbackEncryption, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a message to a single recipient.
|
* Send a message to a single recipient.
|
||||||
*
|
*
|
||||||
* @param recipient The message's destination.
|
* @param recipient The message's destination.
|
||||||
* @param message The message.
|
* @param message The message.
|
||||||
* @throws UntrustedIdentityException
|
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public SendMessageResult sendMessage(long messageID,
|
public SendMessageResult sendMessage(long messageID,
|
||||||
SignalServiceAddress recipient,
|
SignalServiceAddress recipient,
|
||||||
Optional<UnidentifiedAccessPair> unidentifiedAccess,
|
Optional<UnidentifiedAccessPair> unidentifiedAccess,
|
||||||
SignalServiceDataMessage message)
|
SignalServiceDataMessage message)
|
||||||
throws UntrustedIdentityException, IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
byte[] content = createMessageContent(message, recipient);
|
byte[] content = createMessageContent(message, recipient);
|
||||||
long timestamp = message.getTimestamp();
|
long timestamp = message.getTimestamp();
|
||||||
boolean useFallbackEncryption = SessionManagementProtocol.shared.shouldMessageUseFallbackEncryption(message, recipient.getNumber(), store);
|
boolean useFallbackEncryption = SessionManagementProtocol.shared.shouldMessageUseFallbackEncryption(message, recipient.getNumber(), store);
|
||||||
boolean isClosedGroup = message.group.isPresent() && message.group.get().getGroupType() == SignalServiceGroup.GroupType.SIGNAL;
|
boolean isClosedGroup = message.group.isPresent() && message.group.get().getGroupType() == SignalServiceGroup.GroupType.SIGNAL;
|
||||||
SendMessageResult result = sendMessage(messageID, recipient, getTargetUnidentifiedAccess(unidentifiedAccess), timestamp, content, false, message.getTTL(), message.getDeviceLink().isPresent(), useFallbackEncryption, isClosedGroup, false, message.hasVisibleContent());
|
SendMessageResult result = sendMessage(messageID, recipient, getTargetUnidentifiedAccess(unidentifiedAccess), timestamp, content, false, message.getTTL(), message.getDeviceLink().isPresent(), useFallbackEncryption, isClosedGroup, message.hasVisibleContent(), message.getSyncTarget());
|
||||||
|
|
||||||
// // Loki - This shouldn't get invoked for note to self
|
// // Loki - This shouldn't get invoked for note to self
|
||||||
// boolean wouldSignalSendSyncMessage = (result.getSuccess() != null && result.getSuccess().isNeedsSync()) || unidentifiedAccess.isPresent();
|
// boolean wouldSignalSendSyncMessage = (result.getSuccess() != null && result.getSuccess().isNeedsSync()) || unidentifiedAccess.isPresent();
|
||||||
@ -325,8 +282,7 @@ public class SignalServiceMessageSender {
|
|||||||
List<SignalServiceAddress> recipients,
|
List<SignalServiceAddress> recipients,
|
||||||
List<Optional<UnidentifiedAccessPair>> unidentifiedAccess,
|
List<Optional<UnidentifiedAccessPair>> unidentifiedAccess,
|
||||||
SignalServiceDataMessage message)
|
SignalServiceDataMessage message)
|
||||||
throws IOException, UntrustedIdentityException
|
throws IOException {
|
||||||
{
|
|
||||||
// Loki - We only need the first recipient in the line below. This is because the recipient is only used to determine
|
// Loki - We only need the first recipient in the line below. This is because the recipient is only used to determine
|
||||||
// whether an attachment is being sent to an open group or not.
|
// whether an attachment is being sent to an open group or not.
|
||||||
byte[] content = createMessageContent(message, recipients.get(0));
|
byte[] content = createMessageContent(message, recipients.get(0));
|
||||||
@ -350,7 +306,7 @@ public class SignalServiceMessageSender {
|
|||||||
for (String device : linkedDevices) {
|
for (String device : linkedDevices) {
|
||||||
SignalServiceAddress deviceAsAddress = new SignalServiceAddress(device);
|
SignalServiceAddress deviceAsAddress = new SignalServiceAddress(device);
|
||||||
boolean useFallbackEncryption = SessionManagementProtocol.shared.shouldMessageUseFallbackEncryption(syncMessage, device, store);
|
boolean useFallbackEncryption = SessionManagementProtocol.shared.shouldMessageUseFallbackEncryption(syncMessage, device, store);
|
||||||
sendMessage(deviceAsAddress, Optional.<UnidentifiedAccess>absent(), timestamp, syncMessage, false, message.getTTL(), useFallbackEncryption, true);
|
sendMessage(deviceAsAddress, Optional.<UnidentifiedAccess>absent(), timestamp, syncMessage, false, message.getTTL(), useFallbackEncryption);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -392,18 +348,10 @@ public class SignalServiceMessageSender {
|
|||||||
for (String device : linkedDevices) {
|
for (String device : linkedDevices) {
|
||||||
SignalServiceAddress deviceAsAddress = new SignalServiceAddress(device);
|
SignalServiceAddress deviceAsAddress = new SignalServiceAddress(device);
|
||||||
boolean useFallbackEncryption = SessionManagementProtocol.shared.shouldMessageUseFallbackEncryption(message, device, store);
|
boolean useFallbackEncryption = SessionManagementProtocol.shared.shouldMessageUseFallbackEncryption(message, device, store);
|
||||||
sendMessageToPrivateChat(0, deviceAsAddress, Optional.<UnidentifiedAccess>absent(), timestamp, content, false, message.getTTL(), useFallbackEncryption, false, false);
|
// sendMessageToPrivateChat(0, deviceAsAddress, Optional.<UnidentifiedAccess>absent(), timestamp, content, false, message.getTTL(), useFallbackEncryption, false, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSoTimeoutMillis(long soTimeoutMillis) {
|
|
||||||
socket.setSoTimeoutMillis(soTimeoutMillis);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void cancelInFlightRequests() {
|
|
||||||
socket.cancelInFlightRequests();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMessagePipe(SignalServiceMessagePipe pipe, SignalServiceMessagePipe unidentifiedPipe) {
|
public void setMessagePipe(SignalServiceMessagePipe pipe, SignalServiceMessagePipe unidentifiedPipe) {
|
||||||
this.pipe.set(Optional.fromNullable(pipe));
|
this.pipe.set(Optional.fromNullable(pipe));
|
||||||
this.unidentifiedPipe.set(Optional.fromNullable(unidentifiedPipe));
|
this.unidentifiedPipe.set(Optional.fromNullable(unidentifiedPipe));
|
||||||
@ -452,9 +400,7 @@ public class SignalServiceMessageSender {
|
|||||||
result.getUrl());
|
result.getUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendMessage(VerifiedMessage message, Optional<UnidentifiedAccessPair> unidentifiedAccess)
|
private void sendMessage(VerifiedMessage message, Optional<UnidentifiedAccessPair> unidentifiedAccess) {
|
||||||
throws IOException, UntrustedIdentityException
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -494,32 +440,6 @@ public class SignalServiceMessageSender {
|
|||||||
{
|
{
|
||||||
Content.Builder container = Content.newBuilder();
|
Content.Builder container = Content.newBuilder();
|
||||||
|
|
||||||
// if (message.getPreKeyBundle().isPresent()) {
|
|
||||||
// PreKeyBundle preKeyBundle = message.getPreKeyBundle().get();
|
|
||||||
// PreKeyBundleMessage.Builder preKeyBundleMessageBuilder = PreKeyBundleMessage.newBuilder()
|
|
||||||
// .setDeviceId(preKeyBundle.getDeviceId())
|
|
||||||
// .setIdentityKey(ByteString.copyFrom(preKeyBundle.getIdentityKey().serialize()))
|
|
||||||
// .setPreKeyId(preKeyBundle.getPreKeyId())
|
|
||||||
// .setPreKey(ByteString.copyFrom(preKeyBundle.getPreKey().serialize()))
|
|
||||||
// .setSignedKeyId(preKeyBundle.getSignedPreKeyId())
|
|
||||||
// .setSignedKey(ByteString.copyFrom(preKeyBundle.getSignedPreKey().serialize()))
|
|
||||||
// .setSignature(ByteString.copyFrom(preKeyBundle.getSignedPreKeySignature()))
|
|
||||||
// .setIdentityKey(ByteString.copyFrom(preKeyBundle.getIdentityKey().serialize()));
|
|
||||||
// container.setPreKeyBundleMessage(preKeyBundleMessageBuilder);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (message.getDeviceLink().isPresent()) {
|
|
||||||
// DeviceLink deviceLink = message.getDeviceLink().get();
|
|
||||||
// SignalServiceProtos.DeviceLinkMessage.Builder deviceLinkMessageBuilder = SignalServiceProtos.DeviceLinkMessage.newBuilder()
|
|
||||||
// .setPrimaryPublicKey(deviceLink.getMasterPublicKey())
|
|
||||||
// .setSecondaryPublicKey(deviceLink.getSlavePublicKey())
|
|
||||||
// .setRequestSignature(ByteString.copyFrom(Objects.requireNonNull(deviceLink.getRequestSignature())));
|
|
||||||
// if (deviceLink.getAuthorizationSignature() != null) {
|
|
||||||
// deviceLinkMessageBuilder.setAuthorizationSignature(ByteString.copyFrom(deviceLink.getAuthorizationSignature()));
|
|
||||||
// }
|
|
||||||
// container.setDeviceLinkMessage(deviceLinkMessageBuilder.build());
|
|
||||||
// }
|
|
||||||
|
|
||||||
DataMessage.Builder builder = DataMessage.newBuilder();
|
DataMessage.Builder builder = DataMessage.newBuilder();
|
||||||
List<AttachmentPointer> pointers = createAttachmentPointers(message.getAttachments(), recipient);
|
List<AttachmentPointer> pointers = createAttachmentPointers(message.getAttachments(), recipient);
|
||||||
|
|
||||||
@ -559,6 +479,10 @@ public class SignalServiceMessageSender {
|
|||||||
builder.setProfileKey(ByteString.copyFrom(message.getProfileKey().get()));
|
builder.setProfileKey(ByteString.copyFrom(message.getProfileKey().get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (message.getSyncTarget().isPresent()) {
|
||||||
|
builder.setSyncTarget(message.getSyncTarget().get());
|
||||||
|
}
|
||||||
|
|
||||||
if (message.getQuote().isPresent()) {
|
if (message.getQuote().isPresent()) {
|
||||||
DataMessage.Quote.Builder quoteBuilder = DataMessage.Quote.newBuilder()
|
DataMessage.Quote.Builder quoteBuilder = DataMessage.Quote.newBuilder()
|
||||||
.setId(message.getQuote().get().getId())
|
.setId(message.getQuote().get().getId())
|
||||||
@ -636,40 +560,6 @@ public class SignalServiceMessageSender {
|
|||||||
return container.build().toByteArray();
|
return container.build().toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] createCallContent(SignalServiceCallMessage callMessage) {
|
|
||||||
Content.Builder container = Content.newBuilder();
|
|
||||||
CallMessage.Builder builder = CallMessage.newBuilder();
|
|
||||||
|
|
||||||
if (callMessage.getOfferMessage().isPresent()) {
|
|
||||||
OfferMessage offer = callMessage.getOfferMessage().get();
|
|
||||||
builder.setOffer(CallMessage.Offer.newBuilder()
|
|
||||||
.setId(offer.getId())
|
|
||||||
.setDescription(offer.getDescription()));
|
|
||||||
} else if (callMessage.getAnswerMessage().isPresent()) {
|
|
||||||
AnswerMessage answer = callMessage.getAnswerMessage().get();
|
|
||||||
builder.setAnswer(CallMessage.Answer.newBuilder()
|
|
||||||
.setId(answer.getId())
|
|
||||||
.setDescription(answer.getDescription()));
|
|
||||||
} else if (callMessage.getIceUpdateMessages().isPresent()) {
|
|
||||||
List<IceUpdateMessage> updates = callMessage.getIceUpdateMessages().get();
|
|
||||||
|
|
||||||
for (IceUpdateMessage update : updates) {
|
|
||||||
builder.addIceUpdate(CallMessage.IceUpdate.newBuilder()
|
|
||||||
.setId(update.getId())
|
|
||||||
.setSdp(update.getSdp())
|
|
||||||
.setSdpMid(update.getSdpMid())
|
|
||||||
.setSdpMLineIndex(update.getSdpMLineIndex()));
|
|
||||||
}
|
|
||||||
} else if (callMessage.getHangupMessage().isPresent()) {
|
|
||||||
builder.setHangup(CallMessage.Hangup.newBuilder().setId(callMessage.getHangupMessage().get().getId()));
|
|
||||||
} else if (callMessage.getBusyMessage().isPresent()) {
|
|
||||||
builder.setBusy(CallMessage.Busy.newBuilder().setId(callMessage.getBusyMessage().get().getId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
container.setCallMessage(builder);
|
|
||||||
return container.build().toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] createMultiDeviceContactsContent(SignalServiceAttachmentStream contacts, boolean complete)
|
private byte[] createMultiDeviceContactsContent(SignalServiceAttachmentStream contacts, boolean complete)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
@ -987,6 +877,7 @@ public class SignalServiceMessageSender {
|
|||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
List<SendMessageResult> results = new LinkedList<>();
|
List<SendMessageResult> results = new LinkedList<>();
|
||||||
|
SignalServiceAddress ownAddress = localAddress;
|
||||||
Iterator<SignalServiceAddress> recipientIterator = recipients.iterator();
|
Iterator<SignalServiceAddress> recipientIterator = recipients.iterator();
|
||||||
Iterator<Optional<UnidentifiedAccess>> unidentifiedAccessIterator = unidentifiedAccess.iterator();
|
Iterator<Optional<UnidentifiedAccess>> unidentifiedAccessIterator = unidentifiedAccess.iterator();
|
||||||
|
|
||||||
@ -995,7 +886,7 @@ public class SignalServiceMessageSender {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
boolean useFallbackEncryption = SessionManagementProtocol.shared.shouldMessageUseFallbackEncryption(content, recipient.getNumber(), store);
|
boolean useFallbackEncryption = SessionManagementProtocol.shared.shouldMessageUseFallbackEncryption(content, recipient.getNumber(), store);
|
||||||
SendMessageResult result = sendMessage(messageID, recipient, unidentifiedAccessIterator.next(), timestamp, content, online, ttl, false, useFallbackEncryption, isClosedGroup, false, notifyPNServer);
|
SendMessageResult result = sendMessage(messageID, recipient, unidentifiedAccessIterator.next(), timestamp, content, online, ttl, false, useFallbackEncryption, isClosedGroup, notifyPNServer, Optional.absent());
|
||||||
results.add(result);
|
results.add(result);
|
||||||
} catch (UnregisteredUserException e) {
|
} catch (UnregisteredUserException e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
@ -1009,41 +900,46 @@ public class SignalServiceMessageSender {
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
private SendMessageResult sendMessage(SignalServiceAddress recipient,
|
private SendMessageResult sendMessage(SignalServiceAddress recipient,
|
||||||
Optional<UnidentifiedAccess> unidentifiedAccess,
|
Optional<UnidentifiedAccess> unidentifiedAccess,
|
||||||
long timestamp,
|
long timestamp,
|
||||||
byte[] content,
|
byte[] content,
|
||||||
boolean online,
|
boolean online,
|
||||||
int ttl,
|
int ttl,
|
||||||
boolean useFallbackEncryption,
|
boolean useFallbackEncryption)
|
||||||
boolean isSyncMessage)
|
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
// Loki - This method is only invoked for various types of control messages
|
// Loki - This method is only invoked for various types of control messages
|
||||||
return sendMessage(0, recipient, unidentifiedAccess, timestamp, content, online, ttl, false, false, useFallbackEncryption, isSyncMessage, false);
|
return sendMessage(0, recipient, unidentifiedAccess, timestamp, content, online, ttl, false, false, useFallbackEncryption, false,Optional.absent());
|
||||||
}
|
}
|
||||||
|
|
||||||
public SendMessageResult sendMessage(final long messageID,
|
public SendMessageResult sendMessage(final long messageID,
|
||||||
final SignalServiceAddress recipient,
|
final SignalServiceAddress recipient,
|
||||||
Optional<UnidentifiedAccess> unidentifiedAccess,
|
Optional<UnidentifiedAccess> unidentifiedAccess,
|
||||||
long timestamp,
|
long timestamp,
|
||||||
byte[] content,
|
byte[] content,
|
||||||
boolean online,
|
boolean online,
|
||||||
int ttl,
|
int ttl,
|
||||||
boolean isDeviceLinkMessage,
|
boolean isDeviceLinkMessage,
|
||||||
boolean useFallbackEncryption,
|
boolean useFallbackEncryption,
|
||||||
boolean isClosedGroup,
|
boolean isClosedGroup,
|
||||||
boolean isSyncMessage,
|
boolean notifyPNServer,
|
||||||
boolean notifyPNServer)
|
Optional<String> syncTarget)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
long threadID = threadDatabase.getThreadID(recipient.getNumber());
|
boolean isSelfSend = syncTarget.isPresent() && !syncTarget.get().isEmpty();
|
||||||
|
long threadID;
|
||||||
|
if (isSelfSend) {
|
||||||
|
threadID = threadDatabase.getThreadID(syncTarget.get());
|
||||||
|
} else {
|
||||||
|
threadID = threadDatabase.getThreadID(recipient.getNumber());
|
||||||
|
}
|
||||||
PublicChat publicChat = threadDatabase.getPublicChat(threadID);
|
PublicChat publicChat = threadDatabase.getPublicChat(threadID);
|
||||||
try {
|
try {
|
||||||
if (publicChat != null) {
|
if (publicChat != null) {
|
||||||
return sendMessageToPublicChat(messageID, recipient, timestamp, content, publicChat);
|
return sendMessageToPublicChat(messageID, recipient, timestamp, content, publicChat);
|
||||||
} else {
|
} else {
|
||||||
return sendMessageToPrivateChat(messageID, recipient, unidentifiedAccess, timestamp, content, online, ttl, useFallbackEncryption, isClosedGroup, notifyPNServer);
|
return sendMessageToPrivateChat(messageID, recipient, unidentifiedAccess, timestamp, content, online, ttl, useFallbackEncryption, isClosedGroup, notifyPNServer, syncTarget);
|
||||||
}
|
}
|
||||||
} catch (PushNetworkException e) {
|
} catch (PushNetworkException e) {
|
||||||
return SendMessageResult.networkFailure(recipient);
|
return SendMessageResult.networkFailure(recipient);
|
||||||
@ -1152,10 +1048,11 @@ public class SignalServiceMessageSender {
|
|||||||
int ttl,
|
int ttl,
|
||||||
boolean useFallbackEncryption,
|
boolean useFallbackEncryption,
|
||||||
boolean isClosedGroup,
|
boolean isClosedGroup,
|
||||||
final boolean notifyPNServer)
|
final boolean notifyPNServer,
|
||||||
|
Optional<String> syncTarget)
|
||||||
throws IOException, UntrustedIdentityException
|
throws IOException, UntrustedIdentityException
|
||||||
{
|
{
|
||||||
if (recipient.getNumber().equals(userPublicKey)) { return SendMessageResult.success(recipient, false, false); }
|
if (recipient.getNumber().equals(userPublicKey) && !syncTarget.isPresent()) { return SendMessageResult.success(recipient, false, false); }
|
||||||
final SettableFuture<?>[] future = { new SettableFuture<Unit>() };
|
final SettableFuture<?>[] future = { new SettableFuture<Unit>() };
|
||||||
OutgoingPushMessageList messages = getSessionProtocolEncryptedMessage(recipient, timestamp, content);
|
OutgoingPushMessageList messages = getSessionProtocolEncryptedMessage(recipient, timestamp, content);
|
||||||
// Loki - Remove this when we have shared sender keys
|
// Loki - Remove this when we have shared sender keys
|
||||||
@ -1221,14 +1118,10 @@ public class SignalServiceMessageSender {
|
|||||||
}
|
}
|
||||||
return Unit.INSTANCE;
|
return Unit.INSTANCE;
|
||||||
}
|
}
|
||||||
}).fail(new Function1<Exception, Unit>() {
|
}).fail(exception -> {
|
||||||
|
@SuppressWarnings("unchecked") SettableFuture<Unit> f = (SettableFuture<Unit>)future[0];
|
||||||
@Override
|
f.setException(exception);
|
||||||
public Unit invoke(Exception exception) {
|
return Unit.INSTANCE;
|
||||||
@SuppressWarnings("unchecked") SettableFuture<Unit> f = (SettableFuture<Unit>)future[0];
|
|
||||||
f.setException(exception);
|
|
||||||
return Unit.INSTANCE;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@SuppressWarnings("unchecked") SettableFuture<Unit> f = (SettableFuture<Unit>)future[0];
|
@SuppressWarnings("unchecked") SettableFuture<Unit> f = (SettableFuture<Unit>)future[0];
|
||||||
@ -1304,12 +1197,6 @@ public class SignalServiceMessageSender {
|
|||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private AttachmentPointer createAttachmentPointer(SignalServiceAttachmentStream attachment)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
return createAttachmentPointer(attachment, false, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private AttachmentPointer createAttachmentPointer(SignalServiceAttachmentStream attachment, SignalServiceAddress recipient)
|
private AttachmentPointer createAttachmentPointer(SignalServiceAttachmentStream attachment, SignalServiceAddress recipient)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
|
@ -389,6 +389,7 @@ public class SignalServiceCipher {
|
|||||||
ClosedGroupUpdate closedGroupUpdate = content.getClosedGroupUpdate();
|
ClosedGroupUpdate closedGroupUpdate = content.getClosedGroupUpdate();
|
||||||
ClosedGroupUpdateV2 closedGroupUpdateV2 = content.getClosedGroupUpdateV2();
|
ClosedGroupUpdateV2 closedGroupUpdateV2 = content.getClosedGroupUpdateV2();
|
||||||
boolean isDeviceUnlinkingRequest = ((content.getFlags() & DataMessage.Flags.DEVICE_UNLINKING_REQUEST_VALUE) != 0);
|
boolean isDeviceUnlinkingRequest = ((content.getFlags() & DataMessage.Flags.DEVICE_UNLINKING_REQUEST_VALUE) != 0);
|
||||||
|
String syncTarget = content.getSyncTarget();
|
||||||
|
|
||||||
for (AttachmentPointer pointer : content.getAttachmentsList()) {
|
for (AttachmentPointer pointer : content.getAttachmentsList()) {
|
||||||
attachments.add(createAttachmentPointer(pointer));
|
attachments.add(createAttachmentPointer(pointer));
|
||||||
@ -417,7 +418,8 @@ public class SignalServiceCipher {
|
|||||||
null,
|
null,
|
||||||
closedGroupUpdate,
|
closedGroupUpdate,
|
||||||
closedGroupUpdateV2,
|
closedGroupUpdateV2,
|
||||||
isDeviceUnlinkingRequest);
|
isDeviceUnlinkingRequest,
|
||||||
|
syncTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SignalServiceSyncMessage createSynchronizeMessage(Metadata metadata, SyncMessage content)
|
private SignalServiceSyncMessage createSynchronizeMessage(Metadata metadata, SyncMessage content)
|
||||||
|
@ -41,6 +41,7 @@ public class SignalServiceDataMessage {
|
|||||||
private final Optional<ClosedGroupUpdate> closedGroupUpdate;
|
private final Optional<ClosedGroupUpdate> closedGroupUpdate;
|
||||||
private final Optional<ClosedGroupUpdateV2> closedGroupUpdateV2;
|
private final Optional<ClosedGroupUpdateV2> closedGroupUpdateV2;
|
||||||
private final boolean isDeviceUnlinkingRequest;
|
private final boolean isDeviceUnlinkingRequest;
|
||||||
|
private final Optional<String> syncTarget;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a SignalServiceDataMessage with a body and no attachments.
|
* Construct a SignalServiceDataMessage with a body and no attachments.
|
||||||
@ -134,7 +135,7 @@ public class SignalServiceDataMessage {
|
|||||||
Quote quote, List<SharedContact> sharedContacts, List<Preview> previews,
|
Quote quote, List<SharedContact> sharedContacts, List<Preview> previews,
|
||||||
Sticker sticker)
|
Sticker sticker)
|
||||||
{
|
{
|
||||||
this(timestamp, group, attachments, body, endSession, expiresInSeconds, expirationUpdate, profileKey, profileKeyUpdate, quote, sharedContacts, previews, sticker, null, null, null, null, false);
|
this(timestamp, group, attachments, body, endSession, expiresInSeconds, expirationUpdate, profileKey, profileKeyUpdate, quote, sharedContacts, previews, sticker, null, null, null, null, false, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -155,7 +156,7 @@ public class SignalServiceDataMessage {
|
|||||||
Quote quote, List<SharedContact> sharedContacts, List<Preview> previews,
|
Quote quote, List<SharedContact> sharedContacts, List<Preview> previews,
|
||||||
Sticker sticker, PreKeyBundle preKeyBundle, DeviceLink deviceLink,
|
Sticker sticker, PreKeyBundle preKeyBundle, DeviceLink deviceLink,
|
||||||
ClosedGroupUpdate closedGroupUpdate, ClosedGroupUpdateV2 closedGroupUpdateV2,
|
ClosedGroupUpdate closedGroupUpdate, ClosedGroupUpdateV2 closedGroupUpdateV2,
|
||||||
boolean isDeviceUnlinkingRequest)
|
boolean isDeviceUnlinkingRequest, String syncTarget)
|
||||||
{
|
{
|
||||||
this.timestamp = timestamp;
|
this.timestamp = timestamp;
|
||||||
this.body = Optional.fromNullable(body);
|
this.body = Optional.fromNullable(body);
|
||||||
@ -172,6 +173,7 @@ public class SignalServiceDataMessage {
|
|||||||
this.closedGroupUpdate = Optional.fromNullable(closedGroupUpdate);
|
this.closedGroupUpdate = Optional.fromNullable(closedGroupUpdate);
|
||||||
this.closedGroupUpdateV2 = Optional.fromNullable(closedGroupUpdateV2);
|
this.closedGroupUpdateV2 = Optional.fromNullable(closedGroupUpdateV2);
|
||||||
this.isDeviceUnlinkingRequest = isDeviceUnlinkingRequest;
|
this.isDeviceUnlinkingRequest = isDeviceUnlinkingRequest;
|
||||||
|
this.syncTarget = Optional.fromNullable(syncTarget);
|
||||||
|
|
||||||
if (attachments != null && !attachments.isEmpty()) {
|
if (attachments != null && !attachments.isEmpty()) {
|
||||||
this.attachments = Optional.of(attachments);
|
this.attachments = Optional.of(attachments);
|
||||||
@ -250,6 +252,10 @@ public class SignalServiceDataMessage {
|
|||||||
return profileKey;
|
return profileKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Optional<String> getSyncTarget() {
|
||||||
|
return syncTarget;
|
||||||
|
}
|
||||||
|
|
||||||
public Optional<Quote> getQuote() {
|
public Optional<Quote> getQuote() {
|
||||||
return quote;
|
return quote;
|
||||||
}
|
}
|
||||||
@ -307,6 +313,7 @@ public class SignalServiceDataMessage {
|
|||||||
private Sticker sticker;
|
private Sticker sticker;
|
||||||
private PreKeyBundle preKeyBundle;
|
private PreKeyBundle preKeyBundle;
|
||||||
private DeviceLink deviceLink;
|
private DeviceLink deviceLink;
|
||||||
|
private String syncTarget;
|
||||||
private boolean isDeviceUnlinkingRequest;
|
private boolean isDeviceUnlinkingRequest;
|
||||||
|
|
||||||
private Builder() {}
|
private Builder() {}
|
||||||
@ -336,6 +343,11 @@ public class SignalServiceDataMessage {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Builder withSyncTarget(String syncTarget) {
|
||||||
|
this.syncTarget = syncTarget;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public Builder asEndSessionMessage() {
|
public Builder asEndSessionMessage() {
|
||||||
return asEndSessionMessage(true);
|
return asEndSessionMessage(true);
|
||||||
}
|
}
|
||||||
@ -417,7 +429,7 @@ public class SignalServiceDataMessage {
|
|||||||
profileKeyUpdate, quote, sharedContacts, previews,
|
profileKeyUpdate, quote, sharedContacts, previews,
|
||||||
sticker, preKeyBundle, deviceLink,
|
sticker, preKeyBundle, deviceLink,
|
||||||
null, null,
|
null, null,
|
||||||
isDeviceUnlinkingRequest);
|
isDeviceUnlinkingRequest, syncTarget);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user