Search in sources :

Example 1 with OutgoingGroupUpdateMessage

use of org.thoughtcrime.securesms.mms.OutgoingGroupUpdateMessage in project Signal-Android by WhisperSystems.

the class MmsDatabase method getOutgoingMessage.

@Override
public OutgoingMediaMessage getOutgoingMessage(long messageId) throws MmsException, NoSuchMessageException {
    AttachmentDatabase attachmentDatabase = SignalDatabase.attachments();
    MentionDatabase mentionDatabase = SignalDatabase.mentions();
    Cursor cursor = null;
    try {
        cursor = rawQuery(RAW_ID_WHERE, new String[] { String.valueOf(messageId) });
        if (cursor != null && cursor.moveToNext()) {
            List<DatabaseAttachment> associatedAttachments = attachmentDatabase.getAttachmentsForMessage(messageId);
            List<Mention> mentions = mentionDatabase.getMentionsForMessage(messageId);
            long outboxType = cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX));
            String body = cursor.getString(cursor.getColumnIndexOrThrow(BODY));
            long timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(NORMALIZED_DATE_SENT));
            int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SUBSCRIPTION_ID));
            long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN));
            boolean viewOnce = cursor.getLong(cursor.getColumnIndexOrThrow(VIEW_ONCE)) == 1;
            long recipientId = cursor.getLong(cursor.getColumnIndexOrThrow(RECIPIENT_ID));
            long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
            int distributionType = SignalDatabase.threads().getDistributionType(threadId);
            String mismatchDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.MISMATCHED_IDENTITIES));
            String networkDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.NETWORK_FAILURE));
            long quoteId = cursor.getLong(cursor.getColumnIndexOrThrow(QUOTE_ID));
            long quoteAuthor = cursor.getLong(cursor.getColumnIndexOrThrow(QUOTE_AUTHOR));
            String quoteText = cursor.getString(cursor.getColumnIndexOrThrow(QUOTE_BODY));
            boolean quoteMissing = cursor.getInt(cursor.getColumnIndexOrThrow(QUOTE_MISSING)) == 1;
            List<Attachment> quoteAttachments = Stream.of(associatedAttachments).filter(Attachment::isQuote).map(a -> (Attachment) a).toList();
            List<Mention> quoteMentions = parseQuoteMentions(context, cursor);
            List<Contact> contacts = getSharedContacts(cursor, associatedAttachments);
            Set<Attachment> contactAttachments = new HashSet<>(Stream.of(contacts).map(Contact::getAvatarAttachment).filter(a -> a != null).toList());
            List<LinkPreview> previews = getLinkPreviews(cursor, associatedAttachments);
            Set<Attachment> previewAttachments = Stream.of(previews).filter(lp -> lp.getThumbnail().isPresent()).map(lp -> lp.getThumbnail().get()).collect(Collectors.toSet());
            List<Attachment> attachments = Stream.of(associatedAttachments).filterNot(Attachment::isQuote).filterNot(contactAttachments::contains).filterNot(previewAttachments::contains).sorted(new DatabaseAttachment.DisplayOrderComparator()).map(a -> (Attachment) a).toList();
            Recipient recipient = Recipient.resolved(RecipientId.from(recipientId));
            Set<NetworkFailure> networkFailures = new HashSet<>();
            Set<IdentityKeyMismatch> mismatches = new HashSet<>();
            QuoteModel quote = null;
            if (quoteId > 0 && quoteAuthor > 0 && (!TextUtils.isEmpty(quoteText) || !quoteAttachments.isEmpty())) {
                quote = new QuoteModel(quoteId, RecipientId.from(quoteAuthor), quoteText, quoteMissing, quoteAttachments, quoteMentions);
            }
            if (!TextUtils.isEmpty(mismatchDocument)) {
                try {
                    mismatches = JsonUtils.fromJson(mismatchDocument, IdentityKeyMismatchSet.class).getItems();
                } catch (IOException e) {
                    Log.w(TAG, e);
                }
            }
            if (!TextUtils.isEmpty(networkDocument)) {
                try {
                    networkFailures = JsonUtils.fromJson(networkDocument, NetworkFailureSet.class).getItems();
                } catch (IOException e) {
                    Log.w(TAG, e);
                }
            }
            if (body != null && (Types.isGroupQuit(outboxType) || Types.isGroupUpdate(outboxType))) {
                return new OutgoingGroupUpdateMessage(recipient, new MessageGroupContext(body, Types.isGroupV2(outboxType)), attachments, timestamp, 0, false, quote, contacts, previews, mentions);
            } else if (Types.isExpirationTimerUpdate(outboxType)) {
                return new OutgoingExpirationUpdateMessage(recipient, timestamp, expiresIn);
            }
            OutgoingMediaMessage message = new OutgoingMediaMessage(recipient, body, attachments, timestamp, subscriptionId, expiresIn, viewOnce, distributionType, quote, contacts, previews, mentions, networkFailures, mismatches);
            if (Types.isSecureType(outboxType)) {
                return new OutgoingSecureMediaMessage(message);
            }
            return message;
        }
        throw new NoSuchMessageException("No record found for id: " + messageId);
    } catch (IOException e) {
        throw new MmsException(e);
    } finally {
        if (cursor != null)
            cursor.close();
    }
}
Also used : SignalStore(org.thoughtcrime.securesms.keyvalue.SignalStore) SlideDeck(org.thoughtcrime.securesms.mms.SlideDeck) GroupMigrationMembershipChange(org.thoughtcrime.securesms.groups.GroupMigrationMembershipChange) LinkPreview(org.thoughtcrime.securesms.linkpreview.LinkPreview) NonNull(androidx.annotation.NonNull) Avatar(org.thoughtcrime.securesms.contactshare.Contact.Avatar) MessageGroupContext(org.thoughtcrime.securesms.mms.MessageGroupContext) Mention(org.thoughtcrime.securesms.database.model.Mention) MessageRecord(org.thoughtcrime.securesms.database.model.MessageRecord) SecureRandom(java.security.SecureRandom) JSONException(org.json.JSONException) JsonUtils(org.thoughtcrime.securesms.util.JsonUtils) JSONObject(org.json.JSONObject) RecipientId(org.thoughtcrime.securesms.recipients.RecipientId) BodyRangeList(org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList) SqlUtil(org.thoughtcrime.securesms.util.SqlUtil) IdentityKeyMismatchSet(org.thoughtcrime.securesms.database.documents.IdentityKeyMismatchSet) Map(java.util.Map) ViewOnceUtil(org.thoughtcrime.securesms.revealable.ViewOnceUtil) Recipient(org.thoughtcrime.securesms.recipients.Recipient) OutgoingTextMessage(org.thoughtcrime.securesms.sms.OutgoingTextMessage) OutgoingGroupUpdateMessage(org.thoughtcrime.securesms.mms.OutgoingGroupUpdateMessage) InvalidProtocolBufferException(com.google.protobuf.InvalidProtocolBufferException) NotificationInd(com.google.android.mms.pdu_alt.NotificationInd) ACI(org.whispersystems.signalservice.api.push.ACI) ApplicationDependencies(org.thoughtcrime.securesms.dependencies.ApplicationDependencies) Collection(java.util.Collection) OutgoingSecureMediaMessage(org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage) Set(java.util.Set) UUID(java.util.UUID) OutgoingExpirationUpdateMessage(org.thoughtcrime.securesms.mms.OutgoingExpirationUpdateMessage) Log(org.signal.core.util.logging.Log) NetworkFailureSet(org.thoughtcrime.securesms.database.documents.NetworkFailureSet) List(java.util.List) Nullable(androidx.annotation.Nullable) ContentValues(android.content.ContentValues) IncomingTextMessage(org.thoughtcrime.securesms.sms.IncomingTextMessage) Attachment(org.thoughtcrime.securesms.attachments.Attachment) OutgoingMediaMessage(org.thoughtcrime.securesms.mms.OutgoingMediaMessage) MediaUtil(org.thoughtcrime.securesms.util.MediaUtil) Context(android.content.Context) Stream(com.annimon.stream.Stream) Util(org.thoughtcrime.securesms.util.Util) HashMap(java.util.HashMap) SQLiteStatement(net.zetetic.database.sqlcipher.SQLiteStatement) DatabaseAttachment(org.thoughtcrime.securesms.attachments.DatabaseAttachment) ArrayList(java.util.ArrayList) TextSecurePreferences(org.thoughtcrime.securesms.util.TextSecurePreferences) HashSet(java.util.HashSet) Pair(org.whispersystems.libsignal.util.Pair) MmsNotificationAttachment(org.thoughtcrime.securesms.attachments.MmsNotificationAttachment) NotificationMmsMessageRecord(org.thoughtcrime.securesms.database.model.NotificationMmsMessageRecord) QuoteModel(org.thoughtcrime.securesms.mms.QuoteModel) MediaMmsMessageRecord(org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord) LinkedList(java.util.LinkedList) PduHeaders(com.google.android.mms.pdu_alt.PduHeaders) Cursor(android.database.Cursor) MessageId(org.thoughtcrime.securesms.database.model.MessageId) Collectors(com.annimon.stream.Collectors) Contact(org.thoughtcrime.securesms.contactshare.Contact) IdentityKeyMismatch(org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch) MmsException(org.thoughtcrime.securesms.mms.MmsException) TextUtils(android.text.TextUtils) IOException(java.io.IOException) Quote(org.thoughtcrime.securesms.database.model.Quote) Optional(org.whispersystems.libsignal.util.guava.Optional) CursorUtil(org.thoughtcrime.securesms.util.CursorUtil) ViewOnceExpirationInfo(org.thoughtcrime.securesms.revealable.ViewOnceExpirationInfo) AttachmentId(org.thoughtcrime.securesms.attachments.AttachmentId) NetworkFailure(org.thoughtcrime.securesms.database.documents.NetworkFailure) TrimThreadJob(org.thoughtcrime.securesms.jobs.TrimThreadJob) SmsMessageRecord(org.thoughtcrime.securesms.database.model.SmsMessageRecord) Collections(java.util.Collections) JSONArray(org.json.JSONArray) IncomingMediaMessage(org.thoughtcrime.securesms.mms.IncomingMediaMessage) LinkPreview(org.thoughtcrime.securesms.linkpreview.LinkPreview) Attachment(org.thoughtcrime.securesms.attachments.Attachment) DatabaseAttachment(org.thoughtcrime.securesms.attachments.DatabaseAttachment) MmsNotificationAttachment(org.thoughtcrime.securesms.attachments.MmsNotificationAttachment) OutgoingMediaMessage(org.thoughtcrime.securesms.mms.OutgoingMediaMessage) Cursor(android.database.Cursor) OutgoingGroupUpdateMessage(org.thoughtcrime.securesms.mms.OutgoingGroupUpdateMessage) MmsException(org.thoughtcrime.securesms.mms.MmsException) MessageGroupContext(org.thoughtcrime.securesms.mms.MessageGroupContext) Mention(org.thoughtcrime.securesms.database.model.Mention) HashSet(java.util.HashSet) DatabaseAttachment(org.thoughtcrime.securesms.attachments.DatabaseAttachment) Recipient(org.thoughtcrime.securesms.recipients.Recipient) NetworkFailure(org.thoughtcrime.securesms.database.documents.NetworkFailure) IdentityKeyMismatch(org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch) IOException(java.io.IOException) QuoteModel(org.thoughtcrime.securesms.mms.QuoteModel) Contact(org.thoughtcrime.securesms.contactshare.Contact) OutgoingSecureMediaMessage(org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage) OutgoingExpirationUpdateMessage(org.thoughtcrime.securesms.mms.OutgoingExpirationUpdateMessage)

