use of org.thoughtcrime.securesms.recipients.RecipientId in project Signal-Android by WhisperSystems.
the class PushSendJob method getQuoteFor.
protected Optional<SignalServiceDataMessage.Quote> getQuoteFor(OutgoingMediaMessage message) throws IOException {
if (message.getOutgoingQuote() == null)
return Optional.absent();
long quoteId = message.getOutgoingQuote().getId();
String quoteBody = message.getOutgoingQuote().getText();
RecipientId quoteAuthor = message.getOutgoingQuote().getAuthor();
List<SignalServiceDataMessage.Mention> quoteMentions = getMentionsFor(message.getOutgoingQuote().getMentions());
List<SignalServiceDataMessage.Quote.QuotedAttachment> quoteAttachments = new LinkedList<>();
List<Attachment> filteredAttachments = Stream.of(message.getOutgoingQuote().getAttachments()).filterNot(a -> MediaUtil.isViewOnceType(a.getContentType())).toList();
for (Attachment attachment : filteredAttachments) {
BitmapUtil.ScaleResult thumbnailData = null;
SignalServiceAttachment thumbnail = null;
String thumbnailType = MediaUtil.IMAGE_JPEG;
try {
if (MediaUtil.isImageType(attachment.getContentType()) && attachment.getUri() != null) {
Bitmap.CompressFormat format = BitmapUtil.getCompressFormatForContentType(attachment.getContentType());
thumbnailData = BitmapUtil.createScaledBytes(context, new DecryptableStreamUriLoader.DecryptableUri(attachment.getUri()), 100, 100, 500 * 1024, format);
thumbnailType = attachment.getContentType();
} else if (Build.VERSION.SDK_INT >= 23 && MediaUtil.isVideoType(attachment.getContentType()) && attachment.getUri() != null) {
Bitmap bitmap = MediaUtil.getVideoThumbnail(context, attachment.getUri(), 1000);
if (bitmap != null) {
thumbnailData = BitmapUtil.createScaledBytes(context, bitmap, 100, 100, 500 * 1024);
}
}
if (thumbnailData != null) {
SignalServiceAttachment.Builder builder = SignalServiceAttachment.newStreamBuilder().withContentType(thumbnailType).withWidth(thumbnailData.getWidth()).withHeight(thumbnailData.getHeight()).withLength(thumbnailData.getBitmap().length).withStream(new ByteArrayInputStream(thumbnailData.getBitmap())).withResumableUploadSpec(ApplicationDependencies.getSignalServiceMessageSender().getResumableUploadSpec());
thumbnail = builder.build();
}
quoteAttachments.add(new SignalServiceDataMessage.Quote.QuotedAttachment(attachment.isVideoGif() ? MediaUtil.IMAGE_GIF : attachment.getContentType(), attachment.getFileName(), thumbnail));
} catch (BitmapDecodingException e) {
Log.w(TAG, e);
}
}
Recipient quoteAuthorRecipient = Recipient.resolved(quoteAuthor);
if (quoteAuthorRecipient.isMaybeRegistered()) {
SignalServiceAddress quoteAddress = RecipientUtil.toSignalServiceAddress(context, quoteAuthorRecipient);
return Optional.of(new SignalServiceDataMessage.Quote(quoteId, quoteAddress, quoteBody, quoteAttachments, quoteMentions));
} else {
return Optional.absent();
}
}
use of org.thoughtcrime.securesms.recipients.RecipientId in project Signal-Android by WhisperSystems.
the class ReactionSendJob method create.
@WorkerThread
@NonNull
public static ReactionSendJob create(@NonNull Context context, @NonNull MessageId messageId, @NonNull ReactionRecord reaction, boolean remove) throws NoSuchMessageException {
MessageRecord message = messageId.isMms() ? SignalDatabase.mms().getMessageRecord(messageId.getId()) : SignalDatabase.sms().getSmsMessage(messageId.getId());
Recipient conversationRecipient = SignalDatabase.threads().getRecipientForThreadId(message.getThreadId());
if (conversationRecipient == null) {
throw new AssertionError("We have a message, but couldn't find the thread!");
}
RecipientId selfId = Recipient.self().getId();
List<RecipientId> recipients = conversationRecipient.isGroup() ? RecipientUtil.getEligibleForSending(conversationRecipient.getParticipants()).stream().map(Recipient::getId).filter(r -> !r.equals(selfId)).collect(Collectors.toList()) : Collections.singletonList(conversationRecipient.getId());
return new ReactionSendJob(messageId, recipients, recipients.size(), reaction, remove, new Parameters.Builder().setQueue(conversationRecipient.getId().toQueueKey()).addConstraint(NetworkConstraint.KEY).setLifespan(TimeUnit.DAYS.toMillis(1)).setMaxAttempts(Parameters.UNLIMITED).build());
}
use of org.thoughtcrime.securesms.recipients.RecipientId in project Signal-Android by WhisperSystems.
the class PushGroupSendJob method onPushSend.
@Override
public void onPushSend() throws IOException, MmsException, NoSuchMessageException, RetryLaterException {
SignalLocalMetrics.GroupMessageSend.onJobStarted(messageId);
MessageDatabase database = SignalDatabase.mms();
OutgoingMediaMessage message = database.getOutgoingMessage(messageId);
long threadId = database.getMessageRecord(messageId).getThreadId();
Set<NetworkFailure> existingNetworkFailures = message.getNetworkFailures();
Set<IdentityKeyMismatch> existingIdentityMismatches = message.getIdentityKeyMismatches();
ApplicationDependencies.getJobManager().cancelAllInQueue(TypingSendJob.getQueue(threadId));
if (database.isSent(messageId)) {
log(TAG, String.valueOf(message.getSentTimeMillis()), "Message " + messageId + " was already sent. Ignoring.");
return;
}
Recipient groupRecipient = message.getRecipient().resolve();
if (!groupRecipient.isPushGroup()) {
throw new MmsException("Message recipient isn't a group!");
}
if (groupRecipient.isPushV1Group()) {
throw new MmsException("No GV1 messages can be sent anymore!");
}
try {
log(TAG, String.valueOf(message.getSentTimeMillis()), "Sending message: " + messageId + ", Recipient: " + message.getRecipient().getId() + ", Thread: " + threadId + ", Attachments: " + buildAttachmentString(message.getAttachments()));
if (!groupRecipient.resolve().isProfileSharing() && !database.isGroupQuitMessage(messageId)) {
RecipientUtil.shareProfileIfFirstSecureMessage(context, groupRecipient);
}
List<Recipient> target;
if (filterRecipient != null)
target = Collections.singletonList(Recipient.resolved(filterRecipient));
else if (!existingNetworkFailures.isEmpty())
target = Stream.of(existingNetworkFailures).map(nf -> nf.getRecipientId(context)).distinct().map(Recipient::resolved).toList();
else
target = Stream.of(getGroupMessageRecipients(groupRecipient.requireGroupId(), messageId)).distinctBy(Recipient::getId).toList();
RecipientAccessList accessList = new RecipientAccessList(target);
List<SendMessageResult> results = deliver(message, groupRecipient, target);
Log.i(TAG, JobLogger.format(this, "Finished send."));
List<NetworkFailure> networkFailures = Stream.of(results).filter(SendMessageResult::isNetworkFailure).map(result -> new NetworkFailure(accessList.requireIdByAddress(result.getAddress()))).toList();
List<IdentityKeyMismatch> identityMismatches = Stream.of(results).filter(result -> result.getIdentityFailure() != null).map(result -> new IdentityKeyMismatch(accessList.requireIdByAddress(result.getAddress()), result.getIdentityFailure().getIdentityKey())).toList();
ProofRequiredException proofRequired = Stream.of(results).filter(r -> r.getProofRequiredFailure() != null).findLast().map(SendMessageResult::getProofRequiredFailure).orElse(null);
List<SendMessageResult> successes = Stream.of(results).filter(result -> result.getSuccess() != null).toList();
List<Pair<RecipientId, Boolean>> successUnidentifiedStatus = Stream.of(successes).map(result -> new Pair<>(accessList.requireIdByAddress(result.getAddress()), result.getSuccess().isUnidentified())).toList();
Set<RecipientId> successIds = Stream.of(successUnidentifiedStatus).map(Pair::first).collect(Collectors.toSet());
List<NetworkFailure> resolvedNetworkFailures = Stream.of(existingNetworkFailures).filter(failure -> successIds.contains(failure.getRecipientId(context))).toList();
List<IdentityKeyMismatch> resolvedIdentityFailures = Stream.of(existingIdentityMismatches).filter(failure -> successIds.contains(failure.getRecipientId(context))).toList();
List<RecipientId> unregisteredRecipients = Stream.of(results).filter(SendMessageResult::isUnregisteredFailure).map(result -> RecipientId.from(result.getAddress())).toList();
if (networkFailures.size() > 0 || identityMismatches.size() > 0 || proofRequired != null || unregisteredRecipients.size() > 0) {
Log.w(TAG, String.format(Locale.US, "Failed to send to some recipients. Network: %d, Identity: %d, ProofRequired: %s, Unregistered: %d", networkFailures.size(), identityMismatches.size(), proofRequired != null, unregisteredRecipients.size()));
}
RecipientDatabase recipientDatabase = SignalDatabase.recipients();
for (RecipientId unregistered : unregisteredRecipients) {
recipientDatabase.markUnregistered(unregistered);
}
existingNetworkFailures.removeAll(resolvedNetworkFailures);
existingNetworkFailures.addAll(networkFailures);
database.setNetworkFailures(messageId, existingNetworkFailures);
existingIdentityMismatches.removeAll(resolvedIdentityFailures);
existingIdentityMismatches.addAll(identityMismatches);
database.setMismatchedIdentities(messageId, existingIdentityMismatches);
SignalDatabase.groupReceipts().setUnidentified(successUnidentifiedStatus, messageId);
if (proofRequired != null) {
handleProofRequiredException(proofRequired, groupRecipient, threadId, messageId, true);
}
if (existingNetworkFailures.isEmpty() && networkFailures.isEmpty() && identityMismatches.isEmpty() && existingIdentityMismatches.isEmpty()) {
database.markAsSent(messageId, true);
markAttachmentsUploaded(messageId, message);
if (message.getExpiresIn() > 0 && !message.isExpirationUpdate()) {
database.markExpireStarted(messageId);
ApplicationDependencies.getExpiringMessageManager().scheduleDeletion(messageId, true, message.getExpiresIn());
}
if (message.isViewOnce()) {
SignalDatabase.attachments().deleteAttachmentFilesForViewOnceMessage(messageId);
}
} else if (!identityMismatches.isEmpty()) {
Log.w(TAG, "Failing because there were " + identityMismatches.size() + " identity mismatches.");
database.markAsSentFailed(messageId);
notifyMediaMessageDeliveryFailed(context, messageId);
Set<RecipientId> mismatchRecipientIds = Stream.of(identityMismatches).map(mismatch -> mismatch.getRecipientId(context)).collect(Collectors.toSet());
RetrieveProfileJob.enqueue(mismatchRecipientIds);
} else if (!networkFailures.isEmpty()) {
Log.w(TAG, "Retrying because there were " + networkFailures.size() + " network failures.");
throw new RetryLaterException();
}
} catch (UntrustedIdentityException | UndeliverableMessageException e) {
warn(TAG, String.valueOf(message.getSentTimeMillis()), e);
database.markAsSentFailed(messageId);
notifyMediaMessageDeliveryFailed(context, messageId);
}
SignalLocalMetrics.GroupMessageSend.onJobFinished(messageId);
}
use of org.thoughtcrime.securesms.recipients.RecipientId in project Signal-Android by WhisperSystems.
the class PushGroupUpdateJob method onRun.
@Override
public void onRun() throws IOException, UntrustedIdentityException {
if (!Recipient.self().isRegistered()) {
throw new NotPushRegisteredException();
}
Recipient sourceRecipient = Recipient.resolved(source);
if (sourceRecipient.isUnregistered()) {
Log.w(TAG, sourceRecipient.getId() + " not registered!");
return;
}
GroupDatabase groupDatabase = SignalDatabase.groups();
Optional<GroupRecord> record = groupDatabase.getGroup(groupId);
SignalServiceAttachment avatar = null;
if (record == null || !record.isPresent()) {
Log.w(TAG, "No information for group record info request: " + groupId.toString());
return;
}
if (AvatarHelper.hasAvatar(context, record.get().getRecipientId())) {
avatar = SignalServiceAttachmentStream.newStreamBuilder().withContentType("image/jpeg").withStream(AvatarHelper.getAvatar(context, record.get().getRecipientId())).withLength(AvatarHelper.getAvatarLength(context, record.get().getRecipientId())).build();
}
List<SignalServiceAddress> members = new LinkedList<>();
for (RecipientId member : record.get().getMembers()) {
Recipient recipient = Recipient.resolved(member);
if (recipient.isMaybeRegistered()) {
members.add(RecipientUtil.toSignalServiceAddress(context, recipient));
}
}
SignalServiceGroup groupContext = SignalServiceGroup.newBuilder(Type.UPDATE).withAvatar(avatar).withId(groupId.getDecodedId()).withMembers(members).withName(record.get().getTitle()).build();
RecipientId groupRecipientId = SignalDatabase.recipients().getOrInsertFromGroupId(groupId);
Recipient groupRecipient = Recipient.resolved(groupRecipientId);
SignalServiceDataMessage message = SignalServiceDataMessage.newBuilder().asGroupMessage(groupContext).withTimestamp(System.currentTimeMillis()).withExpiration(groupRecipient.getExpiresInSeconds()).build();
SignalServiceMessageSender messageSender = ApplicationDependencies.getSignalServiceMessageSender();
messageSender.sendDataMessage(RecipientUtil.toSignalServiceAddress(context, sourceRecipient), UnidentifiedAccessUtil.getAccessFor(context, sourceRecipient), ContentHint.DEFAULT, message, IndividualSendEvents.EMPTY);
}
use of org.thoughtcrime.securesms.recipients.RecipientId in project Signal-Android by WhisperSystems.
the class MmsDownloadJob method storeRetrievedMms.
private void storeRetrievedMms(String contentLocation, long messageId, long threadId, RetrieveConf retrieved, int subscriptionId, @Nullable RecipientId notificationFrom) throws MmsException {
MessageDatabase database = SignalDatabase.mms();
Optional<GroupId> group = Optional.absent();
Set<RecipientId> members = new HashSet<>();
String body = null;
List<Attachment> attachments = new LinkedList<>();
List<Contact> sharedContacts = new LinkedList<>();
RecipientId from = null;
if (retrieved.getFrom() != null) {
from = Recipient.external(context, Util.toIsoString(retrieved.getFrom().getTextString())).getId();
} else if (notificationFrom != null) {
from = notificationFrom;
}
if (retrieved.getTo() != null) {
for (EncodedStringValue toValue : retrieved.getTo()) {
members.add(Recipient.external(context, Util.toIsoString(toValue.getTextString())).getId());
}
}
if (retrieved.getCc() != null) {
for (EncodedStringValue ccValue : retrieved.getCc()) {
members.add(Recipient.external(context, Util.toIsoString(ccValue.getTextString())).getId());
}
}
if (from != null) {
members.add(from);
}
members.add(Recipient.self().getId());
if (retrieved.getBody() != null) {
body = PartParser.getMessageText(retrieved.getBody());
PduBody media = PartParser.getSupportedMediaParts(retrieved.getBody());
for (int i = 0; i < media.getPartsNum(); i++) {
PduPart part = media.getPart(i);
if (part.getData() != null) {
if (Util.toIsoString(part.getContentType()).toLowerCase().equals(MediaUtil.VCARD)) {
sharedContacts.addAll(VCardUtil.parseContacts(new String(part.getData())));
} else {
Uri uri = BlobProvider.getInstance().forData(part.getData()).createForSingleUseInMemory();
String name = null;
if (part.getName() != null)
name = Util.toIsoString(part.getName());
attachments.add(new UriAttachment(uri, Util.toIsoString(part.getContentType()), AttachmentDatabase.TRANSFER_PROGRESS_DONE, part.getData().length, name, false, false, false, false, null, null, null, null, null));
}
}
}
}
if (members.size() > 2) {
List<RecipientId> recipients = new ArrayList<>(members);
group = Optional.of(SignalDatabase.groups().getOrCreateMmsGroupForMembers(recipients));
}
IncomingMediaMessage message = new IncomingMediaMessage(from, group, body, TimeUnit.SECONDS.toMillis(retrieved.getDate()), -1, System.currentTimeMillis(), attachments, subscriptionId, 0, false, false, false, Optional.of(sharedContacts));
Optional<InsertResult> insertResult = database.insertMessageInbox(message, contentLocation, threadId);
if (insertResult.isPresent()) {
database.deleteMessage(messageId);
ApplicationDependencies.getMessageNotifier().updateNotification(context, insertResult.get().getThreadId());
}
}
Aggregations