Send long-text with other attachments

pull/2/head
Michael Kirk 6 years ago
parent a218d6c465
commit bc4260b444

@ -3604,10 +3604,16 @@ typedef enum : NSUInteger {
} }
BOOL didAddToProfileWhitelist = [ThreadUtil addThreadToProfileWhitelistIfEmptyContactThread:self.thread]; BOOL didAddToProfileWhitelist = [ThreadUtil addThreadToProfileWhitelistIfEmptyContactThread:self.thread];
TSOutgoingMessage *message = [ThreadUtil enqueueMessageWithAttachments:attachments
messageBody:messageText __block TSOutgoingMessage *message;
inThread:self.thread [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
quotedReplyModel:self.inputToolbar.quotedReply]; message = [ThreadUtil enqueueMessageWithText:messageText
mediaAttachments:attachments
inThread:self.thread
quotedReplyModel:self.inputToolbar.quotedReply
linkPreviewDraft:nil
transaction:transaction];
}];
[self messageWasSent:message]; [self messageWasSent:message];

@ -592,10 +592,26 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
} }
} }
NSArray<TSAttachment *> *attachments = [message attachmentsWithTransaction:transaction]; NSString *_Nullable bodyText = [message bodyTextWithTransaction:transaction];
if (bodyText) {
self.displayableBodyText = [self displayableBodyTextForText:bodyText interactionId:message.uniqueId];
}
// Even though displayableBodyText could have already been assigned from the oversized text
// attachment, it's also possible that for new messages we'd first cached the truncated body
// text. So if an AttachmentStream now exists we explicitly use the text from the attachment.
TSAttachment *_Nullable oversizeTextAttachment = [message oversizeTextAttachmentWithTransaction:transaction];
if (oversizeTextAttachment != nil && [oversizeTextAttachment isKindOfClass:[TSAttachmentStream class]]) {
TSAttachmentStream *oversizeTextAttachmentStream = (TSAttachmentStream *)oversizeTextAttachment;
self.messageCellType = OWSMessageCellType_OversizeTextMessage;
self.displayableBodyText = [self displayableBodyTextForOversizeTextAttachment:oversizeTextAttachmentStream
interactionId:message.uniqueId];
}
NSArray<TSAttachment *> *mediaAttachments = [message mediaAttachmentsWithTransaction:transaction];
if ([message isMediaAlbumWithTransaction:transaction]) { if ([message isMediaAlbumWithTransaction:transaction]) {
OWSAssertDebug(attachments.count > 0); OWSAssertDebug(mediaAttachments.count > 0);
NSArray<ConversationMediaAlbumItem *> *mediaAlbumItems = [self mediaAlbumItemsForAttachments:attachments]; NSArray<ConversationMediaAlbumItem *> *mediaAlbumItems = [self mediaAlbumItemsForAttachments:mediaAttachments];
if (mediaAlbumItems.count == 1) { if (mediaAlbumItems.count == 1) {
ConversationMediaAlbumItem *mediaAlbumItem = mediaAlbumItems.firstObject; ConversationMediaAlbumItem *mediaAlbumItem = mediaAlbumItems.firstObject;
@ -608,30 +624,16 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
self.mediaAlbumItems = mediaAlbumItems; self.mediaAlbumItems = mediaAlbumItems;
self.messageCellType = OWSMessageCellType_MediaAlbum; self.messageCellType = OWSMessageCellType_MediaAlbum;
NSString *_Nullable albumTitle = [message bodyTextWithTransaction:transaction];
if (!albumTitle && mediaAlbumItems.count == 1) {
// If the album contains only one option, use its caption as the
// the album title.
albumTitle = mediaAlbumItems.firstObject.caption;
}
if (albumTitle) {
self.displayableBodyText = [self displayableBodyTextForText:albumTitle interactionId:message.uniqueId];
}
return; return;
} }
// Only media galleries should have more than one attachment. // Only media galleries should have more than one attachment.
OWSAssertDebug(attachments.count <= 1); OWSAssertDebug(mediaAttachments.count <= 1);
TSAttachment *_Nullable mediaAttachment = mediaAttachments.firstObject;
TSAttachment *_Nullable attachment = attachments.firstObject; if (mediaAttachment) {
if (attachment) { if ([mediaAttachment isKindOfClass:[TSAttachmentStream class]]) {
if ([attachment isKindOfClass:[TSAttachmentStream class]]) { self.attachmentStream = (TSAttachmentStream *)mediaAttachment;
self.attachmentStream = (TSAttachmentStream *)attachment; if ([self.attachmentStream isAudio]) {
if ([attachment.contentType isEqualToString:OWSMimeTypeOversizeTextMessage]) {
self.messageCellType = OWSMessageCellType_OversizeTextMessage;
self.displayableBodyText = [self displayableBodyTextForOversizeTextAttachment:self.attachmentStream
interactionId:message.uniqueId];
} else if ([self.attachmentStream isAudio]) {
CGFloat audioDurationSeconds = [self.attachmentStream audioDurationSeconds]; CGFloat audioDurationSeconds = [self.attachmentStream audioDurationSeconds];
if (audioDurationSeconds > 0) { if (audioDurationSeconds > 0) {
self.audioDurationSeconds = audioDurationSeconds; self.audioDurationSeconds = audioDurationSeconds;
@ -639,34 +641,28 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
} else { } else {
self.messageCellType = OWSMessageCellType_GenericAttachment; self.messageCellType = OWSMessageCellType_GenericAttachment;
} }
} else { } else if (self.messageCellType == OWSMessageCellType_Unknown) {
self.messageCellType = OWSMessageCellType_GenericAttachment; self.messageCellType = OWSMessageCellType_GenericAttachment;
} }
} else if ([attachment isKindOfClass:[TSAttachmentPointer class]]) { } else if ([mediaAttachment isKindOfClass:[TSAttachmentPointer class]]) {
self.messageCellType = OWSMessageCellType_DownloadingAttachment; self.messageCellType = OWSMessageCellType_DownloadingAttachment;
self.attachmentPointer = (TSAttachmentPointer *)attachment; self.attachmentPointer = (TSAttachmentPointer *)mediaAttachment;
} else { } else {
OWSFailDebug(@"Unknown attachment type"); OWSFailDebug(@"Unknown attachment type");
} }
} }
// Ignore message body for oversize text attachments. if (self.hasBodyText) {
if (message.body.length > 0) {
if (self.hasBodyText) {
OWSFailDebug(@"oversize text message has unexpected caption.");
}
// If we haven't already assigned an attachment type at this point, message.body isn't a caption, // If we haven't already assigned an attachment type at this point, message.body isn't a caption,
// it's a stand-alone text message. // it's a stand-alone text message.
if (self.messageCellType == OWSMessageCellType_Unknown) { if (self.messageCellType == OWSMessageCellType_Unknown) {
OWSAssertDebug(message.attachmentIds.count == 0); OWSAssertDebug(message.attachmentIds.count == 0);
self.messageCellType = OWSMessageCellType_TextMessage; self.messageCellType = OWSMessageCellType_TextMessage;
} }
self.displayableBodyText = [self displayableBodyTextForText:message.body interactionId:message.uniqueId];
OWSAssertDebug(self.displayableBodyText); OWSAssertDebug(self.displayableBodyText);
} }
if (self.hasBodyText && attachment == nil && message.linkPreview) { if (self.hasBodyText && message.linkPreview) {
self.linkPreview = message.linkPreview; self.linkPreview = message.linkPreview;
if (message.linkPreview.imageAttachmentId.length > 0) { if (message.linkPreview.imageAttachmentId.length > 0) {
TSAttachment *_Nullable linkPreviewAttachment = TSAttachment *_Nullable linkPreviewAttachment =

@ -390,12 +390,12 @@ NS_ASSUME_NONNULL_BEGIN
}]; }];
} }
+ (void)sendAttachment:(NSString *)filePath + (void)sendAttachmentWithFilePath:(NSString *)filePath
thread:(TSThread *)thread thread:(TSThread *)thread
label:(NSString *)label label:(NSString *)label
hasCaption:(BOOL)hasCaption hasCaption:(BOOL)hasCaption
success:(nullable void (^)(void))success success:(nullable void (^)(void))success
failure:(nullable void (^)(void))failure failure:(nullable void (^)(void))failure
{ {
OWSAssertDebug(filePath); OWSAssertDebug(filePath);
OWSAssertDebug(thread); OWSAssertDebug(thread);
@ -425,7 +425,9 @@ NS_ASSUME_NONNULL_BEGIN
[DDLog flushLog]; [DDLog flushLog];
} }
OWSAssertDebug(![attachment hasError]); OWSAssertDebug(![attachment hasError]);
[ThreadUtil enqueueMessageWithAttachment:attachment inThread:thread quotedReplyModel:nil];
[self sendAttachment:attachment thread:thread messageBody:messageBody];
success(); success();
} }
@ -551,12 +553,12 @@ NS_ASSUME_NONNULL_BEGIN
ActionFailureBlock failure) { ActionFailureBlock failure) {
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
OWSAssertDebug(fakeAssetLoader.filePath.length > 0); OWSAssertDebug(fakeAssetLoader.filePath.length > 0);
[self sendAttachment:fakeAssetLoader.filePath [self sendAttachmentWithFilePath:fakeAssetLoader.filePath
thread:thread thread:thread
label:label label:label
hasCaption:hasCaption hasCaption:hasCaption
success:success success:success
failure:failure]; failure:failure];
}); });
} }
prepareBlock:fakeAssetLoader.prepareBlock]; prepareBlock:fakeAssetLoader.prepareBlock];
@ -1732,19 +1734,25 @@ NS_ASSUME_NONNULL_BEGIN
return attachment; return attachment;
} }
+ (void)sendAttachment:(NSString *)filePath + (void)sendAttachment:(nullable SignalAttachment *)attachment
thread:(TSThread *)thread thread:(TSThread *)thread
success:(nullable void (^)(void))success messageBody:(nullable NSString *)messageBody
failure:(nullable void (^)(void))failure
{ {
OWSAssertDebug(filePath); [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
OWSAssertDebug(thread); NSArray<SignalAttachment *> *attachments = @[];
if (attachment != nil) {
SignalAttachment *attachment = [self signalAttachmentForFilePath:filePath]; attachments = @[ attachment ];
[ThreadUtil enqueueMessageWithAttachment:attachment inThread:thread quotedReplyModel:nil]; }
success(); [ThreadUtil enqueueMessageWithText:messageBody
mediaAttachments:attachments
inThread:thread
quotedReplyModel:nil
linkPreviewDraft:nil
transaction:transaction];
}];
} }
+ (DebugUIMessagesAction *)fakeIncomingTextMessageAction:(TSThread *)thread text:(NSString *)text + (DebugUIMessagesAction *)fakeIncomingTextMessageAction:(TSThread *)thread text:(NSString *)text
{ {
OWSAssertDebug(thread); OWSAssertDebug(thread);
@ -3342,11 +3350,7 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
+ (void)sendOversizeTextMessage:(TSThread *)thread + (void)sendOversizeTextMessage:(TSThread *)thread
{ {
NSString *message = [self randomOversizeText]; [self sendAttachment:nil thread:thread messageBody:[self randomOversizeText]];
DataSource *_Nullable dataSource = [DataSourceValue dataSourceWithOversizeText:message];
SignalAttachment *attachment =
[SignalAttachment attachmentWithDataSource:dataSource dataUTI:kOversizeTextAttachmentUTI];
[ThreadUtil enqueueMessageWithAttachment:attachment inThread:thread quotedReplyModel:nil];
} }
+ (NSData *)createRandomNSDataOfSize:(size_t)size + (NSData *)createRandomNSDataOfSize:(size_t)size
@ -3379,7 +3383,7 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
// style them indistinguishably from a separate text message. // style them indistinguishably from a separate text message.
attachment.captionText = [self randomCaptionText]; attachment.captionText = [self randomCaptionText];
} }
[ThreadUtil enqueueMessageWithAttachment:attachment inThread:thread quotedReplyModel:nil]; [self sendAttachment:attachment thread:thread messageBody:nil];
} }
+ (SSKProtoEnvelope *)createEnvelopeForThread:(TSThread *)thread + (SSKProtoEnvelope *)createEnvelopeForThread:(TSThread *)thread
@ -4445,7 +4449,7 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
[DDLog flushLog]; [DDLog flushLog];
} }
OWSAssertDebug(![attachment hasError]); OWSAssertDebug(![attachment hasError]);
[ThreadUtil enqueueMessageWithAttachment:attachment inThread:thread quotedReplyModel:nil]; [self sendAttachment:attachment thread:thread messageBody:nil];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
sendUnsafeFile(); sendUnsafeFile();
@ -4759,12 +4763,14 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
[attachments addObject:attachment]; [attachments addObject:attachment];
} }
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
TSOutgoingMessage *message = [ThreadUtil enqueueMessageWithAttachments:attachments TSOutgoingMessage *message = [ThreadUtil enqueueMessageWithText:messageBody
messageBody:messageBody mediaAttachments:attachments
inThread:thread inThread:thread
quotedReplyModel:nil]; quotedReplyModel:nil
OWSLogError(@"timestamp: %llu.", message.timestamp); linkPreviewDraft:nil
transaction:transaction];
OWSLogDebug(@"timestamp: %llu.", message.timestamp);
}]; }];
} }

