Search in sources :

Example 76 with MessageId

use of org.thoughtcrime.securesms.database.model.MessageId in project Signal-Android by signalapp.

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 77 with MessageId

use of org.thoughtcrime.securesms.database.model.MessageId in project Signal-Android by signalapp.

the class MmsDatabase method incrementReceiptCount.

@Override
public Set<MessageUpdate> incrementReceiptCount(SyncMessageId messageId, long timestamp, @NonNull ReceiptType receiptType) {
    SQLiteDatabase database = databaseHelper.getSignalWritableDatabase();
    Set<MessageUpdate> messageUpdates = new HashSet<>();
    try (Cursor cursor = database.query(TABLE_NAME, new String[] { ID, THREAD_ID, MESSAGE_BOX, RECIPIENT_ID, receiptType.getColumnName(), RECEIPT_TIMESTAMP }, DATE_SENT + " = ?", new String[] { String.valueOf(messageId.getTimetamp()) }, null, null, null, null)) {
        while (cursor.moveToNext()) {
            if (Types.isOutgoingMessageType(CursorUtil.requireLong(cursor, MESSAGE_BOX))) {
                RecipientId theirRecipientId = RecipientId.from(CursorUtil.requireLong(cursor, RECIPIENT_ID));
                RecipientId ourRecipientId = messageId.getRecipientId();
                String columnName = receiptType.getColumnName();
                if (ourRecipientId.equals(theirRecipientId) || Recipient.resolved(theirRecipientId).isGroup()) {
                    long id = CursorUtil.requireLong(cursor, ID);
                    long threadId = CursorUtil.requireLong(cursor, THREAD_ID);
                    int status = receiptType.getGroupStatus();
                    boolean isFirstIncrement = CursorUtil.requireLong(cursor, columnName) == 0;
                    long savedTimestamp = CursorUtil.requireLong(cursor, RECEIPT_TIMESTAMP);
                    long updatedTimestamp = isFirstIncrement ? Math.max(savedTimestamp, timestamp) : savedTimestamp;
                    database.execSQL("UPDATE " + TABLE_NAME + " SET " + columnName + " = " + columnName + " + 1, " + RECEIPT_TIMESTAMP + " = ? WHERE " + ID + " = ?", SqlUtil.buildArgs(updatedTimestamp, id));
                    SignalDatabase.groupReceipts().update(ourRecipientId, id, status, timestamp);
                    messageUpdates.add(new MessageUpdate(threadId, new MessageId(id, true)));
                }
            }
        }
        if (messageUpdates.size() > 0 && receiptType == ReceiptType.DELIVERY) {
            earlyDeliveryReceiptCache.increment(messageId.getTimetamp(), messageId.getRecipientId(), timestamp);
        }
        return messageUpdates;
    }
}
Also used : RecipientId(org.thoughtcrime.securesms.recipients.RecipientId) Cursor(android.database.Cursor) HashSet(java.util.HashSet) MessageId(org.thoughtcrime.securesms.database.model.MessageId)

Example 78 with MessageId

use of org.thoughtcrime.securesms.database.model.MessageId in project Signal-Android by signalapp.

the class SmsDatabase method markAsRemoteDelete.

@Override
public void markAsRemoteDelete(long id) {
    SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
    long threadId;
    db.beginTransaction();
    try {
        ContentValues values = new ContentValues();
        values.put(REMOTE_DELETED, 1);
        values.putNull(BODY);
        db.update(TABLE_NAME, values, ID_WHERE, new String[] { String.valueOf(id) });
        threadId = getThreadIdForMessage(id);
        SignalDatabase.reactions().deleteReactions(new MessageId(id, false));
        SignalDatabase.threads().update(threadId, false);
        SignalDatabase.messageLog().deleteAllRelatedToMessage(id, false);
        db.setTransactionSuccessful();
    } finally {
        db.endTransaction();
    }
    notifyConversationListeners(threadId);
}
Also used : ContentValues(android.content.ContentValues) MessageId(org.thoughtcrime.securesms.database.model.MessageId)

Example 79 with MessageId

use of org.thoughtcrime.securesms.database.model.MessageId in project Signal-Android by signalapp.

the class SmsDatabase method setMessagesRead.

