session-ios/SignalServiceKit/src/Messages/OWSMessageManager.m

1156 lines
53 KiB
Mathematica
Raw Normal View History

//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
2015-12-07 03:31:43 +01:00
#import "OWSMessageManager.h"
#import "ContactsManagerProtocol.h"
#import "Cryptography.h"
#import "MimeTypeUtil.h"
#import "NSDate+OWS.h"
#import "NotificationsProtocol.h"
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
#import "OWSAttachmentsProcessor.h"
2017-04-03 20:42:04 +02:00
#import "OWSBlockingManager.h"
#import "OWSCallMessageHandler.h"
#import "OWSDevice.h"
#import "OWSDisappearingConfigurationUpdateInfoMessage.h"
#import "OWSDisappearingMessagesConfiguration.h"
#import "OWSDisappearingMessagesJob.h"
#import "OWSIdentityManager.h"
2017-02-16 00:32:27 +01:00
#import "OWSIncomingMessageFinder.h"
#import "OWSIncomingSentMessageTranscript.h"
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
#import "OWSMessageSender.h"
#import "OWSReadReceiptManager.h"
#import "OWSRecordTranscriptJob.h"
#import "OWSSyncConfigurationMessage.h"
#import "OWSSyncContactsMessage.h"
#import "OWSSyncGroupsMessage.h"
#import "OWSSyncGroupsRequestMessage.h"
#import "ProfileManagerProtocol.h"
#import "TSAccountManager.h"
#import "TSContactThread.h"
2015-12-07 03:31:43 +01:00
#import "TSDatabaseView.h"
#import "TSGroupModel.h"
#import "TSGroupThread.h"
#import "TSIncomingMessage.h"
2015-12-07 03:31:43 +01:00
#import "TSInfoMessage.h"
#import "TSNetworkManager.h"
#import "TSOutgoingMessage.h"
#import "TSStorageManager+SessionStore.h"
#import "TSStorageManager.h"
2015-12-07 03:31:43 +01:00
#import "TextSecureKitEnv.h"
NS_ASSUME_NONNULL_BEGIN
@interface OWSMessageManager ()
@property (nonatomic, readonly) id<OWSCallMessageHandler> callMessageHandler;
@property (nonatomic, readonly) id<ContactsManagerProtocol> contactsManager;
@property (nonatomic, readonly) TSStorageManager *storageManager;
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
@property (nonatomic, readonly) OWSMessageSender *messageSender;
2017-02-16 00:32:27 +01:00
@property (nonatomic, readonly) OWSIncomingMessageFinder *incomingMessageFinder;
2017-04-03 20:42:04 +02:00
@property (nonatomic, readonly) OWSBlockingManager *blockingManager;
@property (nonatomic, readonly) OWSIdentityManager *identityManager;
@property (nonatomic, readonly) TSNetworkManager *networkManager;
@property (nonatomic, readonly) YapDatabaseConnection *dbConnection;
@end
#pragma mark -
@implementation OWSMessageManager
2015-12-07 03:31:43 +01:00
+ (instancetype)sharedManager
{
static OWSMessageManager *sharedMyManager = nil;
2015-12-07 03:31:43 +01:00
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
sharedMyManager = [[self alloc] initDefault];
2015-12-07 03:31:43 +01:00
});
return sharedMyManager;
}
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
- (instancetype)initDefault
{
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
TSNetworkManager *networkManager = [TSNetworkManager sharedManager];
TSStorageManager *storageManager = [TSStorageManager sharedManager];
id<ContactsManagerProtocol> contactsManager = [TextSecureKitEnv sharedEnv].contactsManager;
id<OWSCallMessageHandler> callMessageHandler = [TextSecureKitEnv sharedEnv].callMessageHandler;
OWSIdentityManager *identityManager = [OWSIdentityManager sharedManager];
OWSMessageSender *messageSender = [TextSecureKitEnv sharedEnv].messageSender;
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
return [self initWithNetworkManager:networkManager
storageManager:storageManager
callMessageHandler:callMessageHandler
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
contactsManager:contactsManager
identityManager:identityManager
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
messageSender:messageSender];
}
- (instancetype)initWithNetworkManager:(TSNetworkManager *)networkManager
storageManager:(TSStorageManager *)storageManager
callMessageHandler:(id<OWSCallMessageHandler>)callMessageHandler
contactsManager:(id<ContactsManagerProtocol>)contactsManager
identityManager:(OWSIdentityManager *)identityManager
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
messageSender:(OWSMessageSender *)messageSender
{
2015-12-07 03:31:43 +01:00
self = [super init];
if (!self) {
return self;
2015-12-07 03:31:43 +01:00
}
_storageManager = storageManager;
_networkManager = networkManager;
_callMessageHandler = callMessageHandler;
_contactsManager = contactsManager;
_identityManager = identityManager;
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
_messageSender = messageSender;
_dbConnection = storageManager.newDatabaseConnection;
2017-02-16 00:32:27 +01:00
_incomingMessageFinder = [[OWSIncomingMessageFinder alloc] initWithDatabase:storageManager.database];
2017-04-03 20:42:04 +02:00
_blockingManager = [OWSBlockingManager sharedManager];
OWSSingletonAssert();
[self startObserving];
2015-12-07 03:31:43 +01:00
return self;
}
- (void)startObserving
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(yapDatabaseModified:)
name:YapDatabaseModifiedNotification
object:nil];
}
- (void)yapDatabaseModified:(NSNotification *)notification
{
[self updateApplicationBadgeCount];
}
#pragma mark - Blocking
- (BOOL)isEnvelopeBlocked:(OWSSignalServiceProtosEnvelope *)envelope
{
OWSAssert(envelope);
2017-09-20 17:48:37 +02:00
return [_blockingManager isRecipientIdBlocked:envelope.source];
}
#pragma mark - message handling
- (void)processEnvelope:(OWSSignalServiceProtosEnvelope *)envelope
plaintextData:(NSData *_Nullable)plaintextData
transaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssert(envelope);
OWSAssert(transaction);
OWSAssert([TSAccountManager isRegistered]);
2017-02-10 01:35:10 +01:00
2017-11-08 20:04:51 +01:00
DDLogInfo(@"%@ handling decrypted envelope: %@", self.logTag, [self descriptionForEnvelope:envelope]);
2015-12-07 03:31:43 +01:00
OWSAssert(envelope.source.length > 0);
OWSAssert(![self isEnvelopeBlocked:envelope]);
2015-12-07 03:31:43 +01:00
switch (envelope.type) {
case OWSSignalServiceProtosEnvelopeTypeCiphertext:
case OWSSignalServiceProtosEnvelopeTypePrekeyBundle:
if (plaintextData) {
[self handleEnvelope:envelope plaintextData:plaintextData transaction:transaction];
} else {
OWSFail(
2017-11-08 20:04:51 +01:00
@"%@ missing decrypted data for envelope: %@", self.logTag, [self descriptionForEnvelope:envelope]);
}
break;
case OWSSignalServiceProtosEnvelopeTypeReceipt:
OWSAssert(!plaintextData);
[self handleDeliveryReceipt:envelope transaction:transaction];
break;
// Other messages are just dismissed for now.
case OWSSignalServiceProtosEnvelopeTypeKeyExchange:
DDLogWarn(@"Received Key Exchange Message, not supported");
break;
case OWSSignalServiceProtosEnvelopeTypeUnknown:
DDLogWarn(@"Received an unknown message type");
break;
default:
DDLogWarn(@"Received unhandled envelope type: %d", (int)envelope.type);
break;
}
}
- (void)handleDeliveryReceipt:(OWSSignalServiceProtosEnvelope *)envelope
transaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssert(envelope);
OWSAssert(transaction);
// Old-style delivery notices don't include a "delivery timestamp".
2017-09-27 20:19:26 +02:00
[self processDeliveryReceiptsFromRecipientId:envelope.source
sentTimestamps:@[
@(envelope.timestamp),
]
deliveryTimestamp:nil
transaction:transaction];
}
2017-09-27 20:19:26 +02:00
// deliveryTimestamp is an optional parameter, since legacy
// delivery receipts don't have a "delivery timestamp". Those
// messages repurpose the "timestamp" field to indicate when the
// corresponding message was originally sent.
- (void)processDeliveryReceiptsFromRecipientId:(NSString *)recipientId
sentTimestamps:(NSArray<NSNumber *> *)sentTimestamps
deliveryTimestamp:(NSNumber *_Nullable)deliveryTimestamp
transaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssert(recipientId);
OWSAssert(sentTimestamps);
OWSAssert(transaction);
for (NSNumber *nsTimestamp in sentTimestamps) {
uint64_t timestamp = [nsTimestamp unsignedLongLongValue];
NSArray<TSOutgoingMessage *> *messages
= (NSArray<TSOutgoingMessage *> *)[TSInteraction interactionsWithTimestamp:timestamp
ofClass:[TSOutgoingMessage class]
withTransaction:transaction];
if (messages.count < 1) {
2017-09-27 20:19:26 +02:00
// The service sends delivery receipts for "unpersisted" messages
// like group updates, so these errors are expected to a certain extent.
2017-09-27 20:19:26 +02:00
//
// TODO: persist "early" delivery receipts.
2017-11-08 20:04:51 +01:00
DDLogInfo(@"%@ Missing message for delivery receipt: %llu", self.logTag, timestamp);
} else {
if (messages.count > 1) {
2017-11-08 20:04:51 +01:00
DDLogInfo(@"%@ More than one message (%zd) for delivery receipt: %llu",
self.logTag,
messages.count,
timestamp);
}
for (TSOutgoingMessage *outgoingMessage in messages) {
[outgoingMessage updateWithDeliveredToRecipientId:recipientId
deliveryTimestamp:deliveryTimestamp
transaction:transaction];
}
2017-09-22 21:15:04 +02:00
}
}
}
- (void)handleEnvelope:(OWSSignalServiceProtosEnvelope *)envelope
plaintextData:(NSData *)plaintextData
transaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssert(envelope);
OWSAssert(plaintextData);
OWSAssert(transaction);
OWSAssert(envelope.hasTimestamp && envelope.timestamp > 0);
OWSAssert(envelope.hasSource && envelope.source.length > 0);
OWSAssert(envelope.hasSourceDevice && envelope.sourceDevice > 0);
2017-02-16 00:32:27 +01:00
BOOL duplicateEnvelope = [self.incomingMessageFinder existsMessageWithTimestamp:envelope.timestamp
sourceId:envelope.source
sourceDeviceId:envelope.sourceDevice
transaction:transaction];
2017-02-16 00:32:27 +01:00
if (duplicateEnvelope) {
DDLogInfo(@"%@ Ignoring previously received envelope from %@ with timestamp: %llu",
2017-11-08 20:04:51 +01:00
self.logTag,
envelopeAddress(envelope),
envelope.timestamp);
2017-02-16 00:32:27 +01:00
return;
}
if (envelope.hasContent) {
OWSSignalServiceProtosContent *content = [OWSSignalServiceProtosContent parseFromData:plaintextData];
2017-11-08 20:04:51 +01:00
DDLogInfo(@"%@ handling content: <Content: %@>", self.logTag, [self descriptionForContent:content]);
if (content.hasSyncMessage) {
[self handleIncomingEnvelope:envelope withSyncMessage:content.syncMessage transaction:transaction];
[[OWSDeviceManager sharedManager] setHasReceivedSyncMessage];
} else if (content.hasDataMessage) {
[self handleIncomingEnvelope:envelope withDataMessage:content.dataMessage transaction:transaction];
} else if (content.hasCallMessage) {
[self handleIncomingEnvelope:envelope withCallMessage:content.callMessage];
} else if (content.hasNullMessage) {
2017-11-08 20:04:51 +01:00
DDLogInfo(@"%@ Received null message.", self.logTag);
} else if (content.hasReceiptMessage) {
[self handleIncomingEnvelope:envelope withReceiptMessage:content.receiptMessage transaction:transaction];
} else {
2017-11-08 20:04:51 +01:00
DDLogWarn(@"%@ Ignoring envelope. Content with no known payload", self.logTag);
}
} else if (envelope.hasLegacyMessage) { // DEPRECATED - Remove after all clients have been upgraded.
OWSSignalServiceProtosDataMessage *dataMessage =
[OWSSignalServiceProtosDataMessage parseFromData:plaintextData];
2017-11-08 20:04:51 +01:00
DDLogInfo(
@"%@ handling message: <DataMessage: %@ />", self.logTag, [self descriptionForDataMessage:dataMessage]);
[self handleIncomingEnvelope:envelope withDataMessage:dataMessage transaction:transaction];
} else {
2017-08-04 18:01:45 +02:00
OWSProdInfoWEnvelope([OWSAnalyticsEvents messageManagerErrorEnvelopeNoActionablePayload], envelope);
2015-12-07 03:31:43 +01:00
}
}
- (void)handleIncomingEnvelope:(OWSSignalServiceProtosEnvelope *)envelope
withDataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage
transaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssert(envelope);
OWSAssert(dataMessage);
OWSAssert(transaction);
if ([dataMessage hasProfileKey]) {
NSData *profileKey = [dataMessage profileKey];
NSString *recipientId = envelope.source;
if (profileKey.length == kAES256_KeyByteLength) {
[self.profileManager setProfileKeyData:profileKey forRecipientId:recipientId];
} else {
OWSFail(
@"Unexpected profile key length:%lu on message from:%@", (unsigned long)profileKey.length, recipientId);
}
}
if (dataMessage.hasGroup) {
2017-10-04 16:06:38 +02:00
TSGroupThread *_Nullable groupThread =
[TSGroupThread threadWithGroupId:dataMessage.group.id transaction:transaction];
2017-10-04 16:06:38 +02:00
if (!groupThread) {
// Unknown group.
if (dataMessage.group.type == OWSSignalServiceProtosGroupContextTypeUpdate) {
// Accept group updates for unknown groups.
} else if (dataMessage.group.type == OWSSignalServiceProtosGroupContextTypeDeliver) {
[self sendGroupInfoRequest:dataMessage.group.id envelope:envelope transaction:transaction];
return;
2017-10-04 16:06:38 +02:00
} else {
2017-11-08 20:04:51 +01:00
DDLogInfo(@"%@ Ignoring group message for unknown group from: %@", self.logTag, envelope.source);
return;
}
2015-12-07 03:31:43 +01:00
}
}
if ((dataMessage.flags & OWSSignalServiceProtosDataMessageFlagsEndSession) != 0) {
[self handleEndSessionMessageWithEnvelope:envelope dataMessage:dataMessage transaction:transaction];
} else if ((dataMessage.flags & OWSSignalServiceProtosDataMessageFlagsExpirationTimerUpdate) != 0) {
[self handleExpirationTimerUpdateMessageWithEnvelope:envelope dataMessage:dataMessage transaction:transaction];
} else if ((dataMessage.flags & OWSSignalServiceProtosDataMessageFlagsProfileKeyUpdate) != 0) {
[self handleProfileKeyMessageWithEnvelope:envelope dataMessage:dataMessage];
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
} else if (dataMessage.attachments.count > 0) {
[self handleReceivedMediaWithEnvelope:envelope dataMessage:dataMessage transaction:transaction];
2015-12-07 03:31:43 +01:00
} else {
[self handleReceivedTextMessageWithEnvelope:envelope dataMessage:dataMessage transaction:transaction];
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
if ([self isDataMessageGroupAvatarUpdate:dataMessage]) {
2017-11-08 20:04:51 +01:00
DDLogVerbose(@"%@ Data message had group avatar attachment", self.logTag);
[self handleReceivedGroupAvatarUpdateWithEnvelope:envelope dataMessage:dataMessage transaction:transaction];
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
}
}
}
- (void)sendGroupInfoRequest:(NSData *)groupId
envelope:(OWSSignalServiceProtosEnvelope *)envelope
transaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssert(groupId.length > 0);
OWSAssert(envelope);
OWSAssert(transaction);
if (groupId.length < 1) {
return;
}
// FIXME: https://github.com/WhisperSystems/Signal-iOS/issues/1340
2017-11-08 20:04:51 +01:00
DDLogInfo(@"%@ Sending group info request: %@", self.logTag, envelopeAddress(envelope));
NSString *recipientId = envelope.source;
TSThread *thread = [TSContactThread getOrCreateThreadWithContactId:recipientId transaction:transaction];
OWSSyncGroupsRequestMessage *syncGroupsRequestMessage =
[[OWSSyncGroupsRequestMessage alloc] initWithThread:thread groupId:groupId];
2017-11-15 19:21:31 +01:00
[self.messageSender enqueueMessage:syncGroupsRequestMessage
success:^{
2017-11-08 20:04:51 +01:00
DDLogWarn(@"%@ Successfully sent Request Group Info message.", self.logTag);
}
failure:^(NSError *error) {
2017-11-08 20:04:51 +01:00
DDLogError(@"%@ Failed to send Request Group Info message with error: %@", self.logTag, error);
}];
}
- (id<ProfileManagerProtocol>)profileManager
{
return [TextSecureKitEnv sharedEnv].profileManager;
}
- (void)handleIncomingEnvelope:(OWSSignalServiceProtosEnvelope *)envelope
withReceiptMessage:(OWSSignalServiceProtosReceiptMessage *)receiptMessage
transaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssert(envelope);
OWSAssert(receiptMessage);
OWSAssert(transaction);
PBArray *messageTimestamps = receiptMessage.timestamp;
NSMutableArray<NSNumber *> *sentTimestamps = [NSMutableArray new];
for (int i = 0; i < messageTimestamps.count; i++) {
UInt64 timestamp = [messageTimestamps uint64AtIndex:i];
[sentTimestamps addObject:@(timestamp)];
}
switch (receiptMessage.type) {
case OWSSignalServiceProtosReceiptMessageTypeDelivery:
2017-11-08 20:04:51 +01:00
DDLogVerbose(@"%@ Processing receipt message with delivery receipts.", self.logTag);
2017-09-27 20:19:26 +02:00
[self processDeliveryReceiptsFromRecipientId:envelope.source
sentTimestamps:sentTimestamps
deliveryTimestamp:@(envelope.timestamp)
transaction:transaction];
return;
case OWSSignalServiceProtosReceiptMessageTypeRead:
2017-11-08 20:04:51 +01:00
DDLogVerbose(@"%@ Processing receipt message with read receipts.", self.logTag);
[OWSReadReceiptManager.sharedManager processReadReceiptsFromRecipientId:envelope.source
sentTimestamps:sentTimestamps
readTimestamp:envelope.timestamp];
break;
default:
2017-11-08 20:04:51 +01:00
DDLogInfo(@"%@ Ignoring receipt message of unknown type: %d.", self.logTag, (int)receiptMessage.type);
return;
}
}
- (void)handleIncomingEnvelope:(OWSSignalServiceProtosEnvelope *)envelope
withCallMessage:(OWSSignalServiceProtosCallMessage *)callMessage
{
OWSAssert(envelope);
OWSAssert(callMessage);
if ([callMessage hasProfileKey]) {
NSData *profileKey = [callMessage profileKey];
NSString *recipientId = envelope.source;
[self.profileManager setProfileKeyData:profileKey forRecipientId:recipientId];
}
2017-09-20 17:48:37 +02:00
// By dispatching async, we introduce the possibility that these messages might be lost
// if the app exits before this block is executed. This is fine, since the call by
// definition will end if the app exits.
dispatch_async(dispatch_get_main_queue(), ^{
if (callMessage.hasOffer) {
[self.callMessageHandler receivedOffer:callMessage.offer fromCallerId:envelope.source];
} else if (callMessage.hasAnswer) {
[self.callMessageHandler receivedAnswer:callMessage.answer fromCallerId:envelope.source];
} else if (callMessage.iceUpdate.count > 0) {
for (OWSSignalServiceProtosCallMessageIceUpdate *iceUpdate in callMessage.iceUpdate) {
[self.callMessageHandler receivedIceUpdate:iceUpdate fromCallerId:envelope.source];
}
} else if (callMessage.hasHangup) {
2017-11-08 20:04:51 +01:00
DDLogVerbose(@"%@ Received CallMessage with Hangup.", self.logTag);
[self.callMessageHandler receivedHangup:callMessage.hangup fromCallerId:envelope.source];
} else if (callMessage.hasBusy) {
[self.callMessageHandler receivedBusy:callMessage.busy fromCallerId:envelope.source];
} else {
OWSProdInfoWEnvelope([OWSAnalyticsEvents messageManagerErrorCallMessageNoActionablePayload], envelope);
}
});
}
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
- (void)handleReceivedGroupAvatarUpdateWithEnvelope:(OWSSignalServiceProtosEnvelope *)envelope
dataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage
transaction:(YapDatabaseReadWriteTransaction *)transaction
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
{
OWSAssert(envelope);
OWSAssert(dataMessage);
OWSAssert(transaction);
TSGroupThread *_Nullable groupThread =
[TSGroupThread threadWithGroupId:dataMessage.group.id transaction:transaction];
if (!groupThread) {
2017-11-08 20:04:51 +01:00
OWSFail(@"%@ Missing group for group avatar update", self.logTag);
return;
}
2017-08-04 18:01:45 +02:00
OWSAssert(groupThread);
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
OWSAttachmentsProcessor *attachmentsProcessor =
[[OWSAttachmentsProcessor alloc] initWithAttachmentProtos:@[ dataMessage.group.avatar ]
timestamp:envelope.timestamp
relay:envelope.relay
thread:groupThread
networkManager:self.networkManager
storageManager:self.storageManager
transaction:transaction];
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
if (!attachmentsProcessor.hasSupportedAttachments) {
2017-11-08 20:04:51 +01:00
DDLogWarn(@"%@ received unsupported group avatar envelope", self.logTag);
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
return;
2015-12-07 03:31:43 +01:00
}
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
[attachmentsProcessor fetchAttachmentsForMessage:nil
transaction:transaction
2017-05-10 16:05:01 +02:00
success:^(TSAttachmentStream *attachmentStream) {
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
[groupThread updateAvatarWithAttachmentStream:attachmentStream];
}
2017-05-10 16:05:01 +02:00
failure:^(NSError *error) {
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
DDLogError(@"%@ failed to fetch attachments for group avatar sent at: %llu. with error: %@",
2017-11-08 20:04:51 +01:00
self.logTag,
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
envelope.timestamp,
error);
}];
}
- (void)handleReceivedMediaWithEnvelope:(OWSSignalServiceProtosEnvelope *)envelope
dataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage
transaction:(YapDatabaseReadWriteTransaction *)transaction
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
{
OWSAssert(envelope);
OWSAssert(dataMessage);
OWSAssert(transaction);
TSThread *_Nullable thread = [self threadForEnvelope:envelope dataMessage:dataMessage transaction:transaction];
if (!thread) {
2017-11-08 20:04:51 +01:00
OWSFail(@"%@ ignoring media message for unknown group.", self.logTag);
return;
}
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
OWSAttachmentsProcessor *attachmentsProcessor =
[[OWSAttachmentsProcessor alloc] initWithAttachmentProtos:dataMessage.attachments
timestamp:envelope.timestamp
relay:envelope.relay
thread:thread
networkManager:self.networkManager
storageManager:self.storageManager
transaction:transaction];
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
if (!attachmentsProcessor.hasSupportedAttachments) {
2017-11-08 20:04:51 +01:00
DDLogWarn(@"%@ received unsupported media envelope", self.logTag);
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
return;
}
2017-05-10 16:05:01 +02:00
TSIncomingMessage *_Nullable createdMessage =
[self handleReceivedEnvelope:envelope
withDataMessage:dataMessage
attachmentIds:attachmentsProcessor.supportedAttachmentIds
transaction:transaction];
2017-05-10 16:05:01 +02:00
if (!createdMessage) {
return;
}
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
2017-11-08 20:04:51 +01:00
DDLogDebug(@"%@ incoming attachment message: %@", self.logTag, createdMessage.debugDescription);
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
[attachmentsProcessor fetchAttachmentsForMessage:createdMessage
transaction:transaction
2017-05-10 16:05:01 +02:00
success:^(TSAttachmentStream *attachmentStream) {
2017-11-08 20:04:51 +01:00
DDLogDebug(@"%@ successfully fetched attachment: %@ for message: %@",
self.logTag,
attachmentStream,
createdMessage);
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
}
2017-05-10 16:05:01 +02:00
failure:^(NSError *error) {
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
DDLogError(
2017-11-08 20:04:51 +01:00
@"%@ failed to fetch attachments for message: %@ with error: %@", self.logTag, createdMessage, error);
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
}];
2015-12-07 03:31:43 +01:00
}
- (void)handleIncomingEnvelope:(OWSSignalServiceProtosEnvelope *)envelope
withSyncMessage:(OWSSignalServiceProtosSyncMessage *)syncMessage
transaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssert(envelope);
OWSAssert(syncMessage);
OWSAssert(transaction);
2017-08-04 18:01:45 +02:00
OWSAssert([TSAccountManager isRegistered]);
2017-08-04 18:01:45 +02:00
NSString *localNumber = [TSAccountManager localNumber];
if (![localNumber isEqualToString:envelope.source]) {
2017-08-04 18:01:45 +02:00
// Sync messages should only come from linked devices.
OWSProdErrorWEnvelope([OWSAnalyticsEvents messageManagerErrorSyncMessageFromUnknownSource], envelope);
2017-08-04 18:01:45 +02:00
return;
}
if (syncMessage.hasSent) {
OWSIncomingSentMessageTranscript *transcript =
[[OWSIncomingSentMessageTranscript alloc] initWithProto:syncMessage.sent relay:envelope.relay];
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
OWSRecordTranscriptJob *recordJob =
[[OWSRecordTranscriptJob alloc] initWithIncomingSentMessageTranscript:transcript];
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
OWSSignalServiceProtosDataMessage *dataMessage = syncMessage.sent.message;
OWSAssert(dataMessage);
NSString *destination = syncMessage.sent.destination;
if (dataMessage && destination.length > 0 && dataMessage.hasProfileKey) {
// If we observe a linked device sending our profile key to another
// user, we can infer that that user belongs in our profile whitelist.
if (dataMessage.hasGroup) {
[self.profileManager addGroupIdToProfileWhitelist:dataMessage.group.id];
} else {
[self.profileManager addUserToProfileWhitelist:destination];
}
}
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
if ([self isDataMessageGroupAvatarUpdate:syncMessage.sent.message]) {
2017-05-10 16:05:01 +02:00
[recordJob runWithAttachmentHandler:^(TSAttachmentStream *attachmentStream) {
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
TSGroupThread *_Nullable groupThread =
[TSGroupThread threadWithGroupId:dataMessage.group.id transaction:transaction];
if (!groupThread) {
2017-11-08 20:04:51 +01:00
OWSFail(@"%@ ignoring sync group avatar update for unknown group.", self.logTag);
return;
}
[groupThread updateAvatarWithAttachmentStream:attachmentStream transaction:transaction];
}];
}
transaction:transaction];
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
} else {
2017-05-10 16:05:01 +02:00
[recordJob runWithAttachmentHandler:^(TSAttachmentStream *attachmentStream) {
2017-11-08 20:04:51 +01:00
DDLogDebug(@"%@ successfully fetched transcript attachment: %@", self.logTag, attachmentStream);
}
transaction:transaction];
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
}
2016-09-01 16:28:35 +02:00
} else if (syncMessage.hasRequest) {
if (syncMessage.request.type == OWSSignalServiceProtosSyncMessageRequestTypeContacts) {
// We respond asynchronously because populating the sync message will
// create transactions and it's not practical (due to locking in the OWSIdentityManager)
// to plumb our transaction through.
//
// In rare cases this means we won't respond to the sync request, but that's
// acceptable.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
OWSSyncContactsMessage *syncContactsMessage =
[[OWSSyncContactsMessage alloc] initWithSignalAccounts:self.contactsManager.signalAccounts
identityManager:self.identityManager
profileManager:self.profileManager];
DataSource *dataSource =
[DataSourceValue dataSourceWithSyncMessage:[syncContactsMessage buildPlainTextAttachmentData]];
[self.messageSender enqueueTemporaryAttachment:dataSource
contentType:OWSMimeTypeApplicationOctetStream
inMessage:syncContactsMessage
success:^{
DDLogInfo(@"%@ Successfully sent Contacts response syncMessage.", self.logTag);
}
failure:^(NSError *error) {
DDLogError(
@"%@ Failed to send Contacts response syncMessage with error: %@", self.logTag, error);
}];
});
} else if (syncMessage.request.type == OWSSignalServiceProtosSyncMessageRequestTypeGroups) {
OWSSyncGroupsMessage *syncGroupsMessage = [[OWSSyncGroupsMessage alloc] init];
DataSource *dataSource = [DataSourceValue
dataSourceWithSyncMessage:[syncGroupsMessage buildPlainTextAttachmentDataWithTransaction:transaction]];
2017-11-15 19:21:31 +01:00
[self.messageSender enqueueTemporaryAttachment:dataSource
contentType:OWSMimeTypeApplicationOctetStream
inMessage:syncGroupsMessage
success:^{
2017-11-08 20:04:51 +01:00
DDLogInfo(@"%@ Successfully sent Groups response syncMessage.", self.logTag);
}
failure:^(NSError *error) {
2017-11-08 20:04:51 +01:00
DDLogError(@"%@ Failed to send Groups response syncMessage with error: %@", self.logTag, error);
}];
} else if (syncMessage.request.type == OWSSignalServiceProtosSyncMessageRequestTypeBlocked) {
2017-11-08 20:04:51 +01:00
DDLogInfo(@"%@ Received request for block list", self.logTag);
[_blockingManager syncBlockedPhoneNumbers];
} else if (syncMessage.request.type == OWSSignalServiceProtosSyncMessageRequestTypeConfiguration) {
BOOL areReadReceiptsEnabled =
[[OWSReadReceiptManager sharedManager] areReadReceiptsEnabledWithTransaction:transaction];
OWSSyncConfigurationMessage *syncConfigurationMessage =
[[OWSSyncConfigurationMessage alloc] initWithReadReceiptsEnabled:areReadReceiptsEnabled];
2017-11-15 19:21:31 +01:00
[self.messageSender enqueueMessage:syncConfigurationMessage
success:^{
2017-11-08 20:04:51 +01:00
DDLogInfo(@"%@ Successfully sent Configuration response syncMessage.", self.logTag);
}
failure:^(NSError *error) {
2017-11-08 20:04:51 +01:00
DDLogError(
@"%@ Failed to send Configuration response syncMessage with error: %@", self.logTag, error);
}];
} else {
2017-11-08 20:04:51 +01:00
DDLogWarn(@"%@ ignoring unsupported sync request message", self.logTag);
}
2017-03-31 02:04:19 +02:00
} else if (syncMessage.hasBlocked) {
NSArray<NSString *> *blockedPhoneNumbers = [syncMessage.blocked.numbers copy];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[_blockingManager setBlockedPhoneNumbers:blockedPhoneNumbers sendSyncMessage:NO];
});
2016-09-01 16:28:35 +02:00
} else if (syncMessage.read.count > 0) {
2017-11-08 20:04:51 +01:00
DDLogInfo(@"%@ Received %ld read receipt(s)", self.logTag, (u_long)syncMessage.read.count);
2016-09-01 16:28:35 +02:00
[OWSReadReceiptManager.sharedManager processReadReceiptsFromLinkedDevice:syncMessage.read
transaction:transaction];
} else if (syncMessage.hasVerified) {
2017-11-08 20:04:51 +01:00
DDLogInfo(@"%@ Received verification state for %@", self.logTag, syncMessage.verified.destination);
[self.identityManager processIncomingSyncMessage:syncMessage.verified];
} else {
2017-11-08 20:04:51 +01:00
DDLogWarn(@"%@ Ignoring unsupported sync message.", self.logTag);
}
}
- (void)handleEndSessionMessageWithEnvelope:(OWSSignalServiceProtosEnvelope *)envelope
dataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage
transaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssert(envelope);
OWSAssert(dataMessage);
OWSAssert(transaction);
TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:envelope.source transaction:transaction];
2017-09-20 17:48:37 +02:00
[[[TSInfoMessage alloc] initWithTimestamp:envelope.timestamp
inThread:thread
messageType:TSInfoMessageTypeSessionDidEnd] saveWithTransaction:transaction];
2015-12-07 03:31:43 +01:00
dispatch_async([OWSDispatch sessionStoreQueue], ^{
2017-09-20 17:48:37 +02:00
[self.storageManager deleteAllSessionsForContact:envelope.source];
});
2015-12-07 03:31:43 +01:00
}
- (void)handleExpirationTimerUpdateMessageWithEnvelope:(OWSSignalServiceProtosEnvelope *)envelope
dataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage
transaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssert(envelope);
OWSAssert(dataMessage);
OWSAssert(transaction);
TSThread *_Nullable thread = [self threadForEnvelope:envelope dataMessage:dataMessage transaction:transaction];
if (!thread) {
2017-11-08 20:04:51 +01:00
OWSFail(@"%@ ignoring expiring messages update for unknown group.", self.logTag);
return;
}
OWSDisappearingMessagesConfiguration *disappearingMessagesConfiguration;
if (dataMessage.hasExpireTimer && dataMessage.expireTimer > 0) {
DDLogInfo(@"%@ Expiring messages duration turned to %u for thread %@",
2017-11-08 20:04:51 +01:00
self.logTag,
(unsigned int)dataMessage.expireTimer,
thread);
disappearingMessagesConfiguration =
[[OWSDisappearingMessagesConfiguration alloc] initWithThreadId:thread.uniqueId
enabled:YES
durationSeconds:dataMessage.expireTimer];
} else {
2017-11-08 20:04:51 +01:00
DDLogInfo(@"%@ Expiring messages have been turned off for thread %@", self.logTag, thread);
disappearingMessagesConfiguration = [[OWSDisappearingMessagesConfiguration alloc]
initWithThreadId:thread.uniqueId
enabled:NO
durationSeconds:OWSDisappearingMessagesConfigurationDefaultExpirationDuration];
}
2017-08-04 18:01:45 +02:00
OWSAssert(disappearingMessagesConfiguration);
[disappearingMessagesConfiguration saveWithTransaction:transaction];
NSString *name = [self.contactsManager displayNameForPhoneIdentifier:envelope.source];
OWSDisappearingConfigurationUpdateInfoMessage *message =
[[OWSDisappearingConfigurationUpdateInfoMessage alloc] initWithTimestamp:envelope.timestamp
thread:thread
configuration:disappearingMessagesConfiguration
createdByRemoteName:name];
[message saveWithTransaction:transaction];
2015-12-07 03:31:43 +01:00
}
- (void)handleProfileKeyMessageWithEnvelope:(OWSSignalServiceProtosEnvelope *)envelope
dataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage
{
OWSAssert(envelope);
OWSAssert(dataMessage);
NSString *recipientId = envelope.source;
if (!dataMessage.hasProfileKey) {
2017-11-08 20:04:51 +01:00
OWSFail(
@"%@ received profile key message without profile key from: %@", self.logTag, envelopeAddress(envelope));
return;
}
NSData *profileKey = dataMessage.profileKey;
if (profileKey.length != kAES256_KeyByteLength) {
2017-08-29 00:03:14 +02:00
OWSFail(@"%@ received profile key of unexpected length:%lu from:%@",
2017-11-08 20:04:51 +01:00
self.logTag,
(unsigned long)profileKey.length,
envelopeAddress(envelope));
return;
}
id<ProfileManagerProtocol> profileManager = [TextSecureKitEnv sharedEnv].profileManager;
[profileManager setProfileKeyData:profileKey forRecipientId:recipientId];
}
- (void)handleReceivedTextMessageWithEnvelope:(OWSSignalServiceProtosEnvelope *)envelope
dataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage
transaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssert(envelope);
OWSAssert(dataMessage);
OWSAssert(transaction);
[self handleReceivedEnvelope:envelope withDataMessage:dataMessage attachmentIds:@[] transaction:transaction];
2015-12-07 03:31:43 +01:00
}
- (void)sendGroupUpdateForThread:(TSGroupThread *)gThread message:(TSOutgoingMessage *)message
{
OWSAssert(gThread);
2017-08-04 18:01:45 +02:00
OWSAssert(gThread.groupModel);
OWSAssert(message);
if (gThread.groupModel.groupImage) {
NSData *data = UIImagePNGRepresentation(gThread.groupModel.groupImage);
2017-09-18 21:02:34 +02:00
DataSource *_Nullable dataSource = [DataSourceValue dataSourceWithData:data fileExtension:@"png"];
2017-11-15 19:21:31 +01:00
[self.messageSender enqueueAttachment:dataSource
contentType:OWSMimeTypeImagePng
sourceFilename:nil
inMessage:message
success:^{
2017-11-08 20:04:51 +01:00
DDLogDebug(@"%@ Successfully sent group update with avatar", self.logTag);
}
2017-05-10 16:05:01 +02:00
failure:^(NSError *error) {
2017-11-08 20:04:51 +01:00
DDLogError(@"%@ Failed to send group avatar update with error: %@", self.logTag, error);
}];
} else {
2017-11-15 19:21:31 +01:00
[self.messageSender enqueueMessage:message
success:^{
2017-11-08 20:04:51 +01:00
DDLogDebug(@"%@ Successfully sent group update", self.logTag);
}
2017-05-10 16:05:01 +02:00
failure:^(NSError *error) {
2017-11-08 20:04:51 +01:00
DDLogError(@"%@ Failed to send group update with error: %@", self.logTag, error);
}];
}
}
- (void)handleGroupInfoRequest:(OWSSignalServiceProtosEnvelope *)envelope
dataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage
transaction:(YapDatabaseReadWriteTransaction *)transaction
2017-05-10 16:05:01 +02:00
{
OWSAssert(envelope);
OWSAssert(dataMessage);
OWSAssert(transaction);
2017-05-10 16:05:01 +02:00
OWSAssert(dataMessage.group.type == OWSSignalServiceProtosGroupContextTypeRequestInfo);
NSData *groupId = dataMessage.hasGroup ? dataMessage.group.id : nil;
if (!groupId) {
OWSFail(@"Group info request is missing group id.");
2017-05-10 16:05:01 +02:00
return;
}
2017-11-08 20:04:51 +01:00
DDLogWarn(
@"%@ Received 'Request Group Info' message for group: %@ from: %@", self.logTag, groupId, envelope.source);
2017-05-10 16:05:01 +02:00
TSGroupThread *_Nullable gThread = [TSGroupThread threadWithGroupId:dataMessage.group.id transaction:transaction];
if (!gThread) {
2017-11-08 20:04:51 +01:00
DDLogWarn(@"%@ Unknown group: %@", self.logTag, groupId);
return;
}
// Ensure sender is in the group.
if (![gThread.groupModel.groupMemberIds containsObject:envelope.source]) {
DDLogWarn(@"%@ Ignoring 'Request Group Info' message for non-member of group. %@ not in %@",
2017-11-08 20:04:51 +01:00
self.logTag,
envelope.source,
gThread.groupModel.groupMemberIds);
return;
}
// Ensure we are in the group.
OWSAssert([TSAccountManager isRegistered]);
NSString *localNumber = [TSAccountManager localNumber];
if (![gThread.groupModel.groupMemberIds containsObject:localNumber]) {
2017-11-08 20:04:51 +01:00
DDLogWarn(@"%@ Ignoring 'Request Group Info' message for group we no longer belong to.", self.logTag);
return;
}
2017-05-10 16:05:01 +02:00
NSString *updateGroupInfo =
[gThread.groupModel getInfoStringAboutUpdateTo:gThread.groupModel contactsManager:self.contactsManager];
TSOutgoingMessage *message = [[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
inThread:gThread
groupMetaMessage:TSGroupMessageUpdate];
[message updateWithCustomMessage:updateGroupInfo transaction:transaction];
// Only send this group update to the requester.
[message updateWithSingleGroupRecipient:envelope.source transaction:transaction];
[self sendGroupUpdateForThread:gThread message:message];
2017-05-10 16:05:01 +02:00
}
- (TSIncomingMessage *_Nullable)handleReceivedEnvelope:(OWSSignalServiceProtosEnvelope *)envelope
withDataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage
attachmentIds:(NSArray<NSString *> *)attachmentIds
transaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssert(envelope);
OWSAssert(dataMessage);
OWSAssert(transaction);
uint64_t timestamp = envelope.timestamp;
NSString *body = dataMessage.body;
NSData *groupId = dataMessage.hasGroup ? dataMessage.group.id : nil;
2015-12-07 03:31:43 +01:00
2017-05-10 16:05:01 +02:00
if (dataMessage.group.type == OWSSignalServiceProtosGroupContextTypeRequestInfo) {
[self handleGroupInfoRequest:envelope dataMessage:dataMessage transaction:transaction];
2017-05-10 16:05:01 +02:00
return nil;
}
if (groupId.length > 0) {
NSMutableSet *newMemberIds = [NSMutableSet setWithArray:dataMessage.group.members];
// Group messages create the group if it doesn't already exist.
//
// We distinguish between the old group state (if any) and the new group state.
TSGroupThread *_Nullable oldGroupThread = [TSGroupThread threadWithGroupId:groupId transaction:transaction];
if (oldGroupThread) {
2017-10-04 16:06:38 +02:00
// Don't trust other clients; ensure all known group members remain in the
// group unless it is a "quit" message in which case we should only remove
// the quiting member below.
[newMemberIds addObjectsFromArray:oldGroupThread.groupModel.groupMemberIds];
}
switch (dataMessage.group.type) {
case OWSSignalServiceProtosGroupContextTypeUpdate: {
// Ensures that the thread exists but doesn't update it.
TSGroupThread *newGroupThread =
[TSGroupThread getOrCreateThreadWithGroupId:groupId transaction:transaction];
TSGroupModel *newGroupModel = [[TSGroupModel alloc] initWithTitle:dataMessage.group.name
memberIds:[newMemberIds.allObjects mutableCopy]
2017-10-04 16:06:38 +02:00
image:oldGroupThread.groupModel.groupImage
groupId:dataMessage.group.id];
NSString *updateGroupInfo = [newGroupThread.groupModel getInfoStringAboutUpdateTo:newGroupModel
contactsManager:self.contactsManager];
newGroupThread.groupModel = newGroupModel;
[newGroupThread saveWithTransaction:transaction];
[[[TSInfoMessage alloc] initWithTimestamp:timestamp
inThread:newGroupThread
messageType:TSInfoMessageTypeGroupUpdate
customMessage:updateGroupInfo] saveWithTransaction:transaction];
2017-10-04 16:06:38 +02:00
return nil;
}
case OWSSignalServiceProtosGroupContextTypeQuit: {
if (!oldGroupThread) {
2017-11-08 20:04:51 +01:00
DDLogInfo(@"%@ ignoring quit group message from unknown group.", self.logTag);
return nil;
}
[newMemberIds removeObject:envelope.source];
oldGroupThread.groupModel.groupMemberIds = [newMemberIds.allObjects mutableCopy];
[oldGroupThread saveWithTransaction:transaction];
NSString *nameString = [self.contactsManager displayNameForPhoneIdentifier:envelope.source];
NSString *updateGroupInfo =
[NSString stringWithFormat:NSLocalizedString(@"GROUP_MEMBER_LEFT", @""), nameString];
[[[TSInfoMessage alloc] initWithTimestamp:timestamp
inThread:oldGroupThread
messageType:TSInfoMessageTypeGroupUpdate
customMessage:updateGroupInfo] saveWithTransaction:transaction];
2017-10-04 16:06:38 +02:00
return nil;
}
case OWSSignalServiceProtosGroupContextTypeDeliver: {
if (!oldGroupThread) {
2017-11-08 20:04:51 +01:00
OWSFail(@"%@ ignoring deliver group message from unknown group.", self.logTag);
return nil;
}
if (body.length == 0 && attachmentIds.count < 1) {
DDLogWarn(@"%@ ignoring empty incoming message from: %@ for group: %@ with timestamp: %lu",
2017-11-08 20:04:51 +01:00
self.logTag,
envelopeAddress(envelope),
groupId,
(unsigned long)timestamp);
return nil;
}
DDLogDebug(@"%@ incoming message from: %@ for group: %@ with timestamp: %lu",
2017-11-08 20:04:51 +01:00
self.logTag,
envelopeAddress(envelope),
groupId,
(unsigned long)timestamp);
2017-10-04 16:06:38 +02:00
TSIncomingMessage *incomingMessage =
[[TSIncomingMessage alloc] initWithTimestamp:timestamp
inThread:oldGroupThread
authorId:envelope.source
sourceDeviceId:envelope.sourceDevice
messageBody:body
attachmentIds:attachmentIds
expiresInSeconds:dataMessage.expireTimer];
[self finalizeIncomingMessage:incomingMessage
thread:oldGroupThread
envelope:envelope
dataMessage:dataMessage
attachmentIds:attachmentIds
transaction:transaction];
return incomingMessage;
}
default: {
2017-11-08 20:04:51 +01:00
DDLogWarn(@"%@ Ignoring unknown group message type: %d", self.logTag, (int)dataMessage.group.type);
return nil;
}
}
} else {
if (body.length == 0 && attachmentIds.count < 1) {
DDLogWarn(@"%@ ignoring empty incoming message from: %@ with timestamp: %lu",
2017-11-08 20:04:51 +01:00
self.logTag,
envelopeAddress(envelope),
(unsigned long)timestamp);
return nil;
}
DDLogDebug(@"%@ incoming message from: %@ with timestamp: %lu",
2017-11-08 20:04:51 +01:00
self.logTag,
envelopeAddress(envelope),
(unsigned long)timestamp);
2017-10-04 16:06:38 +02:00
TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:envelope.source
transaction:transaction
relay:envelope.relay];
TSIncomingMessage *incomingMessage = [[TSIncomingMessage alloc] initWithTimestamp:timestamp
inThread:thread
authorId:[thread contactIdentifier]
sourceDeviceId:envelope.sourceDevice
messageBody:body
attachmentIds:attachmentIds
expiresInSeconds:dataMessage.expireTimer];
[self finalizeIncomingMessage:incomingMessage
thread:thread
envelope:envelope
dataMessage:dataMessage
attachmentIds:attachmentIds
transaction:transaction];
return incomingMessage;
}
2017-10-04 16:06:38 +02:00
}
2015-12-07 03:31:43 +01:00
2017-10-04 16:06:38 +02:00
- (void)finalizeIncomingMessage:(TSIncomingMessage *)incomingMessage
thread:(TSThread *)thread
envelope:(OWSSignalServiceProtosEnvelope *)envelope
dataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage
attachmentIds:(NSArray<NSString *> *)attachmentIds
transaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssert(thread);
OWSAssert(incomingMessage);
2017-10-04 16:06:38 +02:00
OWSAssert(envelope);
OWSAssert(dataMessage);
OWSAssert(attachmentIds);
OWSAssert(transaction);
2017-10-04 16:06:38 +02:00
OWSAssert([TSAccountManager isRegistered]);
NSString *localNumber = [TSAccountManager localNumber];
NSString *body = dataMessage.body;
uint64_t timestamp = envelope.timestamp;
if (!thread) {
2017-11-08 20:04:51 +01:00
OWSFail(@"%@ Can't finalize without thread", self.logTag);
2017-10-04 16:06:38 +02:00
return;
}
if (!incomingMessage) {
2017-11-08 20:04:51 +01:00
OWSFail(@"%@ Can't finalize missing message", self.logTag);
2017-10-04 16:06:38 +02:00
return;
}
2017-10-04 16:06:38 +02:00
[incomingMessage saveWithTransaction:transaction];
2017-10-04 16:06:38 +02:00
// Any messages sent from the current user - from this device or another - should be
// automatically marked as read.
BOOL shouldMarkMessageAsRead = [envelope.source isEqualToString:localNumber];
if (shouldMarkMessageAsRead) {
// Don't send a read receipt for messages sent by ourselves.
[incomingMessage markAsReadWithTransaction:transaction sendReadReceipt:NO updateExpiration:YES];
}
2017-11-08 20:04:51 +01:00
DDLogDebug(@"%@ shouldMarkMessageAsRead: %d (%@)", self.logTag, shouldMarkMessageAsRead, envelope.source);
2017-10-04 16:06:38 +02:00
// Other clients allow attachments to be sent along with body, we want the text displayed as a separate
// message
if ([attachmentIds count] > 0 && body != nil && body.length > 0) {
// We want the text to be displayed under the attachment.
uint64_t textMessageTimestamp = timestamp + 1;
TSIncomingMessage *textMessage = [[TSIncomingMessage alloc] initWithTimestamp:textMessageTimestamp
inThread:thread
authorId:envelope.source
sourceDeviceId:envelope.sourceDevice
messageBody:body
attachmentIds:@[]
expiresInSeconds:dataMessage.expireTimer];
2017-11-08 20:04:51 +01:00
DDLogDebug(@"%@ incoming extra text message: %@", self.logTag, incomingMessage.debugDescription);
2017-10-04 16:06:38 +02:00
[textMessage saveWithTransaction:transaction];
}
2017-10-04 16:06:38 +02:00
// In case we already have a read receipt for this new message (this happens sometimes).
[OWSReadReceiptManager.sharedManager applyEarlyReadReceiptsForIncomingMessage:incomingMessage
transaction:transaction];
2017-10-04 16:06:38 +02:00
[OWSDisappearingMessagesJob becomeConsistentWithConfigurationForMessage:incomingMessage
contactsManager:self.contactsManager];
2017-10-04 16:06:38 +02:00
// Update thread preview in inbox
[thread touchWithTransaction:transaction];
2017-10-04 16:06:38 +02:00
[[TextSecureKitEnv sharedEnv].notificationsManager notifyUserForIncomingMessage:incomingMessage
inThread:thread
contactsManager:self.contactsManager
transaction:transaction];
2015-12-07 03:31:43 +01:00
}
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
#pragma mark - helpers
2015-12-07 03:31:43 +01:00
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
- (BOOL)isDataMessageGroupAvatarUpdate:(OWSSignalServiceProtosDataMessage *)dataMessage
{
return dataMessage.hasGroup && dataMessage.group.type == OWSSignalServiceProtosGroupContextTypeUpdate
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
&& dataMessage.group.hasAvatar;
2015-12-07 03:31:43 +01:00
}
/**
* @returns
* Group or Contact thread for message, creating a new contact thread if necessary,
* but never creating a new group thread.
*/
- (nullable TSThread *)threadForEnvelope:(OWSSignalServiceProtosEnvelope *)envelope
dataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage
transaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssert(envelope);
OWSAssert(dataMessage);
OWSAssert(transaction);
if (dataMessage.hasGroup) {
NSData *groupId = dataMessage.group.id;
OWSAssert(groupId.length > 0);
TSGroupThread *_Nullable groupThread = [TSGroupThread threadWithGroupId:groupId transaction:transaction];
// This method should only be called from a code path that has already verified
// that this is a "known" group.
OWSAssert(groupThread);
return groupThread;
} else {
return [TSContactThread getOrCreateThreadWithContactId:envelope.source transaction:transaction];
}
}
- (NSUInteger)unreadMessagesCount
{
2015-12-07 03:31:43 +01:00
__block NSUInteger numberOfItems;
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
numberOfItems = [[transaction ext:TSUnreadDatabaseViewExtensionName] numberOfItemsInAllGroups];
2015-12-07 03:31:43 +01:00
}];
return numberOfItems;
}
- (NSUInteger)unreadMessagesCountExcept:(TSThread *)thread
{
2015-12-07 03:31:43 +01:00
__block NSUInteger numberOfItems;
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
id databaseView = [transaction ext:TSUnreadDatabaseViewExtensionName];
OWSAssert(databaseView);
numberOfItems = ([databaseView numberOfItemsInAllGroups] - [databaseView numberOfItemsInGroup:thread.uniqueId]);
2015-12-07 03:31:43 +01:00
}];
return numberOfItems;
}
- (void)updateApplicationBadgeCount
{
NSUInteger numberOfItems = [self unreadMessagesCount];
// FIXME SHARINGEXTENSION can't use UIApplication.sharedAplication
// [[UIApplication sharedApplication] setApplicationIconBadgeNumber:numberOfItems];
}
- (NSUInteger)unreadMessagesInThread:(TSThread *)thread
{
2015-12-07 03:31:43 +01:00
__block NSUInteger numberOfItems;
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
numberOfItems = [[transaction ext:TSUnreadDatabaseViewExtensionName] numberOfItemsInGroup:thread.uniqueId];
2015-12-07 03:31:43 +01:00
}];
return numberOfItems;
}
@end
NS_ASSUME_NONNULL_END