@ -33,6 +33,13 @@ NS_ASSUME_NONNULL_BEGIN
@implementation DebugUIMisc @implementation DebugUIMisc
#pragma mark - Dependencies
+ (YapDatabaseConnection *)dbConnection
{
return [OWSPrimaryStorage.sharedManager dbReadWriteConnection];
}
#pragma mark - Factory Methods #pragma mark - Factory Methods
- (NSString *)name - (NSString *)name
@ -252,11 +259,23 @@ NS_ASSUME_NONNULL_BEGIN
SignalAttachment *attachment = [SignalAttachment attachmentWithDataSource:dataSource dataUTI:utiType]; SignalAttachment *attachment = [SignalAttachment attachmentWithDataSource:dataSource dataUTI:utiType];
NSData *databasePassword = [OWSPrimaryStorage.sharedManager databasePassword]; NSData *databasePassword = [OWSPrimaryStorage.sharedManager databasePassword];
attachment.captionText = [databasePassword hexadecimalString]; attachment.captionText = [databasePassword hexadecimalString];
[self sendAttachment:attachment thread:thread];
}
+ (void)sendAttachment:(SignalAttachment *)attachment thread:(TSThread *)thread
{
if (!attachment || [attachment hasError]) { if (!attachment || [attachment hasError]) {
OWSFailDebug(@"attachment[%@]: %@", [attachment sourceFilename], [attachment errorName]); OWSFailDebug(@"attachment[%@]: %@", [attachment sourceFilename], [attachment errorName]);
return; return;
} }
[ThreadUtil enqueueMessageWithAttachment:attachment inThread:thread quotedReplyModel:nil]; [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
[ThreadUtil enqueueMessageWithText:nil
mediaAttachments:@[ attachment ]
inThread:thread
quotedReplyModel:nil
linkPreviewDraft:nil
transaction:transaction];
}];
} }
+ (void)sendUnencryptedDatabase:(TSThread *)thread + (void)sendUnencryptedDatabase:(TSThread *)thread
@ -274,11 +293,7 @@ NS_ASSUME_NONNULL_BEGIN
DataSource *_Nullable dataSource = [DataSourcePath dataSourceWithFilePath:filePath shouldDeleteOnDeallocation:YES]; DataSource *_Nullable dataSource = [DataSourcePath dataSourceWithFilePath:filePath shouldDeleteOnDeallocation:YES];
[dataSource setSourceFilename:fileName]; [dataSource setSourceFilename:fileName];
SignalAttachment *attachment = [SignalAttachment attachmentWithDataSource:dataSource dataUTI:utiType]; SignalAttachment *attachment = [SignalAttachment attachmentWithDataSource:dataSource dataUTI:utiType];
if (!attachment || [attachment hasError]) { [self sendAttachment:attachment thread:thread];
OWSFailDebug(@"attachment[%@]: %@", [attachment sourceFilename], [attachment errorName]);
return;
}
[ThreadUtil enqueueMessageWithAttachment:attachment inThread:thread quotedReplyModel:nil];
} }
#ifdef DEBUG #ifdef DEBUG