Example 2 with OutgoingGroupUpdateMessage

use of org.thoughtcrime.securesms.mms.OutgoingGroupUpdateMessage in project Signal-Android by WhisperSystems.

the class MmsDatabase method insertMessageOutbox.

@Override
public long insertMessageOutbox(@NonNull OutgoingMediaMessage message, long threadId, boolean forceSms, int defaultReceiptStatus, @Nullable SmsDatabase.InsertListener insertListener) throws MmsException {
    SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
    long type = Types.BASE_SENDING_TYPE;
    if (message.isSecure())
        type |= (Types.SECURE_MESSAGE_BIT | Types.PUSH_MESSAGE_BIT);
    if (forceSms)
        type |= Types.MESSAGE_FORCE_SMS_BIT;
    if (message.isGroup()) {
        OutgoingGroupUpdateMessage outgoingGroupUpdateMessage = (OutgoingGroupUpdateMessage) message;
        if (outgoingGroupUpdateMessage.isV2Group()) {
            type |= Types.GROUP_V2_BIT | Types.GROUP_UPDATE_BIT;
            if (outgoingGroupUpdateMessage.isJustAGroupLeave()) {
                type |= Types.GROUP_LEAVE_BIT;
            }
        } else {
            MessageGroupContext.GroupV1Properties properties = outgoingGroupUpdateMessage.requireGroupV1Properties();
            if (properties.isUpdate())
                type |= Types.GROUP_UPDATE_BIT;
            else if (properties.isQuit())
                type |= Types.GROUP_LEAVE_BIT;
        }
    }
    if (message.isExpirationUpdate()) {
        type |= Types.EXPIRATION_TIMER_UPDATE_BIT;
    }
    Map<RecipientId, EarlyReceiptCache.Receipt> earlyDeliveryReceipts = earlyDeliveryReceiptCache.remove(message.getSentTimeMillis());
    ContentValues contentValues = new ContentValues();
    contentValues.put(DATE_SENT, message.getSentTimeMillis());
    contentValues.put(MESSAGE_TYPE, PduHeaders.MESSAGE_TYPE_SEND_REQ);
    contentValues.put(MESSAGE_BOX, type);
    contentValues.put(THREAD_ID, threadId);
    contentValues.put(READ, 1);
    contentValues.put(DATE_RECEIVED, System.currentTimeMillis());
    contentValues.put(SUBSCRIPTION_ID, message.getSubscriptionId());
    contentValues.put(EXPIRES_IN, message.getExpiresIn());
    contentValues.put(VIEW_ONCE, message.isViewOnce());
    contentValues.put(RECIPIENT_ID, message.getRecipient().getId().serialize());
    contentValues.put(DELIVERY_RECEIPT_COUNT, Stream.of(earlyDeliveryReceipts.values()).mapToLong(EarlyReceiptCache.Receipt::getCount).sum());
    contentValues.put(RECEIPT_TIMESTAMP, Stream.of(earlyDeliveryReceipts.values()).mapToLong(EarlyReceiptCache.Receipt::getTimestamp).max().orElse(-1));
    if (message.getRecipient().isSelf() && hasAudioAttachment(message.getAttachments())) {
        contentValues.put(VIEWED_RECEIPT_COUNT, 1L);
    }
    List<Attachment> quoteAttachments = new LinkedList<>();
    if (message.getOutgoingQuote() != null) {
        MentionUtil.UpdatedBodyAndMentions updated = MentionUtil.updateBodyAndMentionsWithPlaceholders(message.getOutgoingQuote().getText(), message.getOutgoingQuote().getMentions());
        contentValues.put(QUOTE_ID, message.getOutgoingQuote().getId());
        contentValues.put(QUOTE_AUTHOR, message.getOutgoingQuote().getAuthor().serialize());
        contentValues.put(QUOTE_BODY, updated.getBodyAsString());
        contentValues.put(QUOTE_MISSING, message.getOutgoingQuote().isOriginalMissing() ? 1 : 0);
        BodyRangeList mentionsList = MentionUtil.mentionsToBodyRangeList(updated.getMentions());
        if (mentionsList != null) {
            contentValues.put(QUOTE_MENTIONS, mentionsList.toByteArray());
        }
        quoteAttachments.addAll(message.getOutgoingQuote().getAttachments());
    }
    MentionUtil.UpdatedBodyAndMentions updatedBodyAndMentions = MentionUtil.updateBodyAndMentionsWithPlaceholders(message.getBody(), message.getMentions());
    long messageId = insertMediaMessage(threadId, updatedBodyAndMentions.getBodyAsString(), message.getAttachments(), quoteAttachments, message.getSharedContacts(), message.getLinkPreviews(), updatedBodyAndMentions.getMentions(), null, contentValues, insertListener, false);
    if (message.getRecipient().isGroup()) {
        OutgoingGroupUpdateMessage outgoingGroupUpdateMessage = (message instanceof OutgoingGroupUpdateMessage) ? (OutgoingGroupUpdateMessage) message : null;
        GroupReceiptDatabase receiptDatabase = SignalDatabase.groupReceipts();
        Set<RecipientId> members = new HashSet<>();
        if (outgoingGroupUpdateMessage != null && outgoingGroupUpdateMessage.isV2Group()) {
            MessageGroupContext.GroupV2Properties groupV2Properties = outgoingGroupUpdateMessage.requireGroupV2Properties();
            members.addAll(Stream.of(groupV2Properties.getAllActivePendingAndRemovedMembers()).distinct().map(uuid -> RecipientId.from(ACI.from(uuid), null)).toList());
            members.remove(Recipient.self().getId());
        } else {
            members.addAll(Stream.of(SignalDatabase.groups().getGroupMembers(message.getRecipient().requireGroupId(), GroupDatabase.MemberSet.FULL_MEMBERS_EXCLUDING_SELF)).map(Recipient::getId).toList());
        }
        receiptDatabase.insert(members, messageId, defaultReceiptStatus, message.getSentTimeMillis());
        for (RecipientId recipientId : earlyDeliveryReceipts.keySet()) {
            receiptDatabase.update(recipientId, messageId, GroupReceiptDatabase.STATUS_DELIVERED, -1);
        }
    }
    SignalDatabase.threads().updateLastSeenAndMarkSentAndLastScrolledSilenty(threadId);
    ApplicationDependencies.getDatabaseObserver().notifyMessageInsertObservers(threadId, new MessageId(messageId, true));
    notifyConversationListListeners();
    TrimThreadJob.enqueueAsync(threadId);
    return messageId;
}
Also used : ContentValues(android.content.ContentValues) RecipientId(org.thoughtcrime.securesms.recipients.RecipientId) BodyRangeList(org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList) Attachment(org.thoughtcrime.securesms.attachments.Attachment) DatabaseAttachment(org.thoughtcrime.securesms.attachments.DatabaseAttachment) MmsNotificationAttachment(org.thoughtcrime.securesms.attachments.MmsNotificationAttachment) Recipient(org.thoughtcrime.securesms.recipients.Recipient) OutgoingGroupUpdateMessage(org.thoughtcrime.securesms.mms.OutgoingGroupUpdateMessage) LinkedList(java.util.LinkedList) MessageGroupContext(org.thoughtcrime.securesms.mms.MessageGroupContext) HashSet(java.util.HashSet) MessageId(org.thoughtcrime.securesms.database.model.MessageId)

