|  |  |  | @ -307,23 +307,20 @@ NS_ASSUME_NONNULL_BEGIN | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     if (dataMessage.hasGroup) { | 
		
	
		
			
				|  |  |  |  |         TSGroupThread *_Nullable gThread = | 
		
	
		
			
				|  |  |  |  |         TSGroupThread *_Nullable groupThread = | 
		
	
		
			
				|  |  |  |  |             [TSGroupThread threadWithGroupId:dataMessage.group.id transaction:transaction]; | 
		
	
		
			
				|  |  |  |  |         BOOL unknownGroup = NO; | 
		
	
		
			
				|  |  |  |  |         if (gThread == nil && dataMessage.group.type != OWSSignalServiceProtosGroupContextTypeUpdate) { | 
		
	
		
			
				|  |  |  |  |             unknownGroup = YES; | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |         if (unknownGroup) { | 
		
	
		
			
				|  |  |  |  |             if (dataMessage.group.type == OWSSignalServiceProtosGroupContextTypeRequestInfo) { | 
		
	
		
			
				|  |  |  |  |                 DDLogInfo(@"%@ Ignoring group info request for unknown group from: %@", self.tag, envelope.source); | 
		
	
		
			
				|  |  |  |  |                 return; | 
		
	
		
			
				|  |  |  |  |             } else if (dataMessage.group.type == OWSSignalServiceProtosGroupContextTypeQuit) { | 
		
	
		
			
				|  |  |  |  |                 DDLogInfo(@"%@ Ignoring group quit for unknown group from: %@", self.tag, envelope.source); | 
		
	
		
			
				|  |  |  |  |                 return; | 
		
	
		
			
				|  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         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; | 
		
	
		
			
				|  |  |  |  |             } else { | 
		
	
		
			
				|  |  |  |  |                 DDLogInfo(@"%@ Ignoring group message for unknown group from: %@", self.tag, envelope.source); | 
		
	
		
			
				|  |  |  |  |                 return; | 
		
	
		
			
				|  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					|  |  |  | @ -846,13 +843,6 @@ NS_ASSUME_NONNULL_BEGIN | 
		
	
		
			
				|  |  |  |  |     NSString *body = dataMessage.body; | 
		
	
		
			
				|  |  |  |  |     NSData *groupId = dataMessage.hasGroup ? dataMessage.group.id : nil; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     __block TSIncomingMessage *_Nullable incomingMessage; | 
		
	
		
			
				|  |  |  |  |     __block TSThread *thread; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     // Do this outside of a transaction to avoid deadlock | 
		
	
		
			
				|  |  |  |  |     OWSAssert([TSAccountManager isRegistered]); | 
		
	
		
			
				|  |  |  |  |     NSString *localNumber = [TSAccountManager localNumber]; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     if (dataMessage.group.type == OWSSignalServiceProtosGroupContextTypeRequestInfo) { | 
		
	
		
			
				|  |  |  |  |         [self handleGroupInfoRequest:envelope dataMessage:dataMessage transaction:transaction]; | 
		
	
		
			
				|  |  |  |  |         return nil; | 
		
	
	
		
			
				
					|  |  |  | @ -866,9 +856,9 @@ NS_ASSUME_NONNULL_BEGIN | 
		
	
		
			
				|  |  |  |  |         // We distinguish between the old group state (if any) and the new group state. | 
		
	
		
			
				|  |  |  |  |         TSGroupThread *_Nullable oldGroupThread = [TSGroupThread threadWithGroupId:groupId transaction:transaction]; | 
		
	
		
			
				|  |  |  |  |         if (oldGroupThread) { | 
		
	
		
			
				|  |  |  |  |             // Don't trust other clients; ensure all known group members leave the group | 
		
	
		
			
				|  |  |  |  |             // _unless_ it is a "quit" message in which case we should explicitly remove | 
		
	
		
			
				|  |  |  |  |             // just the quiting member below. | 
		
	
		
			
				|  |  |  |  |             // 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]; | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					|  |  |  | @ -880,7 +870,7 @@ NS_ASSUME_NONNULL_BEGIN | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |                 TSGroupModel *newGroupModel = [[TSGroupModel alloc] initWithTitle:dataMessage.group.name | 
		
	
		
			
				|  |  |  |  |                                                                         memberIds:[newMemberIds.allObjects mutableCopy] | 
		
	
		
			
				|  |  |  |  |                                                                             image:nil | 
		
	
		
			
				|  |  |  |  |                                                                             image:oldGroupThread.groupModel.groupImage | 
		
	
		
			
				|  |  |  |  |                                                                           groupId:dataMessage.group.id]; | 
		
	
		
			
				|  |  |  |  |                 NSString *updateGroupInfo = [newGroupThread.groupModel getInfoStringAboutUpdateTo:newGroupModel | 
		
	
		
			
				|  |  |  |  |                                                                                   contactsManager:self.contactsManager]; | 
		
	
	
		
			
				
					|  |  |  | @ -891,8 +881,7 @@ NS_ASSUME_NONNULL_BEGIN | 
		
	
		
			
				|  |  |  |  |                                                  inThread:newGroupThread | 
		
	
		
			
				|  |  |  |  |                                               messageType:TSInfoMessageTypeGroupUpdate | 
		
	
		
			
				|  |  |  |  |                                             customMessage:updateGroupInfo] saveWithTransaction:transaction]; | 
		
	
		
			
				|  |  |  |  |                 thread = newGroupThread; | 
		
	
		
			
				|  |  |  |  |                 break; | 
		
	
		
			
				|  |  |  |  |                 return nil; | 
		
	
		
			
				|  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  |             case OWSSignalServiceProtosGroupContextTypeQuit: { | 
		
	
		
			
				|  |  |  |  |                 if (!oldGroupThread) { | 
		
	
	
		
			
				
					|  |  |  | @ -910,12 +899,11 @@ NS_ASSUME_NONNULL_BEGIN | 
		
	
		
			
				|  |  |  |  |                                                  inThread:oldGroupThread | 
		
	
		
			
				|  |  |  |  |                                               messageType:TSInfoMessageTypeGroupUpdate | 
		
	
		
			
				|  |  |  |  |                                             customMessage:updateGroupInfo] saveWithTransaction:transaction]; | 
		
	
		
			
				|  |  |  |  |                 thread = oldGroupThread; | 
		
	
		
			
				|  |  |  |  |                 break; | 
		
	
		
			
				|  |  |  |  |                 return nil; | 
		
	
		
			
				|  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  |             case OWSSignalServiceProtosGroupContextTypeDeliver: { | 
		
	
		
			
				|  |  |  |  |                 if (!oldGroupThread) { | 
		
	
		
			
				|  |  |  |  |                     OWSFail(@"%@ ignoring quit group message from unknown group.", self.tag); | 
		
	
		
			
				|  |  |  |  |                     OWSFail(@"%@ ignoring deliver group message from unknown group.", self.tag); | 
		
	
		
			
				|  |  |  |  |                     return nil; | 
		
	
		
			
				|  |  |  |  |                 } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					|  |  |  | @ -933,17 +921,21 @@ NS_ASSUME_NONNULL_BEGIN | 
		
	
		
			
				|  |  |  |  |                     envelopeAddress(envelope), | 
		
	
		
			
				|  |  |  |  |                     groupId, | 
		
	
		
			
				|  |  |  |  |                     (unsigned long)timestamp); | 
		
	
		
			
				|  |  |  |  |                 incomingMessage = [[TSIncomingMessage alloc] initWithTimestamp:timestamp | 
		
	
		
			
				|  |  |  |  |                 TSIncomingMessage *incomingMessage = | 
		
	
		
			
				|  |  |  |  |                     [[TSIncomingMessage alloc] initWithTimestamp:timestamp | 
		
	
		
			
				|  |  |  |  |                                                         inThread:oldGroupThread | 
		
	
		
			
				|  |  |  |  |                                                         authorId:envelope.source | 
		
	
		
			
				|  |  |  |  |                                                   sourceDeviceId:envelope.sourceDevice | 
		
	
		
			
				|  |  |  |  |                                                      messageBody:body | 
		
	
		
			
				|  |  |  |  |                                                    attachmentIds:attachmentIds | 
		
	
		
			
				|  |  |  |  |                                                 expiresInSeconds:dataMessage.expireTimer]; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |                 [incomingMessage saveWithTransaction:transaction]; | 
		
	
		
			
				|  |  |  |  |                 thread = oldGroupThread; | 
		
	
		
			
				|  |  |  |  |                 break; | 
		
	
		
			
				|  |  |  |  |                 [self finalizeIncomingMessage:incomingMessage | 
		
	
		
			
				|  |  |  |  |                                        thread:oldGroupThread | 
		
	
		
			
				|  |  |  |  |                                      envelope:envelope | 
		
	
		
			
				|  |  |  |  |                                   dataMessage:dataMessage | 
		
	
		
			
				|  |  |  |  |                                 attachmentIds:attachmentIds | 
		
	
		
			
				|  |  |  |  |                                   transaction:transaction]; | 
		
	
		
			
				|  |  |  |  |                 return incomingMessage; | 
		
	
		
			
				|  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  |             default: { | 
		
	
		
			
				|  |  |  |  |                 DDLogWarn(@"%@ Ignoring unknown group message type: %d", self.tag, (int)dataMessage.group.type); | 
		
	
	
		
			
				
					|  |  |  | @ -963,26 +955,57 @@ NS_ASSUME_NONNULL_BEGIN | 
		
	
		
			
				|  |  |  |  |             self.tag, | 
		
	
		
			
				|  |  |  |  |             envelopeAddress(envelope), | 
		
	
		
			
				|  |  |  |  |             (unsigned long)timestamp); | 
		
	
		
			
				|  |  |  |  |         TSContactThread *cThread = [TSContactThread getOrCreateThreadWithContactId:envelope.source | 
		
	
		
			
				|  |  |  |  |         TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:envelope.source | 
		
	
		
			
				|  |  |  |  |                                                                       transaction:transaction | 
		
	
		
			
				|  |  |  |  |                                                                             relay:envelope.relay]; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         incomingMessage = [[TSIncomingMessage alloc] initWithTimestamp:timestamp | 
		
	
		
			
				|  |  |  |  |                                                               inThread:cThread | 
		
	
		
			
				|  |  |  |  |                                                               authorId:[cThread contactIdentifier] | 
		
	
		
			
				|  |  |  |  |         TSIncomingMessage *incomingMessage = [[TSIncomingMessage alloc] initWithTimestamp:timestamp | 
		
	
		
			
				|  |  |  |  |                                                                                  inThread:thread | 
		
	
		
			
				|  |  |  |  |                                                                                  authorId:[thread contactIdentifier] | 
		
	
		
			
				|  |  |  |  |                                                                            sourceDeviceId:envelope.sourceDevice | 
		
	
		
			
				|  |  |  |  |                                                                               messageBody:body | 
		
	
		
			
				|  |  |  |  |                                                                             attachmentIds:attachmentIds | 
		
	
		
			
				|  |  |  |  |                                                                          expiresInSeconds:dataMessage.expireTimer]; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         [incomingMessage saveWithTransaction:transaction]; | 
		
	
		
			
				|  |  |  |  |         thread = cThread; | 
		
	
		
			
				|  |  |  |  |         [self finalizeIncomingMessage:incomingMessage | 
		
	
		
			
				|  |  |  |  |                                thread:thread | 
		
	
		
			
				|  |  |  |  |                              envelope:envelope | 
		
	
		
			
				|  |  |  |  |                           dataMessage:dataMessage | 
		
	
		
			
				|  |  |  |  |                         attachmentIds:attachmentIds | 
		
	
		
			
				|  |  |  |  |                           transaction:transaction]; | 
		
	
		
			
				|  |  |  |  |         return incomingMessage; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | - (void)finalizeIncomingMessage:(TSIncomingMessage *)incomingMessage | 
		
	
		
			
				|  |  |  |  |                          thread:(TSThread *)thread | 
		
	
		
			
				|  |  |  |  |                        envelope:(OWSSignalServiceProtosEnvelope *)envelope | 
		
	
		
			
				|  |  |  |  |                     dataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage | 
		
	
		
			
				|  |  |  |  |                   attachmentIds:(NSArray<NSString *> *)attachmentIds | 
		
	
		
			
				|  |  |  |  |                     transaction:(YapDatabaseReadWriteTransaction *)transaction | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |     OWSAssert(thread); | 
		
	
		
			
				|  |  |  |  |     OWSAssert(incomingMessage); | 
		
	
		
			
				|  |  |  |  |     OWSAssert(envelope); | 
		
	
		
			
				|  |  |  |  |     OWSAssert(dataMessage); | 
		
	
		
			
				|  |  |  |  |     OWSAssert(attachmentIds); | 
		
	
		
			
				|  |  |  |  |     OWSAssert(transaction); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     OWSAssert([TSAccountManager isRegistered]); | 
		
	
		
			
				|  |  |  |  |     NSString *localNumber = [TSAccountManager localNumber]; | 
		
	
		
			
				|  |  |  |  |     NSString *body = dataMessage.body; | 
		
	
		
			
				|  |  |  |  |     uint64_t timestamp = envelope.timestamp; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     if (!thread) { | 
		
	
		
			
				|  |  |  |  |         OWSFail(@"%@ Can't finalize without thread", self.tag); | 
		
	
		
			
				|  |  |  |  |         return; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     if (!incomingMessage) { | 
		
	
		
			
				|  |  |  |  |         OWSFail(@"%@ Can't finalize missing message", self.tag); | 
		
	
		
			
				|  |  |  |  |         return; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     [incomingMessage saveWithTransaction:transaction]; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     if (thread && incomingMessage) { | 
		
	
		
			
				|  |  |  |  |     // Any messages sent from the current user - from this device or another - should be | 
		
	
		
			
				|  |  |  |  |     // automatically marked as read. | 
		
	
		
			
				|  |  |  |  |     BOOL shouldMarkMessageAsRead = [envelope.source isEqualToString:localNumber]; | 
		
	
	
		
			
				
					|  |  |  | @ -1025,9 +1048,6 @@ NS_ASSUME_NONNULL_BEGIN | 
		
	
		
			
				|  |  |  |  |                                                                         transaction:transaction]; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     return incomingMessage; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | #pragma mark - helpers | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | - (BOOL)isDataMessageGroupAvatarUpdate:(OWSSignalServiceProtosDataMessage *)dataMessage | 
		
	
	
		
			
				
					|  |  |  | 
 |