@ -1,5 +1,5 @@
// //
// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // Copyright (c) 2019 Open Whisper Systems. All rights reserved.
// //
#import "SharingThreadPickerViewController.h" #import "SharingThreadPickerViewController.h"

@ -44,20 +44,18 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - Durable Message Enqueue #pragma mark - Durable Message Enqueue
+ (TSOutgoingMessage *)enqueueMessageWithText:(NSString *)text + (TSOutgoingMessage *)enqueueMessageWithText:(NSString *)fullMessageText
inThread:(TSThread *)thread inThread:(TSThread *)thread
quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel
linkPreviewDraft:(nullable nullable OWSLinkPreviewDraft *)linkPreviewDraft linkPreviewDraft:(nullable nullable OWSLinkPreviewDraft *)linkPreviewDraft
transaction:(YapDatabaseReadTransaction *)transaction; transaction:(YapDatabaseReadTransaction *)transaction;
+ (TSOutgoingMessage *)enqueueMessageWithAttachment:(SignalAttachment *)attachment + (TSOutgoingMessage *)enqueueMessageWithText:(nullable NSString *)fullMessageText
inThread:(TSThread *)thread mediaAttachments:(NSArray<SignalAttachment *> *)attachments
quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel; inThread:(TSThread *)thread
quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel
+ (TSOutgoingMessage *)enqueueMessageWithAttachments:(NSArray<SignalAttachment *> *)attachments linkPreviewDraft:(nullable nullable OWSLinkPreviewDraft *)linkPreviewDraft
messageBody:(nullable NSString *)messageBody transaction:(YapDatabaseReadTransaction *)transaction;
inThread:(TSThread *)thread
quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel;
+ (TSOutgoingMessage *)enqueueMessageWithContactShare:(OWSContact *)contactShare inThread:(TSThread *)thread; + (TSOutgoingMessage *)enqueueMessageWithContactShare:(OWSContact *)contactShare inThread:(TSThread *)thread;
+ (void)enqueueLeaveGroupMessageInThread:(TSGroupThread *)thread; + (void)enqueueLeaveGroupMessageInThread:(TSGroupThread *)thread;