private List<MarkedMessageInfo> setMessagesRead(String where, String[] arguments) {
    SQLiteDatabase database = databaseHelper.getSignalWritableDatabase();
    List<MarkedMessageInfo> results = new LinkedList<>();
    Cursor cursor = null;
    RecipientId releaseChannelId = SignalStore.releaseChannelValues().getReleaseChannelRecipientId();
    database.beginTransaction();
    try {
        cursor = database.query(TABLE_NAME, new String[] { ID, RECIPIENT_ID, DATE_SENT, TYPE, EXPIRES_IN, EXPIRE_STARTED, THREAD_ID }, where, arguments, null, null, null);
        while (cursor != null && cursor.moveToNext()) {
            if (Types.isSecureType(CursorUtil.requireLong(cursor, TYPE))) {
                long threadId = CursorUtil.requireLong(cursor, THREAD_ID);
                RecipientId recipientId = RecipientId.from(CursorUtil.requireLong(cursor, RECIPIENT_ID));
                long dateSent = CursorUtil.requireLong(cursor, DATE_SENT);
                long messageId = CursorUtil.requireLong(cursor, ID);
                long expiresIn = CursorUtil.requireLong(cursor, EXPIRES_IN);
                long expireStarted = CursorUtil.requireLong(cursor, EXPIRE_STARTED);
                SyncMessageId syncMessageId = new SyncMessageId(recipientId, dateSent);
                ExpirationInfo expirationInfo = new ExpirationInfo(messageId, expiresIn, expireStarted, false);
                if (!recipientId.equals(releaseChannelId)) {
                    results.add(new MarkedMessageInfo(threadId, syncMessageId, new MessageId(messageId, false), expirationInfo));
                }
            }
        }
        ContentValues contentValues = new ContentValues();
        contentValues.put(READ, 1);
        contentValues.put(REACTIONS_UNREAD, 0);
        contentValues.put(REACTIONS_LAST_SEEN, System.currentTimeMillis());
        database.update(TABLE_NAME, contentValues, where, arguments);
        database.setTransactionSuccessful();
    } finally {
        if (cursor != null)
            cursor.close();
        database.endTransaction();
    }
    return results;
}
Also used : ContentValues(android.content.ContentValues) ViewOnceExpirationInfo(org.thoughtcrime.securesms.revealable.ViewOnceExpirationInfo) RecipientId(org.thoughtcrime.securesms.recipients.RecipientId) Cursor(android.database.Cursor) LinkedList(java.util.LinkedList) MessageId(org.thoughtcrime.securesms.database.model.MessageId)

Example 80 with MessageId

use of org.thoughtcrime.securesms.database.model.MessageId in project Signal-Android by signalapp.

the class SmsDatabase method insertMessageOutbox.

@Override
public long insertMessageOutbox(long threadId, OutgoingTextMessage message, boolean forceSms, long date, InsertListener insertListener) {
    SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
    long type = Types.BASE_SENDING_TYPE;
    if (message.isKeyExchange())
        type |= Types.KEY_EXCHANGE_BIT;
    else if (message.isSecureMessage())
        type |= (Types.SECURE_MESSAGE_BIT | Types.PUSH_MESSAGE_BIT);
    else if (message.isEndSession())
        type |= Types.END_SESSION_BIT;
    if (forceSms)
        type |= Types.MESSAGE_FORCE_SMS_BIT;
    if (message.isIdentityVerified())
        type |= Types.KEY_EXCHANGE_IDENTITY_VERIFIED_BIT;
    else if (message.isIdentityDefault())
        type |= Types.KEY_EXCHANGE_IDENTITY_DEFAULT_BIT;
    RecipientId recipientId = message.getRecipient().getId();
    Map<RecipientId, EarlyReceiptCache.Receipt> earlyDeliveryReceipts = earlyDeliveryReceiptCache.remove(date);
    ContentValues contentValues = new ContentValues(6);
    contentValues.put(RECIPIENT_ID, recipientId.serialize());
    contentValues.put(THREAD_ID, threadId);
    contentValues.put(BODY, message.getMessageBody());
    contentValues.put(DATE_RECEIVED, System.currentTimeMillis());
    contentValues.put(DATE_SENT, date);
    contentValues.put(READ, 1);
    contentValues.put(TYPE, type);
    contentValues.put(SUBSCRIPTION_ID, message.getSubscriptionId());
    contentValues.put(EXPIRES_IN, message.getExpiresIn());
    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));
    long messageId = db.insert(TABLE_NAME, null, contentValues);
    if (insertListener != null) {
        insertListener.onComplete();
    }
    if (!message.isIdentityVerified() && !message.isIdentityDefault()) {
        SignalDatabase.threads().setLastScrolled(threadId, 0);
        SignalDatabase.threads().setLastSeenSilently(threadId);
    }
    SignalDatabase.threads().setHasSentSilently(threadId, true);
    ApplicationDependencies.getDatabaseObserver().notifyMessageInsertObservers(threadId, new MessageId(messageId, false));
    if (!message.isIdentityVerified() && !message.isIdentityDefault()) {
        TrimThreadJob.enqueueAsync(threadId);
    }
    return messageId;
}
Also used : ContentValues(android.content.ContentValues) RecipientId(org.thoughtcrime.securesms.recipients.RecipientId) MessageId(org.thoughtcrime.securesms.database.model.MessageId)

Aggregations

MessageId (org.thoughtcrime.securesms.database.model.MessageId)90 RecipientId (org.thoughtcrime.securesms.recipients.RecipientId)40 NonNull (androidx.annotation.NonNull)30 Recipient (org.thoughtcrime.securesms.recipients.Recipient)30 Nullable (androidx.annotation.Nullable)28 LinkedList (java.util.LinkedList)24 List (java.util.List)24 SyncMessageId (org.thoughtcrime.securesms.database.MessageDatabase.SyncMessageId)24 Context (android.content.Context)22 IOException (java.io.IOException)22 Log (org.signal.core.util.logging.Log)22 ApplicationDependencies (org.thoughtcrime.securesms.dependencies.ApplicationDependencies)22 SignalServiceDataMessage (org.whispersystems.signalservice.api.messages.SignalServiceDataMessage)22 ContentValues (android.content.ContentValues)20 Collections (java.util.Collections)20 Attachment (org.thoughtcrime.securesms.attachments.Attachment)20 MessageDatabase (org.thoughtcrime.securesms.database.MessageDatabase)20 Cursor (android.database.Cursor)18 ArrayList (java.util.ArrayList)18 TextSecurePreferences (org.thoughtcrime.securesms.util.TextSecurePreferences)18