// // MBIMBridge.m // MessagesBridge // // Created by James Magahern on 11/12/18. // Copyright © 2018 James Magahern. All rights reserved. // #import "MBIMBridge.h" #import "MBIMBridgeOperation.h" #import "MBIMHTTPConnection.h" #import "hooking.h" #import #import #import #import #import static NSString *const MBIMBridgeToken = @"net.buzzert.kordophone"; @interface MBIMBridge (/* INTERNAL */) @property (nonatomic, strong) HTTPServer *httpServer; @property (nonatomic, strong) NSOperationQueue *operationQueue; - (instancetype)_init; @end @implementation MBIMBridge + (instancetype)sharedInstance { static dispatch_once_t onceToken; static __strong MBIMBridge *sharedBridge = nil; dispatch_once(&onceToken, ^{ sharedBridge = [[MBIMBridge alloc] _init]; }); return sharedBridge; } - (instancetype)_init { self = [super init]; if (self) { [self registerForNotifications]; [self startWebServer]; [sDaemonController setDelegate:self]; [sDaemonListener addHandler:self]; _operationQueue = [[NSOperationQueue alloc] init]; } return self; } - (void)_terminate { // *shrug* exit(0); } #pragma mark - #pragma mark Connection - (void)connect { #if HOOK_IMAGENT char *errorString = nil; BOOL hooked = HookIMAgent(self.dylibPath, &errorString); if (!hooked) { NSString *errorNSString = [NSString stringWithUTF8String:errorString]; NSLog(@"Error hooking imagent: %@", errorNSString); return; } #endif if (![sDaemonController hasListenerForID: MBIMBridgeToken]) { if (![sDaemonController addListenerID:MBIMBridgeToken capabilities:(kFZListenerCapFileTransfers | kFZListenerCapManageStatus | kFZListenerCapChats | kFZListenerCapMessageHistory | kFZListenerCapIDQueries | kFZListenerCapSendMessages)]) { NSLog(@"Failed to connect to imagent"); [self _terminate]; } } } - (void)disconnect { [sDaemonController removeListenerID:MBIMBridgeToken]; } #pragma mark - #pragma mark Notifications - (void)registerForNotifications { (void)[IMChatRegistry sharedInstance]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_messageReceived:) name:IMChatMessageReceivedNotification object:nil]; [[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]); }]; } - (void)_messageReceived:(NSNotification *)notification { NSLog(@"Received message from chat with GUID: %@", [[notification object] guid]); // TODO: Notify observers or something } - (void)_chatRegistryDidLoad:(NSNotification *)notification { NSLog(@"Loaded chat registry. %lu existing chats", (unsigned long)[sChatRegistry numberOfExistingChats]); } - (void)_chatItemsDidChange:(NSNotification *)notification { NSLog(@"chat items changed: %@", notification); } #pragma mark - #pragma mark Web Server initialization - (void)startWebServer { self.httpServer = [[HTTPServer alloc] init]; [self.httpServer setConnectionClass:[MBIMHTTPConnection class]]; [self.httpServer setPort:8080]; NSError *error = nil; if (![self.httpServer start:&error]) { NSLog(@"Error starting HTTP server: %@", [error localizedDescription]); } } #pragma mark - #pragma mark Daemon lifecycle - (void)daemonControllerWillConnect { NSLog(@"Connecting to imagent..."); } - (void)daemonControllerDidConnect { NSLog(@"imagent responded."); IMAccount *iMessageAccount = [[IMAccountController sharedInstance] bestAccountForService:[IMServiceImpl iMessageService]]; if (iMessageAccount) { NSLog(@"Successfully got accounts from imagent"); NSLog(@"iMessage account connected: %@", iMessageAccount); } else { NSLog(@"imagent returned no accounts (not entitled?)"); [self _terminate]; } } - (void)daemonControllerDidDisconnect { NSLog(@"Disconnected from imagent"); } - (void)daemonConnectionLost { NSLog(@"Connection lost to imagent"); } @end