@ -9,6 +9,7 @@
#import "OWSUnreadIndicator.h" #import "OWSUnreadIndicator.h"
#import "TSUnreadIndicatorInteraction.h" #import "TSUnreadIndicatorInteraction.h"
#import <SignalCoreKit/NSDate+OWS.h> #import <SignalCoreKit/NSDate+OWS.h>
#import <SignalCoreKit/SignalCoreKit-Swift.h>
#import <SignalMessaging/OWSProfileManager.h> #import <SignalMessaging/OWSProfileManager.h>
#import <SignalMessaging/SignalMessaging-Swift.h> #import <SignalMessaging/SignalMessaging-Swift.h>
#import <SignalServiceKit/OWSAddToContactsOfferMessage.h> #import <SignalServiceKit/OWSAddToContactsOfferMessage.h>
@ -65,58 +66,18 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - Durable Message Enqueue #pragma mark - Durable Message Enqueue
+ (TSOutgoingMessage *)enqueueMessageWithText:(NSString *)text + (TSOutgoingMessage *)enqueueMessageWithText:(NSString *)fullMessageText
inThread:(TSThread *)thread inThread:(TSThread *)thread
quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel
linkPreviewDraft:(nullable nullable OWSLinkPreviewDraft *)linkPreviewDraft linkPreviewDraft:(nullable nullable OWSLinkPreviewDraft *)linkPreviewDraft
transaction:(YapDatabaseReadTransaction *)transaction transaction:(YapDatabaseReadTransaction *)transaction
{ {
return [self enqueueMessageWithText:fullMessageText
NSString *truncatedText; mediaAttachments:@[]
SignalAttachment *_Nullable oversizeTextAttachment; inThread:thread
quotedReplyModel:quotedReplyModel
if ([text lengthOfBytesUsingEncoding:NSUTF8StringEncoding] >= kOversizeTextMessageSizeThreshold) { linkPreviewDraft:linkPreviewDraft
truncatedText = [text truncatedToByteCount:kOversizeTextMessageSizeThreshold]; transaction:transaction];
DataSource *_Nullable dataSource = [DataSourceValue dataSourceWithOversizeText:text];
if (dataSource) {
oversizeTextAttachment =
[SignalAttachment attachmentWithDataSource:dataSource dataUTI:kOversizeTextAttachmentUTI];
}
} else {
truncatedText = text;
oversizeTextAttachment = nil;
}
OWSDisappearingMessagesConfiguration *configuration =
[OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId transaction:transaction];
uint32_t expiresInSeconds = (configuration.isEnabled ? configuration.durationSeconds : 0);
TSOutgoingMessage *message =
[TSOutgoingMessage outgoingMessageInThread:thread
messageBody:text
attachmentId:nil
expiresInSeconds:expiresInSeconds
quotedMessage:[quotedReplyModel buildQuotedMessageForSending]
linkPreview:nil];
[BenchManager benchAsyncWithTitle:@"Saving outgoing message" block:^(void (^benchmarkCompletion)(void)) {
// To avoid blocking the send flow, we dispatch an async write from within this read transaction
[self.dbConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction * _Nonnull writeTransaction) {
[message saveWithTransaction:writeTransaction];
OWSLinkPreview *_Nullable linkPreview =
[self linkPreviewForLinkPreviewDraft:linkPreviewDraft transaction:writeTransaction];
if (linkPreview) {
[message updateWithLinkPreview:linkPreview transaction:writeTransaction];
}
[self.messageSenderJobQueue addMessage:message transaction:writeTransaction];
}
completionBlock:benchmarkCompletion];
}];
return message;
} }
+ (nullable OWSLinkPreview *)linkPreviewForLinkPreviewDraft:(nullable OWSLinkPreviewDraft *)linkPreviewDraft + (nullable OWSLinkPreview *)linkPreviewForLinkPreviewDraft:(nullable OWSLinkPreviewDraft *)linkPreviewDraft
@ -137,40 +98,48 @@ NS_ASSUME_NONNULL_BEGIN
return linkPreview; return linkPreview;
} }
+ (TSOutgoingMessage *)enqueueMessageWithAttachment:(SignalAttachment *)attachment + (TSOutgoingMessage *)enqueueMessageWithText:(nullable NSString *)fullMessageText
inThread:(TSThread *)thread mediaAttachments:(NSArray<SignalAttachment *> *)attachmentsParam
quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel inThread:(TSThread *)thread
{ quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel
return [self enqueueMessageWithAttachments:@[ linkPreviewDraft:(nullable nullable OWSLinkPreviewDraft *)linkPreviewDraft
attachment, transaction:(YapDatabaseReadTransaction *)transaction
]
messageBody:attachment.captionText
inThread:thread
quotedReplyModel:quotedReplyModel];
}
+ (TSOutgoingMessage *)enqueueMessageWithAttachments:(NSArray<SignalAttachment *> *)attachments
messageBody:(nullable NSString *)messageBody
inThread:(TSThread *)thread
quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel
{ {
OWSAssertIsOnMainThread(); OWSAssertIsOnMainThread();
OWSAssertDebug(attachments.count > 0);
OWSAssertDebug(thread); OWSAssertDebug(thread);
for (SignalAttachment *attachment in attachments) {
OWSAssertDebug(!attachment.hasError); NSString *truncatedText;
OWSAssertDebug(attachment.mimeType.length > 0); NSArray<SignalAttachment *> *attachments = attachmentsParam;
if ([fullMessageText lengthOfBytesUsingEncoding:NSUTF8StringEncoding] < kOversizeTextMessageSizeThreshold) {
truncatedText = fullMessageText;
} else {
truncatedText = [fullMessageText ows_truncatedToByteCount:kOversizeTextMessageSizeThreshold];
DataSource *_Nullable dataSource = [DataSourceValue dataSourceWithOversizeText:fullMessageText];
if (dataSource) {
SignalAttachment *oversizeTextAttachment =
[SignalAttachment attachmentWithDataSource:dataSource dataUTI:kOversizeTextAttachmentUTI];
attachments = [attachmentsParam arrayByAddingObject:oversizeTextAttachment];
} else {
OWSFailDebug(@"dataSource was unexpectedly nil");
}
} }
OWSDisappearingMessagesConfiguration *configuration = OWSDisappearingMessagesConfiguration *configuration =
[OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId]; [OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId transaction:transaction];
uint32_t expiresInSeconds = (configuration.isEnabled ? configuration.durationSeconds : 0); uint32_t expiresInSeconds = (configuration.isEnabled ? configuration.durationSeconds : 0);
for (SignalAttachment *attachment in attachments) {
OWSAssertDebug(!attachment.hasError);
OWSAssertDebug(attachment.mimeType.length > 0);
}
BOOL isVoiceMessage = (attachments.count == 1 && attachments.lastObject.isVoiceMessage); BOOL isVoiceMessage = (attachments.count == 1 && attachments.lastObject.isVoiceMessage);
TSOutgoingMessage *message = TSOutgoingMessage *message =
[[TSOutgoingMessage alloc] initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp] [[TSOutgoingMessage alloc] initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
inThread:thread inThread:thread
messageBody:messageBody messageBody:truncatedText
attachmentIds:[NSMutableArray new] attachmentIds:[NSMutableArray new]
expiresInSeconds:expiresInSeconds expiresInSeconds:expiresInSeconds
expireStartedAt:0 expireStartedAt:0
@ -180,12 +149,40 @@ NS_ASSUME_NONNULL_BEGIN
contactShare:nil contactShare:nil
linkPreview:nil]; linkPreview:nil];
NSMutableArray<OWSOutgoingAttachmentInfo *> *attachmentInfos = [NSMutableArray new]; [BenchManager
for (SignalAttachment *attachment in attachments) { benchAsyncWithTitle:@"Saving outgoing message"
OWSOutgoingAttachmentInfo *attachmentInfo = [attachment buildOutgoingAttachmentInfoWithMessage:message]; block:^(void (^benchmarkCompletion)(void)) {
[attachmentInfos addObject:attachmentInfo]; // To avoid blocking the send flow, we dispatch an async write from within this read
} // transaction
[self.messageSenderJobQueue addMediaMessage:message attachmentInfos:attachmentInfos isTemporaryAttachment:NO]; [self.dbConnection
asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull writeTransaction) {
[message saveWithTransaction:writeTransaction];
OWSLinkPreview *_Nullable linkPreview =
[self linkPreviewForLinkPreviewDraft:linkPreviewDraft
transaction:writeTransaction];
if (linkPreview) {
[message updateWithLinkPreview:linkPreview transaction:writeTransaction];
}
if (attachments.count == 0) {
[self.messageSenderJobQueue addMessage:message transaction:writeTransaction];
} else {
NSMutableArray<OWSOutgoingAttachmentInfo *> *attachmentInfos =
[NSMutableArray new];
for (SignalAttachment *attachment in attachments) {
OWSOutgoingAttachmentInfo *attachmentInfo =
[attachment buildOutgoingAttachmentInfoWithMessage:message];
[attachmentInfos addObject:attachmentInfo];
}
[self.messageSenderJobQueue addMediaMessage:message
attachmentInfos:attachmentInfos
isTemporaryAttachment:NO];
}
}
completionBlock:benchmarkCompletion];
}];
return message; return message;
} }

