diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index 45d0d86..2be70e3 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -75,6 +75,8 @@ CD602062219B68950024D9C5 /* MBIMSendMessageOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD602061219B68950024D9C5 /* MBIMSendMessageOperation.m */; }; CD83E156219BE10A00F4CCEA /* hooking.m in Sources */ = {isa = PBXBuildFile; fileRef = CD83E155219BE10A00F4CCEA /* hooking.m */; }; CD83E166219BE91600F4CCEA /* agentHook.m in Sources */ = {isa = PBXBuildFile; fileRef = CD83E165219BE91600F4CCEA /* agentHook.m */; }; + CDE4556421A3578A0041F5DD /* IMChat+Encoded.m in Sources */ = {isa = PBXBuildFile; fileRef = CDE4556321A3578A0041F5DD /* IMChat+Encoded.m */; }; + CDE455A121A365AD0041F5DD /* MBIMMarkOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CDE455A021A365AD0041F5DD /* MBIMMarkOperation.m */; }; CDF62335219A895D00690038 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = CDF62334219A895D00690038 /* main.m */; }; CDF62339219A8A5600690038 /* MBIMBridge.h in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C4469219A4BC300F2AC00 /* MBIMBridge.h */; }; CDF6233A219A8A5600690038 /* MBIMBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C446A219A4BC300F2AC00 /* MBIMBridge.m */; }; @@ -215,6 +217,10 @@ CD83E161219BE91500F4CCEA /* libagentHook.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libagentHook.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; CD83E165219BE91600F4CCEA /* agentHook.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = agentHook.m; sourceTree = ""; }; CD83E1B5219BF78E00F4CCEA /* hookAgent.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = hookAgent.sh; sourceTree = ""; }; + CDE4556221A3578A0041F5DD /* IMChat+Encoded.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "IMChat+Encoded.h"; sourceTree = ""; }; + CDE4556321A3578A0041F5DD /* IMChat+Encoded.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "IMChat+Encoded.m"; sourceTree = ""; }; + CDE4559F21A365AD0041F5DD /* MBIMMarkOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMMarkOperation.h; sourceTree = ""; }; + CDE455A021A365AD0041F5DD /* MBIMMarkOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMMarkOperation.m; sourceTree = ""; }; CDF62332219A895D00690038 /* kordophoned */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = kordophoned; sourceTree = BUILT_PRODUCTS_DIR; }; CDF62334219A895D00690038 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; CDF62340219A9AAA00690038 /* EmailFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = EmailFoundation.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.Internal.sdk/System/Library/PrivateFrameworks/EmailFoundation.framework; sourceTree = DEVELOPER_DIR; }; @@ -487,6 +493,8 @@ children = ( CD14F1A2219FF22700E7DD22 /* IMMessageItem+Encoded.h */, CD14F1A3219FF22700E7DD22 /* IMMessageItem+Encoded.m */, + CDE4556221A3578A0041F5DD /* IMChat+Encoded.h */, + CDE4556321A3578A0041F5DD /* IMChat+Encoded.m */, ); path = Categories; sourceTree = ""; @@ -501,6 +509,8 @@ CD60205B219B623F0024D9C5 /* MBIMMessagesListOperation.m */, CD60205D219B674B0024D9C5 /* MBIMConversationListOperation.h */, CD60205E219B674B0024D9C5 /* MBIMConversationListOperation.m */, + CDE4559F21A365AD0041F5DD /* MBIMMarkOperation.h */, + CDE455A021A365AD0041F5DD /* MBIMMarkOperation.m */, CD602060219B68950024D9C5 /* MBIMSendMessageOperation.h */, CD602061219B68950024D9C5 /* MBIMSendMessageOperation.m */, CD14F19F219FE7D600E7DD22 /* MBIMUpdatePollOperation.h */, @@ -783,8 +793,10 @@ CD14F1A4219FF22700E7DD22 /* IMMessageItem+Encoded.m in Sources */, CD602062219B68950024D9C5 /* MBIMSendMessageOperation.m in Sources */, CD14F1A1219FE7D600E7DD22 /* MBIMUpdatePollOperation.m in Sources */, + CDE455A121A365AD0041F5DD /* MBIMMarkOperation.m in Sources */, CD602056219B5DFD0024D9C5 /* MBIMBridgeOperation.m in Sources */, CD60205F219B674B0024D9C5 /* MBIMConversationListOperation.m in Sources */, + CDE4556421A3578A0041F5DD /* IMChat+Encoded.m in Sources */, 1AA43E8F219EBB2D00EDF1A7 /* MBIMJSONDataResponse.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/kordophone/Bridge/MBIMBridge.m b/kordophone/Bridge/MBIMBridge.m index cce8c65..ff2e01a 100644 --- a/kordophone/Bridge/MBIMBridge.m +++ b/kordophone/Bridge/MBIMBridge.m @@ -106,12 +106,12 @@ static NSString *const MBIMBridgeToken = @"net.buzzert.kordophone"; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_chatRegistryDidLoad:) name:IMChatRegistryDidLoadNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_chatItemsDidChange:) name:IMChatItemsDidChangeNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserverForName: IMChatRegistryUnreadCountChangedNotification - object: nil - queue: [NSOperationQueue mainQueue] - usingBlock:^(NSNotification *note) { - NSLog(@"Unread count changed: %d", (int)[[IMChatRegistry sharedInstance] unreadCount]); - }]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_unreadCountChanged:) name:IMChatRegistryUnreadCountChangedNotification object:nil]; +} + +- (void)_unreadCountChanged:(NSNotification *)notification +{ + // Not a lot of useful information plumbed here... } - (void)_messageReceived:(NSNotification *)notification @@ -124,7 +124,7 @@ static NSString *const MBIMBridgeToken = @"net.buzzert.kordophone"; if (![message isFromMe]) { MBIMUpdateItem *updateItem = [[MBIMUpdateItem alloc] init]; updateItem.changedChat = chat; - updateItem.message = message; + updateItem.addedMessage = message; [[MBIMUpdateQueue sharedInstance] enqueueUpdateItem:updateItem]; } else { @@ -140,7 +140,14 @@ static NSString *const MBIMBridgeToken = @"net.buzzert.kordophone"; - (void)_chatItemsDidChange:(NSNotification *)notification { - NSLog(@"chat items changed: %@", notification); + IMChat *chat = [notification object]; + if (chat) { + NSLog(@"Chat items change for GUID: %@", [chat guid]); + + MBIMUpdateItem *updateItem = [[MBIMUpdateItem alloc] init]; + updateItem.changedChat = chat; + [[MBIMUpdateQueue sharedInstance] enqueueUpdateItem:updateItem]; + } } #pragma mark - diff --git a/kordophone/Bridge/MBIMHTTPConnection.m b/kordophone/Bridge/MBIMHTTPConnection.m index 1aba86f..5773681 100644 --- a/kordophone/Bridge/MBIMHTTPConnection.m +++ b/kordophone/Bridge/MBIMHTTPConnection.m @@ -36,17 +36,26 @@ NSURL *url = [NSURL URLWithString:path]; NSString *endpointName = [url lastPathComponent]; + + BOOL requestTimedOut = NO; Class operationClass = [MBIMBridgeOperation operationClassForEndpointName:endpointName]; if (operationClass != nil) { _currentOperation = [[operationClass alloc] initWithRequestURL:url completion:completion]; _currentOperation.requestBodyData = _bodyData; [[[MBIMBridge sharedInstance] operationQueue] addOperation:_currentOperation]; - dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(60.0 * NSEC_PER_SEC))); + long status = dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(60.0 * NSEC_PER_SEC))); + if (status != 0) { + requestTimedOut = YES; + } } else { response = [[HTTPErrorResponse alloc] initWithErrorCode:404]; } + if (requestTimedOut) { + response = [_currentOperation cancelAndReturnTimeoutResponse]; + } + return response; } diff --git a/kordophone/Bridge/MBIMUpdateQueue.h b/kordophone/Bridge/MBIMUpdateQueue.h index 9eb15b1..b66ed94 100644 --- a/kordophone/Bridge/MBIMUpdateQueue.h +++ b/kordophone/Bridge/MBIMUpdateQueue.h @@ -13,7 +13,9 @@ NS_ASSUME_NONNULL_BEGIN @interface MBIMUpdateItem : NSObject @property (nonatomic, strong) IMChat *changedChat; -@property (nonatomic, strong) IMMessage *message; +@property (nonatomic, strong) IMMessage *addedMessage; + +- (NSDictionary *)dictionaryRepresentation; @end typedef void (^MBIMUpdateConsumer)(MBIMUpdateItem *item); @@ -23,6 +25,8 @@ typedef void (^MBIMUpdateConsumer)(MBIMUpdateItem *item); + (instancetype)sharedInstance; - (void)addConsumer:(MBIMUpdateConsumer)consumer; +- (void)removeConsumer:(MBIMUpdateConsumer)consumer; + - (void)enqueueUpdateItem:(MBIMUpdateItem *)item; @end diff --git a/kordophone/Bridge/MBIMUpdateQueue.m b/kordophone/Bridge/MBIMUpdateQueue.m index 30e4091..d8869ae 100644 --- a/kordophone/Bridge/MBIMUpdateQueue.m +++ b/kordophone/Bridge/MBIMUpdateQueue.m @@ -7,8 +7,15 @@ // #import "MBIMUpdateQueue.h" +#import "IMMessageItem+Encoded.h" +#import "IMChat+Encoded.h" + +@interface MBIMUpdateItem (/*INTERNAL*/) +@property (nonatomic, assign) NSUInteger messageSequenceNumber; +@end @implementation MBIMUpdateQueue { + NSUInteger _messageSequenceNumber; dispatch_queue_t _accessQueue; NSMutableArray *_consumers; } @@ -30,6 +37,7 @@ if (self) { _accessQueue = dispatch_queue_create("net.buzzert.MBIMUpdateQueue", DISPATCH_QUEUE_SERIAL); _consumers = [[NSMutableArray alloc] init]; + _messageSequenceNumber = 0; } return self; @@ -43,8 +51,19 @@ }); } +- (void)removeConsumer:(MBIMUpdateConsumer)consumer +{ + __weak NSMutableArray *consumers = _consumers; + dispatch_async(_accessQueue, ^{ + [consumers removeObject:consumer]; + }); +} + - (void)enqueueUpdateItem:(MBIMUpdateItem *)item { + _messageSequenceNumber++; + item.messageSequenceNumber = _messageSequenceNumber; + __weak NSMutableArray *consumers = _consumers; dispatch_async(_accessQueue, ^{ for (MBIMUpdateConsumer consumer in consumers) { @@ -58,4 +77,20 @@ @end @implementation MBIMUpdateItem +- (NSDictionary *)dictionaryRepresentation +{ + NSMutableDictionary *updateDict = [NSMutableDictionary dictionary]; + updateDict[@"messageSequenceNumber"] = @(_messageSequenceNumber); + + if ([self changedChat]) { + updateDict[@"conversation"] = [[self changedChat] mbim_dictionaryRepresentation]; + } + + if ([self addedMessage]) { + updateDict[@"message"] = [[self addedMessage] mbim_dictionaryRepresentation]; + } + + return updateDict; +} + @end diff --git a/kordophone/Bridge/Operations/MBIMBridgeOperation.h b/kordophone/Bridge/Operations/MBIMBridgeOperation.h index 50d94c9..6b09950 100644 --- a/kordophone/Bridge/Operations/MBIMBridgeOperation.h +++ b/kordophone/Bridge/Operations/MBIMBridgeOperation.h @@ -26,6 +26,8 @@ typedef void (^MBIMBridgeOperationCompletionBlock)(NSObject * _Nul + (nullable Class)operationClassForEndpointName:(NSString *)endpointName; - (instancetype)initWithRequestURL:(NSURL *)requestURL completion:(MBIMBridgeOperationCompletionBlock)completionBlock; +- (NSObject *)cancelAndReturnTimeoutResponse; + @end NS_ASSUME_NONNULL_END diff --git a/kordophone/Bridge/Operations/MBIMBridgeOperation.m b/kordophone/Bridge/Operations/MBIMBridgeOperation.m index ebab0b1..40ee4f2 100644 --- a/kordophone/Bridge/Operations/MBIMBridgeOperation.m +++ b/kordophone/Bridge/Operations/MBIMBridgeOperation.m @@ -55,4 +55,10 @@ return self; } +- (NSObject *)cancelAndReturnTimeoutResponse +{ + [self cancel]; + return [[HTTPErrorResponse alloc] initWithErrorCode:500]; +} + @end diff --git a/kordophone/Bridge/Operations/MBIMConversationListOperation.m b/kordophone/Bridge/Operations/MBIMConversationListOperation.m index 515d0ca..06c8473 100644 --- a/kordophone/Bridge/Operations/MBIMConversationListOperation.m +++ b/kordophone/Bridge/Operations/MBIMConversationListOperation.m @@ -8,6 +8,7 @@ #import "MBIMConversationListOperation.h" #import "MBIMHTTPUtilities.h" +#import "IMChat+Encoded.h" #import @@ -26,26 +27,7 @@ NSMutableArray *conversations = [NSMutableArray array]; for (IMChat *chat in chats) { - NSMutableDictionary *chatDict = [NSMutableDictionary dictionary]; - chatDict[@"guid"] = [chat guid]; - chatDict[@"displayName"] = [chat displayName]; - chatDict[@"date"] = MBIMWebServerFormatRFC822([chat lastFinishedMessageDate]); - - IMMessage *lastMessage = [chat lastMessage]; - if (lastMessage) { - chatDict[@"lastMessagePreview"] = [[lastMessage text] string]; - } - - NSMutableArray *participantStrings = [NSMutableArray array]; - for (IMHandle *participantHandle in chat.participants) { - NSString *participantString = [participantHandle displayNameForChat:chat]; - if (participantString) { - [participantStrings addObject:participantString]; - } - } - - chatDict[@"participantDisplayNames"] = participantStrings; - + NSDictionary *chatDict = [chat mbim_dictionaryRepresentation]; [conversations addObject:chatDict]; } diff --git a/kordophone/Bridge/Operations/MBIMMarkOperation.h b/kordophone/Bridge/Operations/MBIMMarkOperation.h new file mode 100644 index 0000000..742a51c --- /dev/null +++ b/kordophone/Bridge/Operations/MBIMMarkOperation.h @@ -0,0 +1,17 @@ +// +// MBIMMarkOperation.h +// kordophoned +// +// Created by James Magahern on 11/19/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import "MBIMBridgeOperation.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MBIMMarkOperation : MBIMBridgeOperation + +@end + +NS_ASSUME_NONNULL_END diff --git a/kordophone/Bridge/Operations/MBIMMarkOperation.m b/kordophone/Bridge/Operations/MBIMMarkOperation.m new file mode 100644 index 0000000..31c5cd1 --- /dev/null +++ b/kordophone/Bridge/Operations/MBIMMarkOperation.m @@ -0,0 +1,60 @@ +// +// MBIMMarkOperation.m +// kordophoned +// +// Created by James Magahern on 11/19/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import "MBIMMarkOperation.h" +#import + +@implementation MBIMMarkOperation + ++ (void)load { [super load]; } + ++ (NSString *)endpointName +{ + return @"markConversation"; +} + +- (void)main +{ + NSObject *response = nil; + do { + NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:self.requestURL resolvingAgainstBaseURL:NO]; + + NSString *guid = nil; + for (NSURLQueryItem *queryItem in [urlComponents queryItems]) { + if ([[queryItem name] isEqualToString:@"guid"]) { + guid = [queryItem value]; + break; + } + } + + if (!guid) { + NSLog(@"No query item provided"); + response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; + break; + } + + IMChat *chat = [sChatRegistry existingChatWithGUID:guid]; + if (!chat) { + NSLog(@"Chat with guid: %@ not found", guid); + response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; + break; + } + + // TODO: be smarter about this and mark individual messages as read? Could lead + // to a race condition + if ([chat unreadMessageCount] > 0) { + [chat markAllMessagesAsRead]; + } + + response = [[HTTPErrorResponse alloc] initWithErrorCode:200]; + } while (0); + + self.serverCompletionBlock(response); +} + +@end diff --git a/kordophone/Bridge/Operations/MBIMSendMessageOperation.m b/kordophone/Bridge/Operations/MBIMSendMessageOperation.m index 5b8e2e7..b84c655 100644 --- a/kordophone/Bridge/Operations/MBIMSendMessageOperation.m +++ b/kordophone/Bridge/Operations/MBIMSendMessageOperation.m @@ -22,13 +22,15 @@ - (BOOL)_sendMessage:(NSString *)messageBody toChatWithGUID:(NSString *)chatGUID { + IMChat *chat = [sChatRegistry existingChatWithGUID:chatGUID]; + + // TODO: chat might not be an iMessage chat! IMAccount *iMessageAccount = [[IMAccountController sharedInstance] bestAccountForService:[IMServiceImpl iMessageService]]; - IMHandle *handle = [[iMessageAccount arrayOfAllIMHandles] firstObject]; + IMHandle *senderHandle = [iMessageAccount loginIMHandle]; NSAttributedString *replyAttrString = [[NSAttributedString alloc] initWithString:messageBody]; - IMMessage *reply = [IMMessage fromMeIMHandle:handle withText:replyAttrString fileTransferGUIDs:@[] flags:kIMMessageFinished]; + IMMessage *reply = [IMMessage fromMeIMHandle:senderHandle withText:replyAttrString fileTransferGUIDs:@[] flags:kIMMessageFinished]; - IMChat *chat = [sChatRegistry existingChatWithGUID:chatGUID]; if (!chat) { NSLog(@"Chat does not exist: %@", chatGUID); return NO; diff --git a/kordophone/Bridge/Operations/MBIMUpdatePollOperation.m b/kordophone/Bridge/Operations/MBIMUpdatePollOperation.m index d0db0c9..5c3d40d 100644 --- a/kordophone/Bridge/Operations/MBIMUpdatePollOperation.m +++ b/kordophone/Bridge/Operations/MBIMUpdatePollOperation.m @@ -8,9 +8,10 @@ #import "MBIMUpdatePollOperation.h" #import "MBIMUpdateQueue.h" -#import "IMMessageItem+Encoded.h" -@implementation MBIMUpdatePollOperation +@implementation MBIMUpdatePollOperation { + __strong MBIMUpdateConsumer _updateConsumer; +} + (void)load { [super load]; } @@ -21,19 +22,27 @@ - (void)main { - MBIMUpdateConsumer consumer = ^(MBIMUpdateItem *nextUpdateItem) { - NSDictionary *updateDict = @{ - @"guid" : [[nextUpdateItem changedChat] guid], - @"message" : [[nextUpdateItem message] mbim_dictionaryRepresentation] - }; + __weak __auto_type weakSelf = self; + _updateConsumer = ^(MBIMUpdateItem *nextUpdateItem) { + NSDictionary *updateDict = [nextUpdateItem dictionaryRepresentation]; MBIMJSONDataResponse *response = [MBIMJSONDataResponse responseWithJSONObject:updateDict]; - self.serverCompletionBlock(response); + weakSelf.serverCompletionBlock(response); }; - [[MBIMUpdateQueue sharedInstance] addConsumer:consumer]; + [[MBIMUpdateQueue sharedInstance] addConsumer:_updateConsumer]; } -// TODO: cancel needs to remove the consumer from the update queue +- (void)cancel +{ + [super cancel]; + [[MBIMUpdateQueue sharedInstance] removeConsumer:_updateConsumer]; +} + +- (NSObject *)cancelAndReturnTimeoutResponse +{ + [self cancel]; + return [[HTTPErrorResponse alloc] initWithErrorCode:205]; // 205 = nothing to report +} @end diff --git a/kordophone/Bridge/Operations/Utilities/MBIMHTTPUtilities.h b/kordophone/Bridge/Operations/Utilities/MBIMHTTPUtilities.h index 10f03d6..7ffc249 100644 --- a/kordophone/Bridge/Operations/Utilities/MBIMHTTPUtilities.h +++ b/kordophone/Bridge/Operations/Utilities/MBIMHTTPUtilities.h @@ -9,3 +9,4 @@ #import NSString* MBIMWebServerFormatRFC822(NSDate *date); +NSString* MBIMWebServerFormatISO8601(NSDate *date); diff --git a/kordophone/Bridge/Operations/Utilities/MBIMHTTPUtilities.m b/kordophone/Bridge/Operations/Utilities/MBIMHTTPUtilities.m index 61bbd1a..00e0663 100644 --- a/kordophone/Bridge/Operations/Utilities/MBIMHTTPUtilities.m +++ b/kordophone/Bridge/Operations/Utilities/MBIMHTTPUtilities.m @@ -9,6 +9,7 @@ #include "MBIMHTTPUtilities.h" static NSDateFormatter* _dateFormatterRFC822 = nil; +static NSDateFormatter* _dateFormatterISO8601 = nil; static dispatch_queue_t _dateFormatterQueue = NULL; __attribute__((constructor)) @@ -20,6 +21,11 @@ static void __InitializeDateFormatter() _dateFormatterRFC822.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"]; _dateFormatterRFC822.dateFormat = @"EEE',' dd MMM yyyy HH':'mm':'ss 'GMT'"; _dateFormatterRFC822.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]; + + _dateFormatterISO8601 = [[NSDateFormatter alloc] init]; + _dateFormatterISO8601.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"]; + _dateFormatterISO8601.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss'+00:00'"; + _dateFormatterISO8601.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]; } NSString* MBIMWebServerFormatRFC822(NSDate *date) @@ -31,3 +37,13 @@ NSString* MBIMWebServerFormatRFC822(NSDate *date) return string; } + +NSString* MBIMWebServerFormatISO8601(NSDate *date) +{ + __block NSString *string = nil; + dispatch_sync(_dateFormatterQueue, ^{ + string = [_dateFormatterISO8601 stringFromDate:date]; + }); + + return string; +} diff --git a/kordophone/Categories/IMChat+Encoded.h b/kordophone/Categories/IMChat+Encoded.h new file mode 100644 index 0000000..6f3f09c --- /dev/null +++ b/kordophone/Categories/IMChat+Encoded.h @@ -0,0 +1,17 @@ +// +// IMChat+Encoded.h +// kordophoned +// +// Created by James Magahern on 11/19/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface IMChat (Encoded) +- (NSDictionary *)mbim_dictionaryRepresentation; +@end + +NS_ASSUME_NONNULL_END diff --git a/kordophone/Categories/IMChat+Encoded.m b/kordophone/Categories/IMChat+Encoded.m new file mode 100644 index 0000000..5bcac46 --- /dev/null +++ b/kordophone/Categories/IMChat+Encoded.m @@ -0,0 +1,40 @@ +// +// IMChat+Encoded.m +// kordophoned +// +// Created by James Magahern on 11/19/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import "IMChat+Encoded.h" +#import "MBIMHTTPUtilities.h" + +@implementation IMChat (Encoded) + +- (NSDictionary *)mbim_dictionaryRepresentation +{ + NSMutableDictionary *chatDict = [NSMutableDictionary dictionary]; + chatDict[@"guid"] = [self guid]; + chatDict[@"displayName"] = [self displayName]; + chatDict[@"date"] = MBIMWebServerFormatISO8601([self lastFinishedMessageDate]); + chatDict[@"unreadCount"] = @([self unreadMessageCount]); + + IMMessage *lastMessage = [self lastMessage]; + if (lastMessage) { + chatDict[@"lastMessagePreview"] = [[lastMessage text] string]; + } + + NSMutableArray *participantStrings = [NSMutableArray array]; + for (IMHandle *participantHandle in self.participants) { + NSString *participantString = [participantHandle displayNameForChat:self]; + if (participantString) { + [participantStrings addObject:participantString]; + } + } + + chatDict[@"participantDisplayNames"] = participantStrings; + + return chatDict; +} + +@end diff --git a/kordophone/Categories/IMMessageItem+Encoded.m b/kordophone/Categories/IMMessageItem+Encoded.m index 7305780..27e25d4 100644 --- a/kordophone/Categories/IMMessageItem+Encoded.m +++ b/kordophone/Categories/IMMessageItem+Encoded.m @@ -15,7 +15,7 @@ { NSMutableDictionary *messageDict = [NSMutableDictionary dictionary]; messageDict[@"text"] = [[self text] string]; - messageDict[@"date"] = MBIMWebServerFormatRFC822([self time]); + messageDict[@"date"] = MBIMWebServerFormatISO8601([self time]); messageDict[@"sender"] = [[self sender] displayID]; return messageDict; @@ -29,7 +29,7 @@ { NSMutableDictionary *messageDict = [NSMutableDictionary dictionary]; messageDict[@"text"] = [[self body] string]; - messageDict[@"date"] = MBIMWebServerFormatRFC822([self time]); + messageDict[@"date"] = MBIMWebServerFormatISO8601([self time]); messageDict[@"sender"] = [self sender]; return messageDict;