Example 3 with OutgoingGroupUpdateMessage

use of org.thoughtcrime.securesms.mms.OutgoingGroupUpdateMessage in project Signal-Android by WhisperSystems.

the class GroupV1MessageProcessor method storeMessage.

@Nullable
private static Long storeMessage(@NonNull Context context, @NonNull SignalServiceContent content, @NonNull SignalServiceGroup group, @NonNull GroupContext storage, boolean outgoing) {
    if (group.getAvatar().isPresent()) {
        ApplicationDependencies.getJobManager().add(new AvatarGroupsV1DownloadJob(GroupId.v1orThrow(group.getGroupId())));
    }
    try {
        if (outgoing) {
            MessageDatabase mmsDatabase = SignalDatabase.mms();
            RecipientId recipientId = SignalDatabase.recipients().getOrInsertFromGroupId(GroupId.v1orThrow(group.getGroupId()));
            Recipient recipient = Recipient.resolved(recipientId);
            OutgoingGroupUpdateMessage outgoingMessage = new OutgoingGroupUpdateMessage(recipient, storage, null, content.getTimestamp(), 0, false, null, Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
            long threadId = SignalDatabase.threads().getOrCreateThreadIdFor(recipient);
            long messageId = mmsDatabase.insertMessageOutbox(outgoingMessage, threadId, false, null);
            mmsDatabase.markAsSent(messageId, true);
            return threadId;
        } else {
            MessageDatabase smsDatabase = SignalDatabase.sms();
            String body = Base64.encodeBytes(storage.toByteArray());
            IncomingTextMessage incoming = new IncomingTextMessage(Recipient.externalHighTrustPush(context, content.getSender()).getId(), content.getSenderDevice(), content.getTimestamp(), content.getServerReceivedTimestamp(), System.currentTimeMillis(), body, Optional.of(GroupId.v1orThrow(group.getGroupId())), 0, content.isNeedsReceipt(), content.getServerUuid());
            IncomingGroupUpdateMessage groupMessage = new IncomingGroupUpdateMessage(incoming, storage, body);
            Optional<InsertResult> insertResult = smsDatabase.insertMessageInbox(groupMessage);
            if (insertResult.isPresent()) {
                ApplicationDependencies.getMessageNotifier().updateNotification(context, insertResult.get().getThreadId());
                return insertResult.get().getThreadId();
            } else {
                return null;
            }
        }
    } catch (MmsException e) {
        Log.w(TAG, e);
    }
    return null;
}
Also used : InsertResult(org.thoughtcrime.securesms.database.MessageDatabase.InsertResult) AvatarGroupsV1DownloadJob(org.thoughtcrime.securesms.jobs.AvatarGroupsV1DownloadJob) MessageDatabase(org.thoughtcrime.securesms.database.MessageDatabase) MmsException(org.thoughtcrime.securesms.mms.MmsException) RecipientId(org.thoughtcrime.securesms.recipients.RecipientId) IncomingGroupUpdateMessage(org.thoughtcrime.securesms.sms.IncomingGroupUpdateMessage) IncomingTextMessage(org.thoughtcrime.securesms.sms.IncomingTextMessage) Recipient(org.thoughtcrime.securesms.recipients.Recipient) ByteString(com.google.protobuf.ByteString) OutgoingGroupUpdateMessage(org.thoughtcrime.securesms.mms.OutgoingGroupUpdateMessage) Nullable(androidx.annotation.Nullable)

Example 4 with OutgoingGroupUpdateMessage

use of org.thoughtcrime.securesms.mms.OutgoingGroupUpdateMessage in project Signal-Android by WhisperSystems.

the class GroupManagerV1 method sendGroupUpdate.

private static GroupActionResult sendGroupUpdate(@NonNull Context context, @NonNull GroupId.V1 groupId, @NonNull Set<RecipientId> members, @Nullable String groupName, @Nullable byte[] avatar, int newMemberCount) {
    Attachment avatarAttachment = null;
    RecipientId groupRecipientId = SignalDatabase.recipients().getOrInsertFromGroupId(groupId);
    Recipient groupRecipient = Recipient.resolved(groupRecipientId);
    List<GroupContext.Member> uuidMembers = new ArrayList<>(members.size());
    List<String> e164Members = new ArrayList<>(members.size());
    for (RecipientId member : members) {
        Recipient recipient = Recipient.resolved(member);
        if (recipient.hasE164()) {
            e164Members.add(recipient.requireE164());
            uuidMembers.add(GroupV1MessageProcessor.createMember(recipient.requireE164()));
        }
    }
    GroupContext.Builder groupContextBuilder = GroupContext.newBuilder().setId(ByteString.copyFrom(groupId.getDecodedId())).setType(GroupContext.Type.UPDATE).addAllMembersE164(e164Members).addAllMembers(uuidMembers);
    if (groupName != null)
        groupContextBuilder.setName(groupName);
    GroupContext groupContext = groupContextBuilder.build();
    if (avatar != null) {
        Uri avatarUri = BlobProvider.getInstance().forData(avatar).createForSingleUseInMemory();
        avatarAttachment = new UriAttachment(avatarUri, MediaUtil.IMAGE_PNG, AttachmentDatabase.TRANSFER_PROGRESS_DONE, avatar.length, null, false, false, false, false, null, null, null, null, null);
    }
    OutgoingGroupUpdateMessage outgoingMessage = new OutgoingGroupUpdateMessage(groupRecipient, groupContext, avatarAttachment, System.currentTimeMillis(), 0, false, null, Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
    long threadId = MessageSender.send(context, outgoingMessage, -1, false, null, null);
    return new GroupActionResult(groupRecipient, threadId, newMemberCount, Collections.emptyList());
}
Also used : RecipientId(org.thoughtcrime.securesms.recipients.RecipientId) ArrayList(java.util.ArrayList) UriAttachment(org.thoughtcrime.securesms.attachments.UriAttachment) Attachment(org.thoughtcrime.securesms.attachments.Attachment) Recipient(org.thoughtcrime.securesms.recipients.Recipient) ByteString(com.google.protobuf.ByteString) Uri(android.net.Uri) OutgoingGroupUpdateMessage(org.thoughtcrime.securesms.mms.OutgoingGroupUpdateMessage) GroupActionResult(org.thoughtcrime.securesms.groups.GroupManager.GroupActionResult) UriAttachment(org.thoughtcrime.securesms.attachments.UriAttachment) GroupContext(org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext)

Example 5 with OutgoingGroupUpdateMessage

use of org.thoughtcrime.securesms.mms.OutgoingGroupUpdateMessage in project Signal-Android by signalapp.

the class MmsDatabase method insertMessageOutbox.

@Override
public long insertMessageOutbox(@NonNull OutgoingMediaMessage message, long threadId, boolean forceSms, int defaultReceiptStatus, @Nullable SmsDatabase.InsertListener insertListener) throws MmsException {
    SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
    long type = Types.BASE_SENDING_TYPE;
    if (message.isSecure())
        type |= (Types.SECURE_MESSAGE_BIT | Types.PUSH_MESSAGE_BIT);
    if (forceSms)
        type |= Types.MESSAGE_FORCE_SMS_BIT;
    if (message.isGroup()) {
        OutgoingGroupUpdateMessage outgoingGroupUpdateMessage = (OutgoingGroupUpdateMessage) message;
        if (outgoingGroupUpdateMessage.isV2Group()) {
            type |= Types.GROUP_V2_BIT | Types.GROUP_UPDATE_BIT;
            if (outgoingGroupUpdateMessage.isJustAGroupLeave()) {
                type |= Types.GROUP_LEAVE_BIT;
            }
        } else {
            MessageGroupContext.GroupV1Properties properties = outgoingGroupUpdateMessage.requireGroupV1Properties();
            if (properties.isUpdate())
                type |= Types.GROUP_UPDATE_BIT;
            else if (properties.isQuit())
                type |= Types.GROUP_LEAVE_BIT;
        }
    }
    if (message.isExpirationUpdate()) {
        type |= Types.EXPIRATION_TIMER_UPDATE_BIT;
    }
    Map<RecipientId, EarlyReceiptCache.Receipt> earlyDeliveryReceipts = earlyDeliveryReceiptCache.remove(message.getSentTimeMillis());
    ContentValues contentValues = new ContentValues();
    contentValues.put(DATE_SENT, message.getSentTimeMillis());
    contentValues.put(MESSAGE_TYPE, PduHeaders.MESSAGE_TYPE_SEND_REQ);
    contentValues.put(MESSAGE_BOX, type);
    contentValues.put(THREAD_ID, threadId);
    contentValues.put(READ, 1);
    contentValues.put(DATE_RECEIVED, System.currentTimeMillis());
    contentValues.put(SUBSCRIPTION_ID, message.getSubscriptionId());
    contentValues.put(EXPIRES_IN, message.getExpiresIn());
    contentValues.put(VIEW_ONCE, message.isViewOnce());
    contentValues.put(RECIPIENT_ID, message.getRecipient().getId().serialize());
    contentValues.put(DELIVERY_RECEIPT_COUNT, Stream.of(earlyDeliveryReceipts.values()).mapToLong(EarlyReceiptCache.Receipt::getCount).sum());
    contentValues.put(RECEIPT_TIMESTAMP, Stream.of(earlyDeliveryReceipts.values()).mapToLong(EarlyReceiptCache.Receipt::getTimestamp).max().orElse(-1));
    if (message.getRecipient().isSelf() && hasAudioAttachment(message.getAttachments())) {
        contentValues.put(VIEWED_RECEIPT_COUNT, 1L);
    }
    List<Attachment> quoteAttachments = new LinkedList<>();
    if (message.getOutgoingQuote() != null) {
        MentionUtil.UpdatedBodyAndMentions updated = MentionUtil.updateBodyAndMentionsWithPlaceholders(message.getOutgoingQuote().getText(), message.getOutgoingQuote().getMentions());
        contentValues.put(QUOTE_ID, message.getOutgoingQuote().getId());
        contentValues.put(QUOTE_AUTHOR, message.getOutgoingQuote().getAuthor().serialize());
        contentValues.put(QUOTE_BODY, updated.getBodyAsString());
        contentValues.put(QUOTE_MISSING, message.getOutgoingQuote().isOriginalMissing() ? 1 : 0);
        BodyRangeList mentionsList = MentionUtil.mentionsToBodyRangeList(updated.getMentions());
        if (mentionsList != null) {
            contentValues.put(QUOTE_MENTIONS, mentionsList.toByteArray());
        }
        quoteAttachments.addAll(message.getOutgoingQuote().getAttachments());
    }
    MentionUtil.UpdatedBodyAndMentions updatedBodyAndMentions = MentionUtil.updateBodyAndMentionsWithPlaceholders(message.getBody(), message.getMentions());
    long messageId = insertMediaMessage(threadId, updatedBodyAndMentions.getBodyAsString(), message.getAttachments(), quoteAttachments, message.getSharedContacts(), message.getLinkPreviews(), updatedBodyAndMentions.getMentions(), null, contentValues, insertListener, false);
    if (message.getRecipient().isGroup()) {
        OutgoingGroupUpdateMessage outgoingGroupUpdateMessage = (message instanceof OutgoingGroupUpdateMessage) ? (OutgoingGroupUpdateMessage) message : null;
        GroupReceiptDatabase receiptDatabase = SignalDatabase.groupReceipts();
        Set<RecipientId> members = new HashSet<>();
        if (outgoingGroupUpdateMessage != null && outgoingGroupUpdateMessage.isV2Group()) {
            MessageGroupContext.GroupV2Properties groupV2Properties = outgoingGroupUpdateMessage.requireGroupV2Properties();
            members.addAll(Stream.of(groupV2Properties.getAllActivePendingAndRemovedMembers()).distinct().map(uuid -> RecipientId.from(ACI.from(uuid), null)).toList());
            members.remove(Recipient.self().getId());
        } else {
            members.addAll(Stream.of(SignalDatabase.groups().getGroupMembers(message.getRecipient().requireGroupId(), GroupDatabase.MemberSet.FULL_MEMBERS_EXCLUDING_SELF)).map(Recipient::getId).toList());
        }
        receiptDatabase.insert(members, messageId, defaultReceiptStatus, message.getSentTimeMillis());
        for (RecipientId recipientId : earlyDeliveryReceipts.keySet()) {
            receiptDatabase.update(recipientId, messageId, GroupReceiptDatabase.STATUS_DELIVERED, -1);
        }
    }
    SignalDatabase.threads().updateLastSeenAndMarkSentAndLastScrolledSilenty(threadId);
    ApplicationDependencies.getDatabaseObserver().notifyMessageInsertObservers(threadId, new MessageId(messageId, true));
    notifyConversationListListeners();
    TrimThreadJob.enqueueAsync(threadId);
    return messageId;
}
Also used : ContentValues(android.content.ContentValues) RecipientId(org.thoughtcrime.securesms.recipients.RecipientId) BodyRangeList(org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList) Attachment(org.thoughtcrime.securesms.attachments.Attachment) DatabaseAttachment(org.thoughtcrime.securesms.attachments.DatabaseAttachment) MmsNotificationAttachment(org.thoughtcrime.securesms.attachments.MmsNotificationAttachment) Recipient(org.thoughtcrime.securesms.recipients.Recipient) OutgoingGroupUpdateMessage(org.thoughtcrime.securesms.mms.OutgoingGroupUpdateMessage) LinkedList(java.util.LinkedList) MessageGroupContext(org.thoughtcrime.securesms.mms.MessageGroupContext) HashSet(java.util.HashSet) MessageId(org.thoughtcrime.securesms.database.model.MessageId)

Aggregations

OutgoingGroupUpdateMessage (org.thoughtcrime.securesms.mms.OutgoingGroupUpdateMessage)12 Recipient (org.thoughtcrime.securesms.recipients.Recipient)10 Attachment (org.thoughtcrime.securesms.attachments.Attachment)8 RecipientId (org.thoughtcrime.securesms.recipients.RecipientId)8 ByteString (com.google.protobuf.ByteString)6 MessageId (org.thoughtcrime.securesms.database.model.MessageId)6 MessageGroupContext (org.thoughtcrime.securesms.mms.MessageGroupContext)6 MmsException (org.thoughtcrime.securesms.mms.MmsException)6 ContentValues (android.content.ContentValues)4 NonNull (androidx.annotation.NonNull)4 Nullable (androidx.annotation.Nullable)4 ArrayList (java.util.ArrayList)4 HashSet (java.util.HashSet)4 LinkedList (java.util.LinkedList)4 DatabaseAttachment (org.thoughtcrime.securesms.attachments.DatabaseAttachment)3 MmsNotificationAttachment (org.thoughtcrime.securesms.attachments.MmsNotificationAttachment)3 BodyRangeList (org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList)3 IncomingTextMessage (org.thoughtcrime.securesms.sms.IncomingTextMessage)3 Context (android.content.Context)2 Cursor (android.database.Cursor)2