diff --git a/Signal/src/Jobs/ConversationConfigurationSyncOperation.swift b/Signal/src/Jobs/ConversationConfigurationSyncOperation.swift index b5c50e227..3c38759f8 100644 --- a/Signal/src/Jobs/ConversationConfigurationSyncOperation.swift +++ b/Signal/src/Jobs/ConversationConfigurationSyncOperation.swift @@ -88,6 +88,7 @@ class ConversationConfigurationSyncOperation: OWSOperation { dataSource: attachmentDataSource, contentType: OWSMimeTypeApplicationOctetStream, sourceFilename: nil, + caption: nil, isTemporaryAttachment: true) self.reportSuccess() } diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewItem.h b/Signal/src/ViewControllers/ConversationView/ConversationViewItem.h index 394219d2a..8594478d2 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewItem.h +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewItem.h @@ -48,6 +48,8 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType); // This property will be non-zero if the attachment is valid. @property (nonatomic, readonly) CGSize mediaSize; +@property (nonatomic, readonly, nullable) NSString *caption; + @end #pragma mark - diff --git a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m index e4ab8bfbe..79a1d2723 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m @@ -3759,6 +3759,7 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac byteCount:filesize contentType:@"audio/mp3" sourceFilename:@"test.mp3" + caption:nil attachmentType:TSAttachmentTypeDefault]; pointer.state = TSAttachmentPointerStateFailed; [pointer saveWithTransaction:transaction]; @@ -3785,7 +3786,8 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] initWithContentType:@"audio/mp3" byteCount:filesize - sourceFilename:filename]; + sourceFilename:filename + caption:nil]; NSError *error; BOOL success = [attachmentStream writeData:[self createRandomNSDataOfSize:filesize] error:&error]; @@ -4616,7 +4618,8 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac UInt32 nominalDataLength = (UInt32)MAX((NSUInteger)1, dataSource.dataLength); TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] initWithContentType:fakeAssetLoader.mimeType byteCount:nominalDataLength - sourceFilename:filename]; + sourceFilename:filename + caption:nil]; NSError *error; BOOL success = [attachmentStream writeData:dataSource.data error:&error]; OWSAssertDebug(success && !error); @@ -4631,6 +4634,7 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac byteCount:filesize contentType:fakeAssetLoader.mimeType sourceFilename:fakeAssetLoader.filename + caption:nil attachmentType:TSAttachmentTypeDefault]; attachmentPointer.state = TSAttachmentPointerStateFailed; [attachmentPointer saveWithTransaction:transaction]; diff --git a/Signal/src/ViewControllers/DebugUI/DebugUISyncMessages.m b/Signal/src/ViewControllers/DebugUI/DebugUISyncMessages.m index be87bfca6..38d7e4327 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUISyncMessages.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUISyncMessages.m @@ -118,6 +118,7 @@ NS_ASSUME_NONNULL_BEGIN dataSource:dataSource contentType:OWSMimeTypeApplicationOctetStream sourceFilename:nil + caption:nil isTemporaryAttachment:YES]; } diff --git a/SignalMessaging/attachments/SignalAttachment.swift b/SignalMessaging/attachments/SignalAttachment.swift index 4430491f5..6a645cc30 100644 --- a/SignalMessaging/attachments/SignalAttachment.swift +++ b/SignalMessaging/attachments/SignalAttachment.swift @@ -241,7 +241,7 @@ public class SignalAttachment: NSObject { @objc public var outgoingAttachmentInfo: OutgoingAttachmentInfo { - return OutgoingAttachmentInfo(dataSource: dataSource, contentType: mimeType, sourceFilename: filenameOrDefault) + return OutgoingAttachmentInfo(dataSource: dataSource, contentType: mimeType, sourceFilename: filenameOrDefault, caption: captionText) } @objc diff --git a/SignalServiceKit/protobuf/SignalService.proto b/SignalServiceKit/protobuf/SignalService.proto index 39fabb2bd..c03cc861b 100644 --- a/SignalServiceKit/protobuf/SignalService.proto +++ b/SignalServiceKit/protobuf/SignalService.proto @@ -328,6 +328,7 @@ message AttachmentPointer { optional uint32 flags = 8; optional uint32 width = 9; optional uint32 height = 10; + optional string caption = 11; } message GroupContext { diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachment.h b/SignalServiceKit/src/Messages/Attachments/TSAttachment.h index da9b75750..926f65674 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachment.h +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachment.h @@ -37,19 +37,24 @@ typedef NS_ENUM(NSUInteger, TSAttachmentType) { // not the filename on disk. @property (nonatomic, readonly, nullable) NSString *sourceFilename; +// Currently only applies to albums. +@property (nonatomic, readonly, nullable) NSString *caption; + // This constructor is used for new instances of TSAttachmentPointer, // i.e. undownloaded incoming attachments. - (instancetype)initWithServerId:(UInt64)serverId encryptionKey:(NSData *)encryptionKey byteCount:(UInt32)byteCount contentType:(NSString *)contentType - sourceFilename:(nullable NSString *)sourceFilename; + sourceFilename:(nullable NSString *)sourceFilename + caption:(nullable NSString *)caption; // This constructor is used for new instances of TSAttachmentStream // that represent new, un-uploaded outgoing attachments. - (instancetype)initWithContentType:(NSString *)contentType byteCount:(UInt32)byteCount - sourceFilename:(nullable NSString *)sourceFilename; + sourceFilename:(nullable NSString *)sourceFilename + caption:(nullable NSString *)caption; // This constructor is used for new instances of TSAttachmentStream // that represent downloaded incoming attachments. diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachment.m b/SignalServiceKit/src/Messages/Attachments/TSAttachment.m index dab81e619..3e3786bfe 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachment.m +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachment.m @@ -19,6 +19,8 @@ NSUInteger const TSAttachmentSchemaVersion = 4; @property (nonatomic) NSString *contentType; +@property (nonatomic, nullable) NSString *caption; + @end @implementation TSAttachment @@ -30,6 +32,7 @@ NSUInteger const TSAttachmentSchemaVersion = 4; byteCount:(UInt32)byteCount contentType:(NSString *)contentType sourceFilename:(nullable NSString *)sourceFilename + caption:(nullable NSString *)caption { OWSAssertDebug(serverId > 0); OWSAssertDebug(encryptionKey.length > 0); @@ -54,6 +57,7 @@ NSUInteger const TSAttachmentSchemaVersion = 4; _byteCount = byteCount; _contentType = contentType; _sourceFilename = sourceFilename; + _caption = caption; _attachmentSchemaVersion = TSAttachmentSchemaVersion; @@ -65,6 +69,7 @@ NSUInteger const TSAttachmentSchemaVersion = 4; - (instancetype)initWithContentType:(NSString *)contentType byteCount:(UInt32)byteCount sourceFilename:(nullable NSString *)sourceFilename + caption:(nullable NSString *)caption { if (contentType.length < 1) { OWSLogWarn(@"outgoing attachment has invalid content type"); @@ -82,6 +87,7 @@ NSUInteger const TSAttachmentSchemaVersion = 4; _contentType = contentType; _byteCount = byteCount; _sourceFilename = sourceFilename; + _caption = caption; _attachmentSchemaVersion = TSAttachmentSchemaVersion; @@ -117,6 +123,7 @@ NSUInteger const TSAttachmentSchemaVersion = 4; contentType = OWSMimeTypeApplicationOctetStream; } _contentType = contentType; + _caption = pointer.caption; _attachmentSchemaVersion = TSAttachmentSchemaVersion; diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.h b/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.h index d9183a82e..8fa4bfe67 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.h +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.h @@ -27,6 +27,7 @@ typedef NS_ENUM(NSUInteger, TSAttachmentPointerState) { byteCount:(UInt32)byteCount contentType:(NSString *)contentType sourceFilename:(nullable NSString *)sourceFilename + caption:(nullable NSString *)caption attachmentType:(TSAttachmentType)attachmentType NS_DESIGNATED_INITIALIZER; + (nullable TSAttachmentPointer *)attachmentPointerFromProto:(SSKProtoAttachmentPointer *)attachmentProto; diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.m b/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.m index b1be6f711..f851d8386 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.m +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.m @@ -32,13 +32,15 @@ NS_ASSUME_NONNULL_BEGIN byteCount:(UInt32)byteCount contentType:(NSString *)contentType sourceFilename:(nullable NSString *)sourceFilename + caption:(nullable NSString *)caption attachmentType:(TSAttachmentType)attachmentType { self = [super initWithServerId:serverId encryptionKey:key byteCount:byteCount contentType:contentType - sourceFilename:sourceFilename]; + sourceFilename:sourceFilename + caption:caption]; if (!self) { return self; } @@ -76,13 +78,17 @@ NS_ASSUME_NONNULL_BEGIN attachmentType = TSAttachmentTypeVoiceMessage; } } - + NSString *_Nullable caption; + if (attachmentProto.hasCaption) { + caption = attachmentProto.caption; + } TSAttachmentPointer *pointer = [[TSAttachmentPointer alloc] initWithServerId:attachmentProto.id key:attachmentProto.key digest:digest byteCount:attachmentProto.size contentType:attachmentProto.contentType sourceFilename:attachmentProto.fileName + caption:caption attachmentType:attachmentType]; return pointer; } diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.h b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.h index a16b5d4d5..37aab8fe8 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.h +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.h @@ -25,7 +25,8 @@ typedef void (^OWSThumbnailFailure)(void); - (instancetype)init NS_UNAVAILABLE; - (instancetype)initWithContentType:(NSString *)contentType byteCount:(UInt32)byteCount - sourceFilename:(nullable NSString *)sourceFilename NS_DESIGNATED_INITIALIZER; + sourceFilename:(nullable NSString *)sourceFilename + caption:(nullable NSString *)caption NS_DESIGNATED_INITIALIZER; - (instancetype)initWithPointer:(TSAttachmentPointer *)pointer NS_DESIGNATED_INITIALIZER; - (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER; diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m index 80eaaed09..dac1abc76 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m @@ -54,8 +54,9 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); - (instancetype)initWithContentType:(NSString *)contentType byteCount:(UInt32)byteCount sourceFilename:(nullable NSString *)sourceFilename + caption:(nullable NSString *)caption { - self = [super initWithContentType:contentType byteCount:byteCount sourceFilename:sourceFilename]; + self = [super initWithContentType:contentType byteCount:byteCount sourceFilename:sourceFilename caption:caption]; if (!self) { return self; } @@ -854,7 +855,8 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); TSAttachmentStream *thumbnailAttachment = [[TSAttachmentStream alloc] initWithContentType:OWSMimeTypeImageJpeg byteCount:(uint32_t)thumbnailData.length - sourceFilename:thumbnailName]; + sourceFilename:thumbnailName + caption:nil]; NSError *error; BOOL success = [thumbnailAttachment writeData:thumbnailData error:&error]; @@ -894,7 +896,12 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); builder.contentType = self.contentType; OWSLogVerbose(@"Sending attachment with filename: '%@'", self.sourceFilename); - builder.fileName = self.sourceFilename; + if (self.sourceFilename.length > 0) { + builder.fileName = self.sourceFilename; + } + if (self.caption.length > 0) { + builder.caption = self.caption; + } builder.size = self.byteCount; builder.key = self.encryptionKey; diff --git a/SignalServiceKit/src/Messages/Interactions/OWSContact.m b/SignalServiceKit/src/Messages/Interactions/OWSContact.m index 1a4aa9485..b9e3b89b3 100644 --- a/SignalServiceKit/src/Messages/Interactions/OWSContact.m +++ b/SignalServiceKit/src/Messages/Interactions/OWSContact.m @@ -495,7 +495,8 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value) TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] initWithContentType:OWSMimeTypeImageJpeg byteCount:(UInt32)imageData.length - sourceFilename:nil]; + sourceFilename:nil + caption:nil]; NSError *error; BOOL success = [attachmentStream writeData:imageData error:&error]; diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index 7880584f4..6c546e03f 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -898,6 +898,7 @@ NS_ASSUME_NONNULL_BEGIN dataSource:dataSource contentType:OWSMimeTypeApplicationOctetStream sourceFilename:nil + caption:nil isTemporaryAttachment:YES]; } else if (syncMessage.request.type == SSKProtoSyncMessageRequestTypeBlocked) { OWSLogInfo(@"Received request for block list"); @@ -1119,6 +1120,7 @@ NS_ASSUME_NONNULL_BEGIN dataSource:dataSource contentType:OWSMimeTypeImagePng sourceFilename:nil + caption:nil isTemporaryAttachment:YES]; } else { diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.h b/SignalServiceKit/src/Messages/OWSMessageSender.h index 483d75c0b..043969a5c 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.h +++ b/SignalServiceKit/src/Messages/OWSMessageSender.h @@ -39,12 +39,14 @@ NS_SWIFT_NAME(OutgoingAttachmentInfo) @property (nonatomic, readonly) DataSource *dataSource; @property (nonatomic, readonly) NSString *contentType; @property (nonatomic, readonly, nullable) NSString *sourceFilename; +@property (nonatomic, readonly, nullable) NSString *caption; - (instancetype)init NS_UNAVAILABLE; - (instancetype)initWithDataSource:(DataSource *)dataSource contentType:(NSString *)contentType - sourceFilename:(nullable NSString *)sourceFilename NS_DESIGNATED_INITIALIZER; + sourceFilename:(nullable NSString *)sourceFilename + caption:(nullable NSString *)caption NS_DESIGNATED_INITIALIZER; @end diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index 613bc1407..ec9cdc78a 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -86,6 +86,7 @@ void AssertIsOnSendingQueue() - (instancetype)initWithDataSource:(DataSource *)dataSource contentType:(NSString *)contentType sourceFilename:(nullable NSString *)sourceFilename + caption:(nullable NSString *)caption { self = [super init]; if (!self) { @@ -95,6 +96,7 @@ void AssertIsOnSendingQueue() _dataSource = dataSource; _contentType = contentType; _sourceFilename = sourceFilename; + _caption = caption; return self; } @@ -455,7 +457,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; OWSAssertDebug(dataSource); OWSOutgoingAttachmentInfo *attachmentInfo = [[OWSOutgoingAttachmentInfo alloc] initWithDataSource:dataSource contentType:contentType - sourceFilename:sourceFilename]; + sourceFilename:sourceFilename + caption:nil]; [OutgoingMessagePreparer prepareAttachments:@[ attachmentInfo ] inMessage:message completionHandler:^(NSError *_Nullable error) { @@ -1804,7 +1807,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] initWithContentType:attachmentInfo.contentType byteCount:(UInt32)attachmentInfo.dataSource.dataLength - sourceFilename:attachmentInfo.sourceFilename]; + sourceFilename:attachmentInfo.sourceFilename + caption:attachmentInfo.caption]; if (outgoingMessage.isVoiceMessage) { attachmentStream.attachmentType = TSAttachmentTypeVoiceMessage; } diff --git a/SignalServiceKit/src/Network/MessageSenderJobQueue.swift b/SignalServiceKit/src/Network/MessageSenderJobQueue.swift index 3fc626876..5c36241db 100644 --- a/SignalServiceKit/src/Network/MessageSenderJobQueue.swift +++ b/SignalServiceKit/src/Network/MessageSenderJobQueue.swift @@ -41,9 +41,9 @@ public class MessageSenderJobQueue: NSObject, JobQueue { self.add(message: message, removeMessageAfterSending: false, transaction: transaction) } - @objc(addMediaMessage:dataSource:contentType:sourceFilename:isTemporaryAttachment:) - public func add(mediaMessage: TSOutgoingMessage, dataSource: DataSource, contentType: String, sourceFilename: String?, isTemporaryAttachment: Bool) { - let attachmentInfo = OutgoingAttachmentInfo(dataSource: dataSource, contentType: contentType, sourceFilename: sourceFilename) + @objc(addMediaMessage:dataSource:contentType:sourceFilename:caption:isTemporaryAttachment:) + public func add(mediaMessage: TSOutgoingMessage, dataSource: DataSource, contentType: String, sourceFilename: String?, caption: String?, isTemporaryAttachment: Bool) { + let attachmentInfo = OutgoingAttachmentInfo(dataSource: dataSource, contentType: contentType, sourceFilename: sourceFilename, caption: caption) add(mediaMessage: mediaMessage, attachmentInfos: [attachmentInfo], isTemporaryAttachment: isTemporaryAttachment) } diff --git a/SignalServiceKit/src/Protos/Generated/SSKProto.swift b/SignalServiceKit/src/Protos/Generated/SSKProto.swift index e7a434434..7ceac4485 100644 --- a/SignalServiceKit/src/Protos/Generated/SSKProto.swift +++ b/SignalServiceKit/src/Protos/Generated/SSKProto.swift @@ -4544,6 +4544,9 @@ extension SSKProtoSyncMessage.SSKProtoSyncMessageBuilder { if hasHeight { builder.setHeight(height) } + if let _value = caption { + builder.setCaption(_value) + } return builder } @@ -4599,6 +4602,10 @@ extension SSKProtoSyncMessage.SSKProtoSyncMessageBuilder { proto.height = valueParam } + @objc public func setCaption(_ valueParam: String) { + proto.caption = valueParam + } + @objc public func build() throws -> SSKProtoAttachmentPointer { return try SSKProtoAttachmentPointer.parseProto(proto) } @@ -4690,6 +4697,16 @@ extension SSKProtoSyncMessage.SSKProtoSyncMessageBuilder { return proto.hasHeight } + @objc public var caption: String? { + guard proto.hasCaption else { + return nil + } + return proto.caption + } + @objc public var hasCaption: Bool { + return proto.hasCaption + } + private init(proto: SignalServiceProtos_AttachmentPointer, id: UInt64) { self.proto = proto diff --git a/SignalServiceKit/src/Protos/Generated/SignalService.pb.swift b/SignalServiceKit/src/Protos/Generated/SignalService.pb.swift index 8082ccb4c..7b8e5e894 100644 --- a/SignalServiceKit/src/Protos/Generated/SignalService.pb.swift +++ b/SignalServiceKit/src/Protos/Generated/SignalService.pb.swift @@ -1860,6 +1860,15 @@ struct SignalServiceProtos_AttachmentPointer { /// Clears the value of `height`. Subsequent reads from it will return its default value. mutating func clearHeight() {self._height = nil} + var caption: String { + get {return _caption ?? String()} + set {_caption = newValue} + } + /// Returns true if `caption` has been explicitly set. + var hasCaption: Bool {return self._caption != nil} + /// Clears the value of `caption`. Subsequent reads from it will return its default value. + mutating func clearCaption() {self._caption = nil} + var unknownFields = SwiftProtobuf.UnknownStorage() enum Flags: SwiftProtobuf.Enum { @@ -1897,6 +1906,7 @@ struct SignalServiceProtos_AttachmentPointer { fileprivate var _flags: UInt32? = nil fileprivate var _width: UInt32? = nil fileprivate var _height: UInt32? = nil + fileprivate var _caption: String? = nil } #if swift(>=4.2) @@ -4107,6 +4117,7 @@ extension SignalServiceProtos_AttachmentPointer: SwiftProtobuf.Message, SwiftPro 8: .same(proto: "flags"), 9: .same(proto: "width"), 10: .same(proto: "height"), + 11: .same(proto: "caption"), ] mutating func decodeMessage(decoder: inout D) throws { @@ -4122,6 +4133,7 @@ extension SignalServiceProtos_AttachmentPointer: SwiftProtobuf.Message, SwiftPro case 8: try decoder.decodeSingularUInt32Field(value: &self._flags) case 9: try decoder.decodeSingularUInt32Field(value: &self._width) case 10: try decoder.decodeSingularUInt32Field(value: &self._height) + case 11: try decoder.decodeSingularStringField(value: &self._caption) default: break } } @@ -4158,6 +4170,9 @@ extension SignalServiceProtos_AttachmentPointer: SwiftProtobuf.Message, SwiftPro if let v = self._height { try visitor.visitSingularUInt32Field(value: v, fieldNumber: 10) } + if let v = self._caption { + try visitor.visitSingularStringField(value: v, fieldNumber: 11) + } try unknownFields.traverse(visitor: &visitor) } @@ -4172,6 +4187,7 @@ extension SignalServiceProtos_AttachmentPointer: SwiftProtobuf.Message, SwiftPro if lhs._flags != rhs._flags {return false} if lhs._width != rhs._width {return false} if lhs._height != rhs._height {return false} + if lhs._caption != rhs._caption {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true }