@ -45,6 +45,9 @@ NS_ASSUME_NONNULL_BEGIN
- (BOOL)hasAttachments; - (BOOL)hasAttachments;
- (NSArray<TSAttachment *> *)attachmentsWithTransaction:(YapDatabaseReadTransaction *)transaction; - (NSArray<TSAttachment *> *)attachmentsWithTransaction:(YapDatabaseReadTransaction *)transaction;
- (NSArray<TSAttachment *> *)mediaAttachmentsWithTransaction:(YapDatabaseReadTransaction *)transaction;
- (nullable TSAttachment *)oversizeTextAttachmentWithTransaction:(YapDatabaseReadTransaction *)transaction;
- (void)removeAttachment:(TSAttachment *)attachment - (void)removeAttachment:(TSAttachment *)attachment
transaction:(YapDatabaseReadWriteTransaction *)transaction NS_SWIFT_NAME(removeAttachment(_:transaction:)); transaction:(YapDatabaseReadWriteTransaction *)transaction NS_SWIFT_NAME(removeAttachment(_:transaction:));

@ -219,6 +219,26 @@ static const NSUInteger OWSMessageSchemaVersion = 4;
return [attachments copy]; return [attachments copy];
} }
- (NSArray<TSAttachment *> *)attachmentsWithTransaction:(YapDatabaseReadTransaction *)transaction
contentType:(NSString *)contentType
{
NSArray<TSAttachment *> *attachments = [self attachmentsWithTransaction:transaction];
return [attachments filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(TSAttachment *evaluatedObject,
NSDictionary<NSString *, id> *_Nullable bindings) {
return [evaluatedObject.contentType isEqualToString:contentType];
}]];
}
- (NSArray<TSAttachment *> *)attachmentsWithTransaction:(YapDatabaseReadTransaction *)transaction
exceptContentType:(NSString *)contentType
{
NSArray<TSAttachment *> *attachments = [self attachmentsWithTransaction:transaction];
return [attachments filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(TSAttachment *evaluatedObject,
NSDictionary<NSString *, id> *_Nullable bindings) {
return ![evaluatedObject.contentType isEqualToString:contentType];
}]];
}
- (void)removeAttachment:(TSAttachment *)attachment transaction:(YapDatabaseReadWriteTransaction *)transaction; - (void)removeAttachment:(TSAttachment *)attachment transaction:(YapDatabaseReadWriteTransaction *)transaction;
{ {
OWSAssertDebug([self.attachmentIds containsObject:attachment.uniqueId]); OWSAssertDebug([self.attachmentIds containsObject:attachment.uniqueId]);
@ -257,15 +277,24 @@ static const NSUInteger OWSMessageSchemaVersion = 4;
} }
} }
- (nullable TSAttachment *)oversizeTextAttachmentWithTransaction:(YapDatabaseReadTransaction *)transaction
{
return [self attachmentsWithTransaction:transaction contentType:OWSMimeTypeOversizeTextMessage].firstObject;
}
- (NSArray<TSAttachment *> *)mediaAttachmentsWithTransaction:(YapDatabaseReadTransaction *)transaction
{
return [self attachmentsWithTransaction:transaction exceptContentType:OWSMimeTypeOversizeTextMessage];
}
- (nullable NSString *)oversizeTextWithTransaction:(YapDatabaseReadTransaction *)transaction - (nullable NSString *)oversizeTextWithTransaction:(YapDatabaseReadTransaction *)transaction
{ {
if (self.attachmentIds.count != 1) { TSAttachment *_Nullable attachment = [self oversizeTextAttachmentWithTransaction:transaction];
if (!attachment) {
return nil; return nil;
} }
TSAttachment *_Nullable attachment = [self attachmentsWithTransaction:transaction].firstObject; if (![attachment isKindOfClass:TSAttachmentStream.class]) {
if (![OWSMimeTypeOversizeTextMessage isEqualToString:attachment.contentType]
|| ![attachment isKindOfClass:TSAttachmentStream.class]) {
return nil; return nil;
} }

Loading…
Cancel
Save